public function provisionHosts(ProvisioningDefinition $hosts, $provConf)
{
// what are we doing?
$log = usingLog()->startAction("use Ansible to provision host(s)");
// get our ansible configuration
$ansibleSettings = fromConfig()->getModuleSetting('ansible');
// our reverse list of roles => hosts
$rolesToHosts = array();
// build up the list of roles
foreach ($hosts as $hostId => $hostProps) {
// what is the host's IP address?
$ipAddress = fromHost($hostId)->getIpAddress();
// add the host to the required roles
if (isset($hostProps->roles)) {
foreach ($hostProps->roles as $role) {
if (!isset($rolesToHosts[$role])) {
$rolesToHosts[$role] = array();
}
$rolesToHosts[$role][] = $ipAddress;
}
}
}
// at this point, we know which roles need applying to which hosts
//
// build up the inventory file
$inventory = "";
foreach ($rolesToHosts as $role => $hostsForRole) {
// add the role marker
$inventory .= "[{$role}]" . PHP_EOL;
// add the list of hosts
foreach ($hostsForRole as $host) {
$inventory .= $host . PHP_EOL;
}
// add an extra blank line for readability
$inventory .= PHP_EOL;
}
// write out the inventory
$inventoryFile = $this->writeInventoryFile($inventory);
// where should we create the host_vars?
$inventoryFolder = dirname($inventoryFile);
// we set these in the foreach() loop
$sshUsername = null;
$sshKeyFile = null;
// now we need to write out the host files
foreach ($hosts as $hostId => $hostProps) {
// what is the host's IP address?
$ipAddress = fromHost($hostId)->getIpAddress();
$sshUsername = fromHost($hostId)->getSshUsername();
$sshKeyFile = fromHost($hostId)->getSshKeyFile();
// do we have any vars to write?
if (!isset($hostProps->params) || $hostProps->params === null || is_array($hostProps) && count($hostProps) == 0) {
// we'd better remove any host_vars file that exists,
// in case what's there (if anything) is left over from
// a different test run
$this->removeHostVarsFile($inventoryFolder, $ipAddress);
} else {
// write the host vars file
$this->writeHostVarsFile($inventoryFolder, $ipAddress, $hostProps->params);
}
}
// build the command for Ansible
$command = 'ansible-playbook -i "' . $inventoryFile . '"' . ' "--private-key=' . $sshKeyFile . '"' . ' "--user=' . $sshUsername . '"';
$command .= ' "' . $ansibleSettings->dir . DIRECTORY_SEPARATOR . $ansibleSettings->playbook . '"';
// let's run the command
//
// this looks like a hack, but it is the only way to work with Ansible
// if there's an ansible.cfg in the root of the playbook :(
$cwd = getcwd();
chdir($ansibleSettings->dir);
$commandRunner = new CommandRunner();
$result = $commandRunner->runSilently($command);
chdir($cwd);
// what happened?
if (!$result->didCommandSucceed()) {
throw new E5xx_ActionFailed(__METHOD__, "provisioning failed");
}
// all done
$log->endAction();
}