Completed
Pull Request — master (#588)
by Mateusz
11:08
created

DeployJob::updateStatus()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 5
nc 1
nop 1
1
<?php
2
3
/**
4
 * Runs a deployment via the most appropriate backend
5
 */
6
class DeployJob extends DeploynautJob {
7
8
	/**
9
	 * @var array
10
	 */
11
	public $args;
12
13
	/**
14
	 * Poll the sigFile looking for a signal to self-deliver.
15
	 * This is useful if we don't know the PID of the worker - we can easily deliver signals
16
	 * if we only know the ClassName and ID of the DataObject.
17
	 */
18
	public function alarmHandler() {
19
		$sigFile = $this->args['sigFile'];
20
		if (file_exists($sigFile) && is_readable($sigFile) && is_writable($sigFile)) {
21
			$signal = (int)file_get_contents($sigFile);
22
			if (is_int($signal) && in_array((int)$signal, [
23
				// The following signals are trapped by both Resque and Rainforest.
24
				SIGTERM,
25
				SIGINT,
26
				SIGQUIT,
27
				// The following are Resque only.
28
				SIGUSR1,
29
				SIGUSR2,
30
				SIGCONT
31
			])) {
32
				echo sprintf(
33
					'[-] Signal "%s" received, delivering to own process group, PID "%s".' . PHP_EOL,
34
					$signal,
35
					getmypid()
36
				);
37
38
				// Mark the signal as received.
39
				unlink($sigFile);
40
41
				// Dispatch to own process group.
42
				$pgid = posix_getpgid(getmypid());
43
				if ($pgid<=0) {
44
					echo sprintf(
45
						'[-] Unable to send signal to invalid PGID "%s".' . PHP_EOL,
46
						$pgid
47
					);
48
				} else {
49
					posix_kill(-$pgid, $signal);
50
				}
51
			}
52
		}
53
54
		// Wake up again soon.
55
		pcntl_alarm(1);
56
	}
57
58
	public function setUp() {
59
		// Make this process a session leader so we can send signals
60
		// to this job as a whole (including any subprocesses such as spawned by Symfony).
61
		posix_setsid();
62
63
		if(function_exists('pcntl_alarm') && function_exists('pcntl_signal')) {
64
			if (!empty($this->args['sigFile'])) {
65
				echo sprintf('[-] Signal file requested, polling "%s".' . PHP_EOL, $this->args['sigFile']);
66
				declare(ticks = 1);
67
				pcntl_signal(SIGALRM, [$this, 'alarmHandler']);
68
				pcntl_alarm(1);
69
			}
70
		}
71
72
		$this->updateStatus(DNDeployment::TR_DEPLOY);
73
		chdir(BASE_PATH);
74
	}
75
76
	public function perform() {
77
		echo "[-] DeployJob starting" . PHP_EOL;
78
		$log = new DeploynautLogFile($this->args['logfile']);
79
80
		$deployment = DNDeployment::get()->byID($this->args['deploymentID']);
81
		$environment = $deployment->Environment();
82
		$project = $environment->Project();
83
		// This is a bit icky, but there is no easy way of capturing a failed deploy by using the PHP Resque
84
		try {
85
			// Disallow concurrent deployments (don't rely on queuing implementation to restrict this)
86
			// Only consider deployments started in the last 30 minutes (older jobs probably got stuck)
87
			$runningDeployments = $environment->runningDeployments()->exclude('ID', $this->args['deploymentID']);
88 View Code Duplication
			if($runningDeployments->count()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
89
				$runningDeployment = $runningDeployments->first();
90
				$log->write(sprintf(
91
					'[-] Error: another deployment is in progress (started at %s by %s)',
92
					$runningDeployment->dbObject('Created')->Nice(),
93
					$runningDeployment->Deployer()->Title
94
				));
95
				throw new RuntimeException(sprintf(
96
					'Another deployment is in progress (started at %s by %s)',
97
					$runningDeployment->dbObject('Created')->Nice(),
98
					$runningDeployment->Deployer()->Title
99
				));
100
			}
101
102
			$environment->Backend()->deploy(
103
				$environment,
104
				$log,
105
				$project,
106
				// Pass all args to give the backend full visibility. These args also contain
107
				// all options from the DeploymentStrategy merged in, including sha.
108
				$this->args
109
			);
110
		} catch(Exception $e) {
111
			// DeploynautJob will automatically trigger onFailure.
112
			echo "[-] DeployJob failed" . PHP_EOL;
113
			throw $e;
114
		}
115
		$this->updateStatus(DNDeployment::TR_COMPLETE);
116
		echo "[-] DeployJob finished" . PHP_EOL;
117
	}
118
119
	public function onFailure(Exception $exception) {
120
		$this->updateStatus(DNDeployment::TR_FAIL);
121
	}
122
123
	/**
124
	 * @param string $status Transition
125
	 * @global array $databaseConfig
126
	 */
127
	protected function updateStatus($status) {
128
		global $databaseConfig;
129
		DB::connect($databaseConfig);
130
		$dnDeployment = DNDeployment::get()->byID($this->args['deploymentID']);
131
		$dnDeployment->getMachine()->apply($status);
132
	}
133
134
	/**
135
	 * @return DNData
136
	 */
137
	protected function DNData() {
138
		return DNData::inst();
139
	}
140
}
141