// remove the file from our computer too
        $filename = '/tmp/testfile-' . $hostname . '.txt';
        if (file_exists($filename)) {
            // tidy up
            unlink($filename);
        }
    }
});
// ========================================================================
//
// POSSIBLE ACTION(S)
//
// ------------------------------------------------------------------------
$story->addAction(function () {
    foreach (hostWithRole('upload_target') as $hostname) {
        fromHost($hostname)->downloadFile('testfile.txt', "/tmp/testfile-{$hostname}.txt");
    }
});
// ========================================================================
//
// POST-TEST INSPECTION
//
// ------------------------------------------------------------------------
$story->addPostTestInspection(function () {
    // we should have a file for each host in the configuration
    foreach (hostWithRole('upload_target') as $hostname) {
        $filename = '/tmp/testfile-' . $hostname . '.txt';
        if (!file_exists($filename)) {
            usingLog()->writeToLog("file not downloaded from host '{$hostname}'");
            usingErrors()->throwException("file '{$filename}' not downloaded");
        }
    // use the checkpoint to share the name of our screen session
    $checkpoint = getCheckpoint();
    $checkpoint->session = "storyplayer_test_session";
    // make sure the session isn't running on the host
    foreach (hostWithRole('host_target') as $hostId) {
        $details = fromHost($hostId)->getScreenSessionDetails($checkpoint->session);
        if ($details) {
            usingHost($hostId)->stopProcess($details->pid);
        }
    }
});
$story->addTestTeardown(function () {
    $checkpoint = getCheckpoint();
    // if we've left the session running, go and kill it off
    foreach (hostWithRole('host_target') as $hostId) {
        $details = fromHost($hostId)->getScreenSessionDetails($checkpoint->session);
        if ($details) {
            usingHost($hostId)->stopProcess($details->pid);
        }
    }
});
// ========================================================================
//
// POSSIBLE ACTION(S)
//
// ------------------------------------------------------------------------
$story->addAction(function () {
    $checkpoint = getCheckpoint();
    foreach (hostWithRole('host_target') as $hostId) {
        usingHost($hostId)->startInScreen($checkpoint->session, "top");
    }
<?php

// ========================================================================
//
// STORY DETAILS
//
// ------------------------------------------------------------------------
$story = newStoryFor('Storyplayer')->inGroup('Modules')->called('HTTP: Can connect to self-signed SSL server');
$story->requiresStoryplayerVersion(2);
// ========================================================================
//
// POSSIBLE ACTION(S)
//
// ------------------------------------------------------------------------
$story->addAction(function () {
    foreach (hostWithRole('ssl_target') as $hostname) {
        $url = "https://" . fromHost($hostname)->getHostname();
        fromHttp()->get($url);
    }
});
// ========================================================================
//
// POST-TEST INSPECTION
//
// ------------------------------------------------------------------------
$story->addPostTestInspection(function ($st) {
    // do nothing
});
 public function isConnectedToHost($hostId, $portNumber)
 {
     // what are we doing?
     $log = usingLog()->startAction("make sure ZMQ socket is connected to host '{$hostId}':{$portNumber}");
     // build the address that we should be connected to
     $ipAddress = fromHost($hostId)->getIpAddress();
     $zmqAddress = "tcp://{$ipAddress}:{$portNumber}";
     // where are we connected to?
     $connections = fromZmqSocket($this->args[0])->getEndpoints();
     // make sure we're connected
     assertsArray($connections['connect'])->containsValue($zmqAddress);
     // all done
     $log->endAction();
 }
Beispiel #5
0
 public function startVm($vmName)
 {
     // what are we doing?
     $log = usingLog()->startAction("start VM '{$vmName}'");
     // get the VM details
     $vmDetails = fromHost($vmName)->getDetails();
     // create our host adapter
     $host = HostLib::getHostAdapter($this->st, $vmDetails->type);
     // restart our virtual machine
     $host->startHost($vmDetails);
     // all done
     $log->endAction();
 }
//
// ------------------------------------------------------------------------
$story->addAction(function () {
    foreach (hostWithRole('upload_target') as $hostId) {
        // get the default user details for this test environment
        $hostUser = fromHost($hostId)->getStorySetting("user.username");
        $hostGroup = fromHost($hostId)->getStorySetting("user.group");
        // get the details for this file
        $details = fromHost($hostId)->getFileDetails('testfile.txt');
        // make sure we have the details that we expect
        assertsObject($details)->isNotNull();
        assertsObject($details)->hasAttribute("user");
        assertsString($details->user)->equals($hostUser);
        assertsObject($details)->hasAttribute("group");
        assertsString($details->group)->equals($hostGroup);
    }
});
// ========================================================================
//
// POST-TEST INSPECTION
//
// ------------------------------------------------------------------------
$story->addPostTestInspection(function () {
    foreach (hostWithRole('upload_target') as $hostId) {
        // get the default user details for this test environment
        $hostUser = fromHost($hostId)->getStorySetting("user.username");
        $hostGroup = fromHost($hostId)->getStorySetting("user.group");
        // check the details for this file
        expectsHost($hostId)->hasFileWithPermissions('testfile.txt', $hostUser, $hostGroup, 0644);
    }
});
//
// PRE-TEST INSPECTION
//
// ------------------------------------------------------------------------
// ========================================================================
//
// POSSIBLE ACTION(S)
//
// ------------------------------------------------------------------------
$story->addAction(function () {
    // we're going to store the received message in here
    $checkpoint = getCheckpoint();
    foreach (firstHostWithRole("zmq_target") as $hostId) {
        $context = usingZmqContext()->getZmqContext();
        $inPort = fromHost($hostId)->getStorySetting("zmq.multi.inPort");
        $outPort = fromHost($hostId)->getStorySetting("zmq.multi.outPort");
        $inSocket = usingZmqContext($context)->connectToHost($hostId, $inPort, 'PUSH');
        $outSocket = usingZmqContext($context)->connectToHost($hostId, $outPort, 'PULL');
        expectsZmqSocket($inSocket)->canSendmultiNonBlocking($checkpoint->expectedMessage);
        $checkpoint->actualMessage = fromZmqSocket($outSocket)->recvMulti();
    }
});
// ========================================================================
//
// POST-TEST INSPECTION
//
// ------------------------------------------------------------------------
$story->addPostTestInspection(function () {
    $checkpoint = getCheckpoint();
    assertsObject($checkpoint)->hasAttribute("expectedMessage");
    assertsObject($checkpoint)->hasAttribute("actualMessage");
Beispiel #8
0
 /**
  *
  * @param  stdClass $groupDef
  * @return void
  */
 public function destroyHost($groupDef)
 {
     // what are we doing?
     $log = usingLog()->startAction("destroy VM(s)");
     // stop all the VMs, one by one
     foreach ($groupDef->details->machines as $hostId => $machine) {
         // get the machine details
         $vmDetails = fromHostsTable()->getDetailsForHost($hostId);
         if ($vmDetails) {
             // is the VM actually running?
             if (fromHost($hostId)->getHostIsRunning()) {
                 // delete the VM from disk
                 //
                 // this will also deregister the host from the
                 // HostsTable and RolesTable
                 usingVagrant()->destroyVm($hostId);
             }
         }
     }
     // all done
     $log->endAction();
 }
//
// TEST SETUP / TEARDOWN
//
// ------------------------------------------------------------------------
$story->addTestSetup(function () {
    // this is what we expect to retrieve from the test environment config
    $checkpoint = getCheckpoint();
    $checkpoint->expected = "successfully retrieved this appSetting :)";
});
// ========================================================================
//
// POSSIBLE ACTION(S)
//
// ------------------------------------------------------------------------
$story->addAction(function () {
    // do nothing
});
// ========================================================================
//
// POST-TEST INSPECTION
//
// ------------------------------------------------------------------------
$story->addPostTestInspection(function ($st) {
    // what value do we expect to retrieve?
    $expected = fromCheckpoint()->get('expected');
    // make sure we have it
    foreach (hostWithRole('host_target') as $hostId) {
        $actual = fromHost($hostId)->getAppSetting('host.expected');
        assertsString($actual)->equals($expected);
    }
});
 public function connectToHost($hostId, $port, $socketType, $sendHwm = 100, $recvHwm = 100)
 {
     // what are we doing?
     $log = usingLog()->startAction("connect() to ZMQ '{$socketType}' socket on host '{$hostId}':{$port}");
     // do we have a supported socket?
     if (!isset($this->socketMap[$socketType])) {
         $msg = "unknown ZMQ socket type '{$socketType}'";
         $log->endAction($msg);
         throw new E5xx_ActionFailed(__METHOD__, $msg);
     }
     // where are we connecting to?
     $ipAddress = fromHost($hostId)->getIpAddress();
     // create the socket
     $socket = new ZMQSocket($this->args[0], $this->socketMap[$socketType]);
     if (!$socket) {
         $msg = "unable to create ZMQ socket";
         $log->endAction($msg);
         throw new E5xx_ActionFailed(__METHOD__, $msg);
     }
     // set high-water marks now
     $socket->setSockOpt(ZMQ::SOCKOPT_SNDHWM, $sendHwm);
     $socket->setSockOpt(ZMQ::SOCKOPT_RCVHWM, $recvHwm);
     // make the connection
     //
     // NOTE: we use the 'force' parameter here to avoid Storyplayer
     // hanging if the remote end is not available
     $socket->connect("tcp://{$ipAddress}:{$port}", true);
     // all done
     $log->endAction();
     return $socket;
 }
 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='******'"';
     $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();
 }
Beispiel #12
0
 /**
  * @param  string $sessionName
  * @return bool
  */
 public function getScreenIsRunning($sessionName)
 {
     // what are we doing?
     $log = usingLog()->startAction("check if screen session '{$sessionName}' is still running");
     // get the details
     $sessionData = fromHost($this->args[0])->getScreenSessionDetails($sessionName);
     // all done
     if ($sessionData) {
         $log->endAction("still running");
         return true;
     } else {
         $log->endAction("not running");
         return false;
     }
 }
Beispiel #13
0
 public function hasFolderWithPermissions($folder, $owner, $group, $mode)
 {
     // shorthand
     $octMode = decoct($mode);
     // what are we doing?
     $log = usingLog()->startAction("make sure folder '{$folder}' exists on host '{$this->args[0]}' with permissions '{$octMode}' owned by '{$owner}:{$group}'");
     // make sure we have valid host details
     $hostDetails = $this->getHostDetails();
     // get the file details
     $details = fromHost($hostDetails->hostId)->getFileDetails($folder);
     // validate the details
     if ($details === null) {
         throw new E5xx_ExpectFailed(__METHOD__, "'{$folder}' exists", "'{$folder}' does not exist");
     }
     if ($details->type != 'dir') {
         throw new E5xx_ExpectFailed(__METHOD__, "'{$folder}' is a file", "'{$folder}' is type '{$details->type}'");
     }
     if ($details->mode != $mode) {
         $theirOctMode = decoct($details->mode);
         throw new E5xx_ExpectFailed(__METHOD__, "'{$folder}' has permissions '{$octMode}'", "'{$folder}' has permissions '{$theirOctMode}'");
     }
     if ($details->user != $owner || $details->group != $group) {
         throw new E5xx_ExpectFailed(__METHOD__, "'{$folder}' has ownership '{$owner}:{$group}'", "'{$folder}' has ownership '{$details->user}:{$details->group}'");
     }
     // if we get here, then all is good
     $log->endAction();
 }
 public function provisionHosts(ProvisioningDefinition $hosts, $provConfig)
 {
     // what are we doing?
     $log = usingLog()->startAction("use dsbuild to provision host(s)");
     // the params file that we are going to output
     $dsbuildParams = new BaseObject();
     // build up the list of settings to write out
     foreach ($hosts as $hostId => $hostProps) {
         // what is the host's IP address?
         $ipAddress = fromHost($hostId)->getIpAddress();
         $propName = $hostId . '_ipv4Address';
         $dsbuildParams->{$propName} = $ipAddress;
         if (isset($hostProps->params)) {
             $dsbuildParams->mergeFrom($hostProps->params);
         }
     }
     // add in all the config settings that we know about
     $dsbuildParams->storyplayer_ipv4Address = fromConfig()->get('storyplayer.ipAddress');
     $dsbuildParams->mergeFrom($this->flattenData($this->st->getActiveConfig()->getData('')));
     // write them out
     $this->writeDsbuildParamsShellFile((array) $dsbuildParams);
     $this->writeDsbuildParamsYamlFile((array) $dsbuildParams);
     // at this point, we are ready to attempt provisioning
     //
     // provision each host in the order that they're listed
     foreach ($hosts as $hostId => $hostProps) {
         // which dsbuildfile are we going to run?
         $hostDir = fromHost($hostId)->getLocalFolder();
         $dsbuildFilename = $this->getDsbuildFilename($hostDir, $provConfig, $hostId);
         if ($dsbuildFilename === null) {
             // there is no dsbuildfile at all to run
             $log->endAction("cannot find dsbuildfile to run :(");
             throw new E5xx_ActionFailed(__METHOD__, "no dsbuildfile to run");
         }
         // at this point, we are ready to provision
         $commandRunner = new CommandRunner();
         // copy the dsbuildparams files to the target machine using scp
         // NOTE: the "vagrant rsync" command seems not working with some Vagrant provisioners (e.g. OpenStack)
         $command = 'scp' . ' ' . $dsbuildParams->{'hosts_' . $hostId . '_scpOptions_0'} . ' ' . $dsbuildParams->{'hosts_' . $hostId . '_scpOptions_1'} . ' dsbuildparams.*' . ' ' . $dsbuildParams->{'hosts_' . $hostId . '_sshUsername'} . '@' . $dsbuildParams->{'hosts_' . $hostId . '_ipAddress'} . ':/vagrant/';
         $result = $commandRunner->runSilently($command);
         if (!$result->didCommandSucceed()) {
             // try to rsync folders in case of scp fail
             $command = 'vagrant rsync ' . $hostId;
             $commandRunner->runSilently($command);
         }
         // provision
         $command = 'sudo bash /vagrant/' . $dsbuildFilename;
         $result = usingHost($hostId)->runCommand($command);
         // what happened?
         if (!$result->didCommandSucceed()) {
             throw new E5xx_ActionFailed(__METHOD__, "provisioning failed");
         }
     }
     // all done
     $log->endAction();
 }
    // make sure the session is running on each host
    foreach (hostWithRole('host_target') as $hostId) {
        foreach ($checkpoint->sessions as $session) {
            $details = fromHost($hostId)->getScreenSessionDetails($session);
            if (!$details) {
                usingHost($hostId)->startInScreen($session, 'top');
            }
        }
    }
});
$story->addTestTeardown(function () {
    $checkpoint = getCheckpoint();
    // if we've left the session running, go and kill it off
    foreach (hostWithRole('host_target') as $hostId) {
        foreach ($checkpoint->sessions as $session) {
            $details = fromHost($hostId)->getScreenSessionDetails($session);
            if ($details) {
                usingHost($hostId)->stopProcess($details->pid);
            }
        }
    }
});
// ========================================================================
//
// POSSIBLE ACTION(S)
//
// ------------------------------------------------------------------------
$story->addAction(function () {
    // make sure all the sessions are running first
    $checkpoint = getCheckpoint();
    foreach (hostWithRole('host_target') as $hostId) {
Beispiel #16
0
 public function disconnectFromHost($hostId, $port)
 {
     // what are we doing?
     $log = usingLog()->startAction("disconnect() from ZMQ tcp socket on host '{$hostId}':{$port}");
     // where are we connecting to?
     $ipAddress = fromHost($hostId)->getIpAddress();
     // we're reusing the existing socket
     $socket = $this->args[0];
     // attempt the disconnection
     $socket->disconnect("tcp://{$ipAddress}:{$port}");
     // all done
     $log->endAction();
 }
//
// PRE-TEST INSPECTION
//
// ------------------------------------------------------------------------
// ========================================================================
//
// POSSIBLE ACTION(S)
//
// ------------------------------------------------------------------------
$story->addAction(function () {
    // we're going to store the received message in here
    $checkpoint = getCheckpoint();
    foreach (firstHostWithRole("zmq_target") as $hostId) {
        $context = usingZmqContext()->getZmqContext();
        $inPort = fromHost($hostId)->getStorySetting("zmq.single.inPort");
        $outPort = fromHost($hostId)->getStorySetting("zmq.single.outPort");
        $inSocket = usingZmqContext($context)->connectToHost($hostId, $inPort, 'PUSH');
        $outSocket = usingZmqContext($context)->connectToHost($hostId, $outPort, 'PULL');
        usingZmqSocket($inSocket)->send($checkpoint->expectedMessage);
        $checkpoint->actualMessage = fromZmqSocket($outSocket)->recv();
    }
});
// ========================================================================
//
// POST-TEST INSPECTION
//
// ------------------------------------------------------------------------
$story->addPostTestInspection(function () {
    $checkpoint = getCheckpoint();
    assertsObject($checkpoint)->hasAttribute("expectedMessage");
    assertsObject($checkpoint)->hasAttribute("actualMessage");
Beispiel #18
0
 public function stopProcess($pid, $grace = 5)
 {
     // what are we doing?
     $log = usingLog()->startAction("stop process '{$pid}' on host '{$this->args[0]}'");
     // is the process running at all?
     if (!fromHost($this->args[0])->getPidIsRunning($pid)) {
         $log->endAction("process is not running");
         return;
     }
     // yes it is, so stop it
     // send a TERM signal to the screen session
     $log->addStep("send SIGTERM to process '{$pid}'", function () use($pid) {
         if ($this->getIsLocalhost()) {
             posix_kill($pid, SIGTERM);
         } else {
             usingHost($this->args[0])->runCommand("kill {$pid}");
         }
     });
     // has this worked?
     $isStopped = $log->addStep("wait for process to terminate", function () use($pid, $grace, $log) {
         for ($i = 0; $i < $grace; $i++) {
             if (!fromHost($this->args[0])->getPidIsRunning($pid)) {
                 return true;
             }
             // process still exists
             sleep(1);
         }
         return false;
     });
     // did the process stop?
     if ($isStopped) {
         $log->endAction();
         return;
     }
     $log->addStep("send SIGKILL to process '{$pid}'", function () use($pid) {
         if ($this->getIsLocalhost()) {
             posix_kill($pid, SIGKILL);
         } else {
             usingHost($this->args[0])->runCommand("kill -9 {$pid}");
         }
         sleep(1);
     });
     // success?
     if (fromHost($this->args[0])->getProcessIsRunning($pid)) {
         $log->endAction("process is still running :(");
         throw new E5xx_ActionFailed(__METHOD__);
     }
     // all done
     $log->endAction("process has finished");
 }