public function createHost($groupDef, $provisioningVars = array())
{
// what are we doing?
$log = usingLog()->startAction('create new VM');
// make sure we're happy with this group
$this->checkGroupDefinition($groupDef);
// where is the action?
$baseFolder = $this->getVagrantDir($groupDef);
// make sure we're happy with details about the machine
foreach ($groupDef->details->machines as $hostId => $machine) {
// TODO: it would be great to autodetect this one day
if (!isset($machine->osName)) {
throw new E5xx_ActionFailed(__METHOD__, "missing groupDef->details->machines['{$hostId}']->osName");
}
if (!isset($machine->roles)) {
throw new E5xx_ActionFailed(__METHOD__, "missing groupDef->details->machines['{$hostId}']->roles");
}
}
// make sure the VM is stopped, if it is running
$log->addStep('stop vagrant VM in ' . $baseFolder . ' if already running', function () use($baseFolder) {
$command = "vagrant destroy --force";
$this->runCommandAgainstHostManager($baseFolder, $command);
});
// remove any existing hosts table entry
foreach ($groupDef->details->machines as $hostId => $machine) {
usingHostsTable()->removeHost($hostId);
// remove any roles
usingRolesTable()->removeHostFromAllRoles($hostId);
}
// work out which network interface to use
$this->setVagrantBridgedInterface();
// let's start the VM
$command = "vagrant up";
$result = $log->addStep('create vagrant VM(s) in ' . $baseFolder, function () use($baseFolder, $command) {
return $this->runCommandAgainstHostManager($baseFolder, $command);
});
// did it work?
if ($result->returnCode != 0) {
$log->endAction("VM failed to start or provision :(");
throw new E5xx_ActionFailed(__METHOD__);
}
// yes it did!!
// store the details
foreach ($groupDef->details->machines as $hostId => $machine) {
// we want all the details from the config file
$vmDetails = clone $machine;
// this allows the story to perform actions against a single
// machine if required
$vmDetails->type = 'VagrantVm';
// new in v2.x:
//
// when provisioning a folder of vagrant vms, we now use
// the same name for the VM that vagrant uses
$vmDetails->hostId = $hostId;
// remember where the machine lives
$vmDetails->dir = $baseFolder;
// we need to remember how to SSH into the box
$vmDetails->sshUsername = 'vagrant';
$vmDetails->sshKeyFile = $this->determinePrivateKey($vmDetails);
$vmDetails->sshOptions = ["-i '" . $vmDetails->sshKeyFile . "'", "-o StrictHostKeyChecking=no", "-o UserKnownHostsFile=/dev/null", "-o LogLevel=quiet"];
$vmDetails->scpOptions = ["-i '" . $vmDetails->sshKeyFile . "'", "-o StrictHostKeyChecking=no"];
// remember how to connect to the machine via the network
$vmDetails->ipAddress = $this->determineIpAddress($vmDetails);
$vmDetails->hostname = $this->determineHostname($vmDetails);
// mark the box as provisioned
// we will use this in stopBox() to avoid destroying VMs that failed
// to provision
$vmDetails->provisioned = true;
// remember this vm, now that it is running
usingHostsTable()->addHost($vmDetails->hostId, $vmDetails);
foreach ($vmDetails->roles as $role) {
usingRolesTable()->addHostToRole($vmDetails, $role);
}
// now, let's get this VM into our SSH known_hosts file, to avoid
// prompting people when we try and provision this VM
$log->addStep("get the VM into the SSH known_hosts file", function () use($vmDetails) {
usingHost($vmDetails->hostId)->runCommand("ls");
});
}
// all done
$log->endAction();
}