Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CMSO-1592] New command to wait for workflows and run wake. #2485

Open
wants to merge 7 commits into
base: 3.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions src/Collections/Workflows.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,46 @@ public function __construct(array $options = [])
}
}

/**
* Returns all existing workflows that match given environment id and status.
*
* @return Workflow[]
*/
public function allByEnvironmentIdAndStatus($environment_id, $status)
{
$status_map = [
'finished' => 'isFinished',
'unfinished' => 'isUnfinished',
'successful' => 'isSuccessful',
'failed' => 'isFailed',
];
if (!isset($status_map[$status])) {
throw new TerminusException('Invalid status "{status}".', compact('status'));
}
$status_method = $status_map[$status];
return array_filter(
$this->all(),
function ($workflow) use ($environment_id, $status_method) {
return $workflow->getEnvironmentId() == $environment_id && $workflow->$status_method();
}
);
}

/**
* Returns all existing workflows that match given environment id.
*
* @return Workflow[]
*/
public function allByEnvironmentId($environment_id)
{
return array_filter(
$this->all(),
function ($workflow) use ($environment_id) {
return $workflow->getEnvironmentId() == $environment_id;
}
);
}

/**
* Returns all existing workflows that have finished
*
Expand All @@ -64,6 +104,51 @@ function ($workflow) {
);
}

/**
* Returns all existing workflows that have not finished
*
* @return Workflow[]
*/
public function allUnfinished()
{
return array_filter(
$this->all(),
function ($workflow) {
return $workflow->isUnfinished();
}
);
}

/**
* Returns all existing workflows that have succeeded
*
* @return Workflow[]
*/
public function allSuccessful()
{
return array_filter(
$this->all(),
function ($workflow) {
return $workflow->isSuccessful();
}
);
}

/**
* Returns all existing workflows that have failed
*
* @return Workflow[]
*/
public function allFailed()
{
return array_filter(
$this->all(),
function ($workflow) {
return $workflow->isFailed();
}
);
}

/**
* Returns all existing workflows that contain logs
*
Expand Down
103 changes: 103 additions & 0 deletions src/Commands/Env/WaitWorkflowsCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?php

namespace Pantheon\Terminus\Commands\Env;

use Pantheon\Terminus\Commands\TerminusCommand;
use Pantheon\Terminus\Site\SiteAwareInterface;
use Pantheon\Terminus\Site\SiteAwareTrait;
use Pantheon\Terminus\Exceptions\TerminusException;

/**
* Class WaitWorkflowsCommand.
*
* @package Pantheon\Terminus\Commands\Env
*/
class WaitWorkflowsCommand extends TerminusCommand implements SiteAwareInterface
{
use SiteAwareTrait;

/**
* Waits for all workflows in a given environment and optionally attempt to do healthcheck on it.
*
* @authorize
*
* @command env:wait-workflows
* @aliases env:ww
*
* @param string $site_env Site & environment in the format `site-name.env`
* @option bool $healthcheck Whether to wait for the healthcheck to pass
* @option int $timeout How long to wait for the workflows to finish
*
* @throws TerminusException
*
* @usage <site>.<env> Wakes <site>'s <env> environment by pinging it.
*/
public function waitWorkflows($site_env, $options = [
'healthcheck' => true,
'timeout' => 300,
])
{
$this->requireSiteIsNotFrozen($site_env);
$site = $this->getSite($site_env);
$env = $this->getEnv($site_env);

$workflows = $site->getWorkflows()->setPaging(false)->fetch()->allByEnvironmentIdAndStatus(
$env->id,
'unfinished'
);
$this->log()->notice('Waiting for {number} workflow(s).', ['number' => count($workflows)]);

$startWaiting = time();
$wf_types_to_wait = [
'sync_code',
'sync_code_with_build',
'sync_code_external_vcs',
'environment_update_pantheon_yml',
'check_database_version',
'change_database_version',
'change_object_cache_version',
'change_search_version',
];
foreach ($workflows as $workflow) {
$type = $workflow->get('type');
if (!in_array($type, $wf_types_to_wait)) {
continue;
}
$description = $workflow->get('description');
$workflow->fetch();
while ($workflow->isUnfinished()) {
$this->log()->notice(
"Workflow '{description}' is running...",
['description' => $description]
);

if (time() - $startWaiting > $options['timeout']) {
throw new TerminusException(
'Timeout waiting for workflows to finish. Please check the status of the workflows manually.'
);
}
sleep(5);
$workflow->fetch();
}
// Abort if workflow failed.
if ($workflow->isFailed()) {
throw new TerminusException(
'Workflow failed. Please check the status of the workflows manually.'
);
}
if ($workflow->isSuccessful()) {
$this->log()->notice(
"Workflow '{description}' succeeded.",
['description' => $description]
);
}
}

if ($options['healthcheck']) {
$this->log()->notice('Running healthcheck on environment...');
$env->wake();
}

$this->log()->notice('All done!');
}
}
8 changes: 0 additions & 8 deletions src/Commands/Env/WakeCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,6 @@ public function wake($site_env)
$env = $this->getEnv($site_env);
$wakeStatus = $env->wake();

