package ee.elinyo.teamcity.plugins.ansible.agent;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import jetbrains.buildServer.RunBuildException;
import jetbrains.buildServer.agent.artifacts.ArtifactsWatcher;
import jetbrains.buildServer.agent.runner.BuildServiceAdapter;
import jetbrains.buildServer.agent.runner.ProcessListener;
import jetbrains.buildServer.agent.runner.ProgramCommandLine;
import jetbrains.buildServer.agent.runner.SimpleProgramCommandLine;
import jetbrains.buildServer.runner.CommandLineArgumentsUtil;
import jetbrains.buildServer.util.FileUtil;
import org.jetbrains.annotations.NotNull;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.text.StringUtil;
import ee.elinyo.teamcity.plugins.ansible.common.AnsibleCommand;
import ee.elinyo.teamcity.plugins.ansible.common.AnsibleRunConfig;
public class AnsibleRunService extends BuildServiceAdapter {
protected static final Logger LOG = Logger.getInstance(AnsibleRunService.class.getName());
private ArtifactsWatcher artifactsWatcher;
public AnsibleRunService(ArtifactsWatcher artifactsWatcher) {
this.artifactsWatcher = artifactsWatcher;
}
@Override
public ProgramCommandLine makeProgramCommandLine() throws RunBuildException {
AnsibleRunConfig config = new AnsibleRunConfig(getRunnerParameters());
if (LOG.isDebugEnabled()) {
LOG.debug("Going to run ansible with parameters: " + config.toString());
}
if (AnsibleCommand.CUSTOM_SCRIPT.equals(config.getCommandType())) {
return makeCustomScriptCommand(config);
}
return makeExecutableCommand(config);
}
private ProgramCommandLine makeExecutableCommand(AnsibleRunConfig config)
throws RunBuildException {
String workingDir = getWorkingDirectory().getPath();
StringBuilder args = new StringBuilder("");
if (!StringUtil.isEmptyOrSpaces(config.getInventory())) {
args.append("-i ").append(config.getInventory());
}
if (StringUtil.isEmptyOrSpaces(config.getPlaybook())) {
throw new RunBuildException("Ansible playbook should be specified");
}
args.append(" ").append(config.getPlaybook());
if (!StringUtil.isEmptyOrSpaces(config.getOptions())) {
args.append(" ").append(config.getOptions());
}
return new SimpleProgramCommandLine(getProvidedEnvironmetVariables(),
workingDir,
config.getExecutable(), CommandLineArgumentsUtil.extractArguments(args.toString()));
}
private Map<String, String> getProvidedEnvironmetVariables() {
Map<String, String> vars = new HashMap<String, String>(getEnvironmentVariables());
vars.put("ANSIBLE_NOCOLOR", "1");
return vars;
}
private ProgramCommandLine makeCustomScriptCommand(AnsibleRunConfig config) throws RunBuildException {
String workingDir = getWorkingDirectory().getPath();
List<String> args = Collections.emptyList();
String customScript = getCustomScriptExecutable(config);
return new SimpleProgramCommandLine(getProvidedEnvironmetVariables(),
workingDir,
customScript, args);
}
private String getCustomScriptExecutable(AnsibleRunConfig config) throws RunBuildException {
String content = null;
File scriptFile = null;
if (config.getSourceCode() != null) {
content = config.getSourceCode().replace("\r\n", "\n").replace("\r", "\n");
}
if (StringUtil.isEmptyOrSpaces(content)) {
throw new RunBuildException("Custom script source code cannot be empty");
}
try {
scriptFile = File.createTempFile("ansible_custom_exe", null, getBuildTempDirectory());
FileUtil.writeFileAndReportErrors(scriptFile, content);
} catch (IOException e) {
throw new RunBuildException("Failed to create a tmp file for custom ansible execution script");
}
boolean executable = scriptFile.setExecutable(true, true);
if (!executable) {
throw new RunBuildException("Failed to set executable permissions to " + scriptFile.getAbsolutePath());
}
return scriptFile.getAbsolutePath();
}
@NotNull
@Override
public List<ProcessListener> getListeners() {
List<ProcessListener> listeners = new ArrayList<ProcessListener>(super.getListeners());
listeners.add(new AnsibleOutputListener(getBuild(), getRunnerContext(), artifactsWatcher));
return listeners;
}
}