/* * Copyright 2015 Jean-Christophe Sirot <sirot@chelonix.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jenkinsci.plugins.ansible; import javax.annotation.Nonnull; import java.io.IOException; import com.cloudbees.plugins.credentials.CredentialsProvider; import com.cloudbees.plugins.credentials.common.StandardUsernameCredentials; import hudson.AbortException; import hudson.Extension; import hudson.FilePath; import hudson.Launcher; import hudson.Util; import hudson.model.Computer; import hudson.model.Run; import hudson.model.TaskListener; import hudson.tasks.Builder; import hudson.util.FormValidation; import jenkins.tasks.SimpleBuildStep; import org.apache.commons.lang.StringUtils; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.QueryParameter; /** * A builder which wraps an Ansible Ad-Hoc command invocation. */ public class AnsibleAdHocCommandBuilder extends Builder implements SimpleBuildStep { public String ansibleName; // SSH settings /** * The id of the credentials to use. */ public String credentialsId = null; public final String hostPattern; /** * Path to the inventory file. */ public final Inventory inventory; public final String module; public final String command; public boolean sudo = false; public String sudoUser = "root"; public int forks = 5; public boolean unbufferedOutput = true; public boolean colorizedOutput = false; public boolean hostKeyChecking = false; public String additionalParameters = null; @Deprecated public AnsibleAdHocCommandBuilder(String ansibleName, String hostPattern, Inventory inventory, String module, String command, String credentialsId, boolean sudo, String sudoUser, int forks, boolean unbufferedOutput, boolean colorizedOutput, boolean hostKeyChecking, String additionalParameters) { this.ansibleName = ansibleName; this.hostPattern = hostPattern; this.inventory = inventory; this.module = module; this.command = command; this.credentialsId = credentialsId; this.sudo = sudo; this.sudoUser = sudoUser; this.forks = forks; this.unbufferedOutput = unbufferedOutput; this.colorizedOutput = colorizedOutput; this.hostKeyChecking = hostKeyChecking; this.additionalParameters = additionalParameters; } @DataBoundConstructor public AnsibleAdHocCommandBuilder(String hostPattern, Inventory inventory, String module, String command) { this.hostPattern = hostPattern; this.inventory = inventory; this.module = module; this.command = command; } @DataBoundSetter public void setAnsibleName(String ansibleName) { this.ansibleName = ansibleName; } @DataBoundSetter public void setCredentialsId(String credentialsId) { this.credentialsId = credentialsId; } @DataBoundSetter public void setSudo(boolean sudo) { this.sudo = sudo; } @DataBoundSetter public void setSudoUser(String sudoUser) { this.sudoUser = sudoUser; } @DataBoundSetter public void setForks(int forks) { this.forks = forks; } @DataBoundSetter public void setUnbufferedOutput(boolean unbufferedOutput) { this.unbufferedOutput = unbufferedOutput; } @DataBoundSetter public void setColorizedOutput(boolean colorizedOutput) { this.colorizedOutput = colorizedOutput; } @DataBoundSetter public void setHostKeyChecking(boolean hostKeyChecking) { this.hostKeyChecking = hostKeyChecking; } @DataBoundSetter public void setAdditionalParameters(String additionalParameters) { this.additionalParameters = additionalParameters; } @Override public void perform(@Nonnull Run<?, ?> run, @Nonnull FilePath ws, @Nonnull Launcher launcher, @Nonnull TaskListener listener) throws InterruptedException, IOException { try { CLIRunner runner = new CLIRunner(run, ws, launcher, listener); Computer computer = Computer.currentComputer(); if (computer == null) { throw new AbortException("The ansible playbook build step requires to be launched on a node"); } String exe = AnsibleInstallation.getExecutable(ansibleName, AnsibleCommand.ANSIBLE, computer.getNode(), listener, run.getEnvironment(listener)); AnsibleAdHocCommandInvocation invocation = new AnsibleAdHocCommandInvocation(exe, run, ws, listener); invocation.setHostPattern(hostPattern); invocation.setInventory(inventory); invocation.setModule(module); invocation.setModuleCommand(command); invocation.setSudo(sudo, sudoUser); invocation.setForks(forks); invocation.setCredentials(StringUtils.isNotBlank(credentialsId) ? CredentialsProvider.findCredentialById(credentialsId, StandardUsernameCredentials.class, run) : null); invocation.setAdditionalParameters(additionalParameters); invocation.setHostKeyCheck(hostKeyChecking); invocation.setUnbufferedOutput(unbufferedOutput); invocation.setColorizedOutput(colorizedOutput); if (!invocation.execute(runner)) { throw new AbortException("Ansible Ad-Hoc command execution failed"); } } catch (IOException ioe) { Util.displayIOException(ioe, listener); ioe.printStackTrace(listener.fatalError(hudson.tasks.Messages.CommandInterpreter_CommandFailed())); throw ioe; } catch (AnsibleInvocationException aie) { listener.fatalError(aie.getMessage()); throw new AbortException(aie.getMessage()); } } @Extension public static final class DescriptorImpl extends AbstractAnsibleBuilderDescriptor { public DescriptorImpl() { super("Invoke Ansible Ad-Hoc Command"); } public FormValidation doCheckHostPattern(@QueryParameter String hostPattern) { return checkNotNullOrEmpty(hostPattern, "Host pattern must not be empty"); } } }