-
Notifications
You must be signed in to change notification settings - Fork 0
/
deploy
executable file
·477 lines (427 loc) · 15.6 KB
/
deploy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
#!/usr/bin/php -q
<?php
/**
* Author: Dan Shumaker
* Date: 10/1/2012 - 1/4/2014
* script: deploy
*/
require_once dirname(__FILE__) . '/cli_settings.php';
$help = "
Description: Move files, database, or code from one acquia server to the next and run drush commands.
- Yes you can use the gui to do most of these things (not the drush, varnish, memcache stuff) but CLI's are better! :)
Features:
- Task Queue - It will wait until one acquia task process is done before starting another one. This is
nice because their might be six or seven acquia tasks that need to be done for any one push and with
this deploy tool you only have to initiate the sequence and then \"walk away\". If any one of the tasks
fail then the queue of tasks is aborted (not rolled back but just halted).
- Command line Automation - While the gui is nice I wanted to be able to execute several tasks at once . This deploy
script automates that for you.
";
/*
Dependencies:
- This deploy script depends on valid drush aliases being installed on your acquia server.
- You'll need acquia's aliases for your sites: https://docs.acquia.com/cloud/drush-aliases
- You'll need acquia's cloud api for your site: https://insight.acquia.com/cloud/util/download/drush
- Only tested with drush 5.
- access to acquia network accounts.
- ssh keys installed on acquia server and network accounts.
Setup:
- Initally you need to setup a deploy process up by saving all the credentials in a configuration file. Then after that you call deploy with
the --load parameter and nothing else and it does the rest.
Typical usages after setup:
deploy --load=stage_to_dev_db+files.dep
deploy --load=dev_to_stage_code_only.dep
deploy --load=dev_to_stage.dep
deploy --load=stage_to_prod.dep
Typical setup usage:
Setup for dev_to_stage_db_files.dep
deploy --varnish=1 \
--database=1 \
--files=1 \
--memcache=1 \
--drush="vset drupal_stale_file_threshold 1 -y;vset shield_user XXXXXX -y; vset shield_pass XXXXXXX -y; cc all;vset drupal_stale_file_threshold 172800 -y" \
--source=@drush_dev_server_alais \
--dest=@drush_stage_server_alias \
--dest_db=XXXX \
--dest_env=dev \
--dest_host=staging-XXXX.prod.hosting.acquia.com \
--dest_domain=XXXXXdev.prod.acquia-sites.com \
--save=stage_to_dev_db_files.dep
Command Line Options:
--varnish ( off ) -- (boolean) Purges the varnish cache for the site.
--database ( off ) -- Specifies the databasename to push & pull
--code ( off ) -- (boolean) Whether or not to push code -- off by default
--files ( off ) -- (boolean) whether or not to push the default/files directory
--backup ( off ) -- (boolean) backup the database before pushing and pulling it.
--memcache ( off ) -- (boolean) purge memcache on server
--drush ( (quote surrounded drush commands with the drush left out of the beginning of the command see examples)
--source ( @dev ) (drush alias of source site)
--dest ( @test ) ( drush alias of destination site)
--dest_db ( autocalculated from drush dest alais ) -- you can override the autocalculated values if you wish.
--dest_env ( autocalculated from drush dest alais )
--dest_host ( autocalculated from drush dest alais )
--dest_domain ( autocalculated from drush dest alais )
--save ( off ) (don't run any commands but save the settings to a file for later use -- RUN THIS FIRST)
--load ( off ) (specify a deploy settings / configuration file to load and execute)
--print ( off ) (print help)
*/
class StopWatch {
public $total;
public $time;
public function __construct() {
$this->total = $this->time = microtime(true);
}
public function clock() {
return -$this->time + ($this->time = microtime(true));
}
public function elapsed() {
return microtime(true) - $this->total;
}
public function reset() {
$this->total=$this->time=microtime(true);
}
}
class Tio {
// If wanted pretty output to the browser then I'd use krumo: http://krumo.sourceforge.net/
// But I want terminal and file output.
public $prompt = FALSE;
public $verbose = FALSE;
public $timing = FALSE;
public $db;
public $file = FALSE;
public $start_time;
public $stderr;
public $stdin;
public $stdout;
public $io = array(
0 => array("pipe","r"), // stdin , what child proc will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("pipe", "w") // stderr is a pipe that the child will write to
);
function __construct() {
$this->start_time = new StopWatch();
}
public function p($str, $prompt=FALSE, $error=FALSE) {
if (is_array($str) && $this->verbose ) {
if ($this->file) {
if (is_string($this->file)) {
$this->file = fopen($this->file, 'w') or die('failed to open file') ;
}
ob_start();
var_dump($str);
$result = ob_get_clean();
fwrite($this->file, $result);
} else {
print_r($str);
}
}
if ($this->verbose || $error ) {
if ($this->file) {
if (is_string($this->file)) {
$this->file = fopen($this->file, 'w') or die('failed to open file') ;
}
fwrite($this->file, $str);
} else {
print $str . "\n";
}
}
}
function pt($start=0) {
if ($this->timing) {
if ($start === 1) {
$this->start_time->reset();
}
if ($this->start_time->elapsed() > 60) {
$elapsed = $this->start_time->elapsed() / 60;
$estr = round($elapsed,2) . " minutes ";
} else {
$estr = round($this->start_time->elapsed(),2) . " seconds ";
}
print date("g:i:s A D, F jS Y",time()) . " Elapsed: " . $estr . "\n";
}
}
private function read_til_end($pipe) {
$buffer = "";
$results = "";
// Read til the end
while (($buffer = fgets($pipe)) !== false) {
$results .= $buffer;
}
if (!feof($pipe)) {
echo "Error: unexpected fgets() fail\n";
}
return $results;
}
/**
* Blocking command execution
*/
public function run($command) {
print $command . "\n";
$this->stderr = '';
$this->stdout = '';
$process = proc_open($command, $this->io, $pipes);
if (is_resource($process)) {
$this->stdout .= stream_get_line($pipes[1], 65535);
$this->stderr .= stream_get_line($pipes[2], 65535);
$status = proc_get_status($process);
while ($status['running']) {
$this->stdout .= stream_get_line($pipes[1], 65535);
$this->stderr .= stream_get_line($pipes[2], 65535);
print "Waiting for " . $status['pid'] . "\n";
sleep(1);
$status = proc_get_status($process);
}
// Get the last output
$this->stdout .= stream_get_line($pipes[1], 65535);
$this->stderr .= stream_get_line($pipes[2], 65535);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
}
proc_close($process);
}
public function ismake($dir) {
if (is_dir($dir)) {
return;
} else {
if (mkdir($dir, 0777, true)) {
return;
} else {
$this->p("Couldn't create directory ". $dir);
exit();
}
}
}
}
class deploy{
function __construct($help) {
$this->cli = new CommandLineSettings( $help );
$this->io = new Tio();
$this->task_id = 0;
$this->backedup = FALSE;
}
public function processargs($argv) {
// Options
$this->cli->add_option( 'varnish', false, true );
$this->cli->add_option( 'database', false, true );
$this->cli->add_option( 'code', false, true );
$this->cli->add_option( 'files', false, true );
$this->cli->add_option( 'backup', false, true );
$this->cli->add_option( 'memcache', false, true );
$this->cli->add_option( 'drush', 'semi-colon separated list of commands beginning with drush and dest alias',true );
$this->cli->add_option( 'source', '@becker.dev', true );
$this->cli->add_option( 'dest', '@becker.test', true );
$this->cli->add_option( 'dest_db', 'autocalculated from drush dest alais', true );
$this->cli->add_option( 'dest_env', 'autocalculated from drush dest alais', true );
$this->cli->add_option( 'dest_host', 'autocalculated from drush dest alais', true );
$this->cli->add_option( 'dest_domain', 'autocalculated from drush dest alais', true );
$this->cli->parseArgs($argv);
if ($this->cli->args['load']) {
$this->cli->load_settings();
// Add ability to override settings
foreach($argv as $key => $arg) {
if (substr($arg, 0, 7) == '--load=') {
unset($argv[$key]);
break;
}
}
$this->cli->parseArgs($argv);
}
if ($this->cli->args['save']) {
$this->get_dest_info();
$this->cli->save_settings();
$this->cli->print_help();
exit();
}
$p = $this->cli->args['print'];
if ($p) {
$this->cli->print_help();
exit();
}
if ($this->cli->args['print']) {
$this->cli->print_help();
exit();
}
if ($this->cli->args['backup']) {
$this->io->timing = true;
$this->io->pt(1);
print "\n" . $this->backup() . "\n" ;
$this->io->pt();
}
if ($this->cli->args['code']) {
$this->io->timing = true;
$this->io->pt(1);
print "\n" . $this->code() . "\n";
$this->io->pt();
}
if ($this->cli->args['files']) {
$this->io->timing = true;
$this->io->pt(1);
print "\n" . $this->files() . "\n";
$this->io->pt();
}
if ($this->cli->args['database']) {
$this->io->timing = true;
$this->io->pt(1);
print "\n" . $this->database() . "\n";
$this->io->pt();
}
if ($this->cli->args['varnish']) {
$this->io->timing = true;
$this->io->pt(1);
print "\n" . $this->varnish() . "\n";
$this->io->pt();
}
if ($this->cli->args['memcache']) {
$this->io->timing = true;
$this->io->pt(1);
print "\n" . $this->memcache() . "\n";
$this->io->pt();
}
if ($this->cli->args['drush']) {
$this->io->timing = true;
$this->io->pt(1);
print "\n" . $this->drush() . "\n";
$this->io->pt();
}
}
public function get_dest_info() {
$this->io->run('drush ' . $this->cli->args['dest'] . ' ac-database-instance-list');
$res = preg_match('/\bname(?:\s)+:(?:\s)+(\w*)/', $this->io->stdout, $db_name);
if ($res == 1) {
$this->cli->args['dest_db'] = $db_name[1];
} else {
print "Error determining the database name, aborting";
exit();
}
$this->io->run('drush ' . $this->cli->args['dest'] . ' ac-environment-info ');
$res = preg_match('/\bname(?:\s)+:(?:\s)+(\w*)/', $this->io->stdout, $env);
if ($res) {
$this->cli->args['dest_env'] = $env[1];
} else {
print 'Error determining destination environment of ' . $this->cli->args['dest'] . '\n';
exit();
}
$res = preg_match('/ssh_host(?:\s)+:(?:\s)+(\S+)/', $this->io->stdout, $server);
if ($res) {
$this->cli->args['dest_host'] = $server[1];
} else {
print 'Error determining ssh_host of ' . $this->cli->args['dest'] . '\n';
exit();
}
/*
$this->io->run('drush ' . $this->cli->args['dest'] . ' ac-domain-list ' );
$res = preg_match('/name(?:\s)+:(?:\s)+(\S+)/', $this->io->stdout, $domain);
*/
// Drush 5
//$this->io->run('drush site-alias ' . $this->cli->args['dest'] . ' --component=uri' );
// Drush 6
$this->io->run('drush site-alias ' . $this->cli->args['dest'] . ' --fields=uri --format=list' );
$res = $this->io->stdout;
if ($res) {
$this->cli->args['dest_domain'] = trim($res);
} else {
print 'Error determining domain of ' . $this->cli->args['dest'] . '\n';
exit();
}
}
public function backup() {
$state = "ERROR";
$this->io->run('drush ' . $this->cli->args['dest'] . ' ac-database-instance-backup ' . $this->cli->args['dest_db']);
$state = $this->wait_for_acquia($this->get_ac_task());
$this->backedup = TRUE;
return $state;
}
public function get_ac_task() {
$output = $this->io->stdout . $this->io->stderr;
print "--debug--";
print $output;
$res = preg_match('/Task (\d+)/', $output, $task);
if ($res) {
$this->task_id = $task[1];
return $task[1];
} else {
print "Error retrieving Acquia Task , aborting\n";
print $output;
exit();
}
}
public function wait_for_acquia($task_id) {
$state = array(0 => 'test', 1 => 'first');
while ($state[1] != 'done') {
$this->io->run("drush " . $this->cli->args['dest'] . ' ac-task-info ' . $task_id);
$res = preg_match('/\bstate(?:\s)+:(?:\s)+(\w*)/', $this->io->stdout, $state);
if ($res) {
if (count($state) > 1) {
if ($state[1] != 'done') {
print implode(' ', array('Task', $task_id , 'is', $state[1] ,"...\n"));
sleep(10);
} else {
print "\nFinished\n";
return $state[1];
}
} else {
print "\nALERT: No task state found in output. Here is what was found:\n";
print_r($state);
print "\n";
$state = array(0 => 'transition', 1 => 'running');
sleep(10);
}
} else {
// Didn't find state in the output for some reason, should still wait.
// just print the output in case.
print "\nALERT: No task state found in output\nConsidering this as still running\nPrinting output\n";
print_r($this->io->stdout);
print "\n";
$state = array(0 => 'transition', 1 => 'running');
sleep(10);
}
}
}
public function code() {
$this->io->run('drush ' . $this->cli->args['source'] . ' ac-code-deploy ' . $this->cli->args['dest_env']);
return $this->wait_for_acquia($this->get_ac_task());
}
public function files() {
$this->io->run('drush ' . $this->cli->args['source'] . ' ac-files-copy ' . $this->cli->args['dest_env']);
return $this->wait_for_acquia($this->get_ac_task());
}
public function database() {
if (!$this->backedup) {
$this->backup();
}
$this->io->run(implode(' ', array('drush', $this->cli->args['source'], 'ac-database-copy', $this->cli->args['dest_db'], $this->cli->args['dest_env'])));
return $this->wait_for_acquia($this->get_ac_task());
}
public function memcache() {
$this->io->run('ssh ' . $this->cli->args['dest_host'] . ' "memflush --server=localhost:11211"');
}
public function varnish() {
$this->io->run('drush ' . $this->cli->args['dest'] . ' ac-domain-purge ' . $this->cli->args['dest_domain']);
$output = $this->io->stdout . $this->io->stderr;
$res = preg_match('/\bid(?:\s)+:(?:\s)+(\w*)/', $output, $id);
if ($res) {
$this->task_id = $id[1];
} else {
print "Error retrieving Acquia Task , aborting\n";
print $output;
exit();
}
return $this->wait_for_acquia($this->task_id);
}
public function drush() {
if ($this->cli->args['drush'] != "semi-colon separated list of commands beginning with drush and dest alias" ) {
$cmds = explode(";", $this->cli->args['drush']);
foreach( $cmds as $cmd ) {
$this->io->run(implode(" ", array("drush", $this->cli->args['dest'], $cmd)));
}
}
}
}
/**
* MAIN
*/
date_default_timezone_set("America/Los_Angeles");
$main = new deploy($help);
$main->processargs($argv);
?>