// @TODO: Move the exceptions up the chain to the `wake` function. (One env is ported over).
if (empty($wakeStatus['success'])) {
throw new TerminusException('Could not reach {target}', $wakeStatus);
}
if (empty($wakeStatus['styx'])) {
throw new TerminusException('Pantheon headers missing, which is not quite right.');
}

$this->log()->notice('OK >> {target} responded', $wakeStatus);
}
}
6 changes: 6 additions & 0 deletions src/Models/Environment.php
Original file line number Diff line number Diff line change
Expand Up @@ -1008,6 +1008,12 @@ function ($domain) {
$response = $this->request()->request(
"https://{$domain->id}/pantheon_healthcheck"
);
if ($response['status_code'] != 200) {
throw new TerminusException('Could not reach {target}', $wakeStatus);
}
if (empty($response['headers']['X-Pantheon-Styx-Hostname'])) {
throw new TerminusException('Pantheon headers missing, which is not quite right.');
}
return [
'success' => ($response['status_code'] === 200),
'styx' => $response['headers']['X-Pantheon-Styx-Hostname'],
Expand Down
33 changes: 33 additions & 0 deletions src/Models/Workflow.php
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,29 @@ public function getStatus()
return $status;
}

/**
* Returns the environment_id of this workflow
*
* @return string
*/
public function getEnvironmentId()
{
if ($this->has('environment_id')) {
return $this->get('environment_id');
}
return null;
}

/**
* Detects if the workflow has not finished
*
* @return bool True if workflow has not finished
*/
public function isUnfinished()
{
return !$this->has('result');
}

/**
* Detects if the workflow has finished
*
Expand All @@ -250,6 +273,16 @@ public function isSuccessful()
return $this->get('result') == 'succeeded';
}

/**
* Detects if the workflow was failed
*
* @return bool True if workflow failed
*/
public function isFailed()
{
return $this->get('result') != 'succeeded';
}

/**
* Returns a list of WorkflowOperations for this workflow
*
Expand Down
1 change: 1 addition & 0 deletions src/Terminus.php
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ private function addBuiltInCommandsAndHooks()
'Pantheon\\Terminus\\Commands\\Env\\MetricsCommand',
'Pantheon\\Terminus\\Commands\\Env\\RotateRandomSeedCommand',
'Pantheon\\Terminus\\Commands\\Env\\ViewCommand',
'Pantheon\\Terminus\\Commands\\Env\\WaitWorkflowsCommand',
'Pantheon\\Terminus\\Commands\\Env\\WakeCommand',
'Pantheon\\Terminus\\Commands\\Env\\WipeCommand',
'Pantheon\\Terminus\\Commands\\HTTPS\\InfoCommand',
Expand Down
14 changes: 14 additions & 0 deletions tests/Functional/EnvCommandsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,20 @@ public function testDeployCommand()
);
}

/**
* @test
* @covers \Pantheon\Terminus\Commands\Env\WaitWorkflowsCommand
*
* @group env
* @group short
*/
public function testWaitWorkflowsCommand()
{
$this->terminus(
sprintf('env:wait-workflows %s.%s', $this->getSiteName(), 'dev')
);
}

/**
* @test
* @covers \Pantheon\Terminus\Commands\Env\CloneContentCommand
Expand Down