Passed
Pull Request — master (#53)
by
unknown
01:36
created

AnsiblePlaybook::step()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
/*
3
 * This file is part of the php-ansible package.
4
 *
5
 * (c) Marc Aschmann <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Asm\Ansible\Command;
12
13
use InvalidArgumentException;
14
15
/**
16
 * Class AnsiblePlaybook
17
 *
18
 * @package Asm\Ansible\Command
19
 * @author Marc Aschmann <[email protected]>
20
 */
21
final class AnsiblePlaybook extends AbstractAnsibleCommand implements AnsiblePlaybookInterface
22
{
23
    /**
24
     * @var boolean
25
     */
26
    private $hasInventory = false;
27
28
    /**
29
     * Executes a command process.
30
     * Returns either exitcode or string output if no callback is given.
31
     *
32
     * @param callable|null $callback
33
     * @return integer|string
34
     */
35
    public function execute($callback = null)
36
    {
37
        $this->checkInventory();
38
39
        return $this->runProcess($callback);
40
    }
41
42
    /**
43
     * The play to be executed.
44
     *
45
     * @param string $playbook
46
     * @return AnsiblePlaybookInterface
47
     */
48
    public function play(string $playbook): AnsiblePlaybookInterface
49
    {
50
        $this->addBaseoption($playbook);
51
52
        return $this;
53
    }
54
55
    /**
56
     * Ask for SSH password.
57
     *
58
     * @return AnsiblePlaybookInterface
59
     */
60
    public function askPass(): AnsiblePlaybookInterface
61
    {
62
        $this->addParameter('--ask-pass');
63
64
        return $this;
65
    }
66
67
    /**
68
     * Ask for su password.
69
     *
70
     * @return AnsiblePlaybookInterface
71
     */
72
    public function askSuPass(): AnsiblePlaybookInterface
73
    {
74
        $this->addParameter('--ask-su-pass');
75
76
        return $this;
77
    }
78
79
    /**
80
     * Ask for sudo password.
81
     *
82
     * @return AnsiblePlaybookInterface
83
     */
84
    public function askBecomePass(): AnsiblePlaybookInterface
85
    {
86
        $this->addParameter('--ask-become-pass');
87
88
        return $this;
89
    }
90
91
    /**
92
     * Ask for vault password.
93
     *
94
     * @return AnsiblePlaybookInterface
95
     */
96
    public function askVaultPass(): AnsiblePlaybookInterface
97
    {
98
        $this->addParameter('--ask-vault-pass');
99
100
        return $this;
101
    }
102
103
    /**
104
     * Enable privilege escalation
105
     *
106
     * @return AnsiblePlaybookInterface
107
     * @see http://docs.ansible.com/ansible/become.html
108
     */
109
    public function become(): AnsiblePlaybookInterface
110
    {
111
        $this->addParameter('--become');
112
113
        return $this;
114
    }
115
116
    /**
117
     * Desired sudo user (default=root).
118
     *
119
     * @param string $user
120
     * @return AnsiblePlaybookInterface
121
     */
122
    public function becomeUser(string $user = 'root'): AnsiblePlaybookInterface
123
    {
124
        $this->addOption('--become-user', $user);
125
126
        return $this;
127
    }
128
129
    /**
130
     * Don't make any changes; instead, try to predict some of the changes that may occur.
131
     *
132
     * @return AnsiblePlaybookInterface
133
     */
134
    public function check(): AnsiblePlaybookInterface
135
    {
136
        $this->addParameter('--check');
137
138
        return $this;
139
    }
140
141
    /**
142
     * Connection type to use (default=smart).
143
     *
144
     * @param string $connection
145
     * @return AnsiblePlaybookInterface
146
     */
147
    public function connection(string $connection = 'smart'): AnsiblePlaybookInterface
148
    {
149
        $this->addOption('--connection', $connection);
150
151
        return $this;
152
    }
153
154
    /**
155
     * When changing (small) files and templates, show the
156
     * differences in those files; works great with --check.
157
     *
158
     * @return AnsiblePlaybookInterface
159
     */
160
    public function diff(): AnsiblePlaybookInterface
161
    {
162
        $this->addParameter('--diff');
163
164
        return $this;
165
    }
166
167
    /**
168
     * @inheritDoc
169
     */
170
    public function extraVars($extraVars=''): AnsiblePlaybookInterface
171
    {
172
        if (empty($extraVars))
173
            return $this;
174
175
        // Building the key=>value parameter
176
        if (is_array($extraVars)){
177
            $vars = [];
178
            foreach ($extraVars as $key => $value){
179
                $vars[] = sprintf('%s=%s', $key, $value);
180
            }
181
            $this->addOption('--extra-vars', sprintf('"%s"', implode(' ', $vars)));
182
            return $this;
183
        }
184
185
        // Should we consider $extraVars as a JSON/YML file?
186
        if (@is_file($extraVars)) {
187
            $this->addOption('--extra-vars', sprintf('@"%s"', $extraVars));
188
            return $this;
189
        }
190
191
        // At this point, the only allowed type is string.
192
        if (!is_string($extraVars))
193
            throw new InvalidArgumentException(sprintf('Expected string|array, got "%s"', gettype($extraVars)));
194
195
196
        if (strpos($extraVars, '=') === false) {
197
            throw new InvalidArgumentException('The extra vars raw string should be in the "key=value" form.');
198
        }
199
200
        // Here: we have a plain variable=value string
201
        if (substr($extraVars, 0, 1) !== '"')
202
            $extraVars = '"' . $extraVars;
203
204
        if (substr($extraVars, -1, 1) !== '"')
205
            $extraVars = $extraVars . '"';
206
207
        $this->addOption('--extra-vars', $extraVars);
208
        return $this;
209
    }
210
211
    /**
212
     * Run handlers even if a task fails.
213
     *
214
     * @return AnsiblePlaybookInterface
215
     */
216
    public function forceHandlers(): AnsiblePlaybookInterface
217
    {
218
        $this->addParameter('--force-handlers');
219
220
        return $this;
221
    }
222
223
    /**
224
     * Specify number of parallel processes to use (default=5).
225
     *
226
     * @param int $forks
227
     * @return AnsiblePlaybookInterface
228
     */
229
    public function forks(int $forks = 5): AnsiblePlaybookInterface
230
    {
231
        $this->addOption('--forks', $forks);
232
233
        return $this;
234
    }
235
236
    /**
237
     * Show help message and exit.
238
     *
239
     * @return AnsiblePlaybookInterface
240
     */
241
    public function help(): AnsiblePlaybookInterface
242
    {
243
        $this->addParameter('--help');
244
245
        return $this;
246
    }
247
248
    /**
249
     * Specify inventory host file (default=/etc/ansible/hosts).
250
     *
251
     * @param string $inventory filename for hosts file
252
     * @return AnsiblePlaybookInterface
253
     */
254
    public function inventoryFile(string $inventory = '/etc/ansible/hosts'): AnsiblePlaybookInterface
255
    {
256
        $this->addOption('--inventory-file', $inventory);
257
        $this->hasInventory = true;
258
259
        return $this;
260
    }
261
262
    /**
263
     * @inheritDoc
264
     */
265
    public function inventory(array $hosts = []): AnsiblePlaybookInterface
266
    {
267
        if (empty($hosts))
268
            return $this;
269
270
        // In order to let ansible-playbook understand that the given option is a list of hosts, the list must end by
271
        // comma "," if it contains just an entry. For example, supposing just a single host, "localhosts":
272
        //
273
        //   Wrong: --inventory="locahost"
274
        // Correct: --inventory="locahost,"
275
        $hostList = implode(', ', $hosts);
276
277
        if (count($hosts) === 1)
278
            $hostList .= ',';
279
280
        $this->addOption('--inventory', sprintf('"%s"', $hostList));
281
        $this->hasInventory = true;
282
283
        return $this;
284
    }
285
286
    /**
287
     * Further limit selected hosts to an additional pattern.
288
     *
289
     * @param array|string $subset list of hosts
290
     * @return AnsiblePlaybookInterface
291
     */
292
    public function limit($subset = ''): AnsiblePlaybookInterface
293
    {
294
        $subset = $this->checkParam($subset, ',');
295
296
        $this->addOption('--limit', $subset);
297
298
        return $this;
299
    }
300
301
    /**
302
     * Outputs a list of matching hosts; does not execute anything else.
303
     *
304
     * @return AnsiblePlaybookInterface
305
     */
306
    public function listHosts(): AnsiblePlaybookInterface
307
    {
308
        $this->addParameter('--list-hosts');
309
310
        return $this;
311
    }
312
313
    /**
314
     * List all tasks that would be executed.
315
     *
316
     * @return AnsiblePlaybookInterface
317
     */
318
    public function listTasks(): AnsiblePlaybookInterface
319
    {
320
        $this->addParameter('--list-tasks');
321
322
        return $this;
323
    }
324
325
    /**
326
     * Specify path(s) to module library (default=/usr/share/ansible/).
327
     *
328
     * @param array $path list of paths for modules
329
     * @return AnsiblePlaybookInterface
330
     */
331
    public function modulePath(array $path = ['/usr/share/ansible/']): AnsiblePlaybookInterface
332
    {
333
        $this->addOption('--module-path', implode(',', $path));
334
335
        return $this;
336
    }
337
338
    /**
339
     * Disable cowsay
340
     *
341
     * @codeCoverageIgnore
342
     * @return AnsiblePlaybookInterface
343
     */
344
    public function noCows(): AnsiblePlaybookInterface
345
    {
346
        $this->processBuilder->setEnv('ANSIBLE_NOCOWS', 1);
347
348
        return $this;
349
    }
350
351
    /**
352
     * Enable/Disable Colors
353
     *
354
     * @param bool $colors
355
     * @return AnsiblePlaybookInterface
356
     */
357
    public function colors(bool $colors = true): AnsiblePlaybookInterface
358
    {
359
        $this->processBuilder->setEnv('ANSIBLE_FORCE_COLOR', intval($colors));
360
361
        return $this;
362
    }
363
364
    /**
365
     * Use this file to authenticate the connection.
366
     *
367
     * @param string $file private key file
368
     * @return AnsiblePlaybookInterface
369
     */
370
    public function privateKey(string $file): AnsiblePlaybookInterface
371
    {
372
        $this->addOption('--private-key', $file);
373
374
        return $this;
375
    }
376
377
    /**
378
     * Only run plays and tasks whose tags do not match these values.
379
     *
380
     * @param array|string $tags list of tags to skip
381
     * @return AnsiblePlaybookInterface
382
     */
383
    public function skipTags($tags = ''): AnsiblePlaybookInterface
384
    {
385
        $tags = $this->checkParam($tags, ',');
386
        $this->addOption('--skip-tags', $tags);
387
388
        return $this;
389
    }
390
391
    /**
392
     * Start the playbook at the task matching this name.
393
     *
394
     * @param string $task name of task
395
     * @return AnsiblePlaybookInterface
396
     */
397
    public function startAtTask(string $task): AnsiblePlaybookInterface
398
    {
399
        $this->addOption('--start-at-task', $task);
400
401
        return $this;
402
    }
403
404
    /**
405
     * One-step-at-a-time: confirm each task before running.
406
     *
407
     * @return AnsiblePlaybookInterface
408
     */
409
    public function step(): AnsiblePlaybookInterface
410
    {
411
        $this->addParameter('--step');
412
413
        return $this;
414
    }
415
416
    /**
417
     * Run operations with su.
418
     *
419
     * @return AnsiblePlaybookInterface
420
     */
421
    public function su(): AnsiblePlaybookInterface
422
    {
423
        $this->addParameter('--su');
424
425
        return $this;
426
    }
427
428
    /**
429
     * Run operations with su as this user (default=root).
430
     *
431
     * @param string $user
432
     * @return AnsiblePlaybookInterface
433
     */
434
    public function suUser(string $user = 'root'): AnsiblePlaybookInterface
435
    {
436
        $this->addOption('--su-user', $user);
437
438
        return $this;
439
    }
440
441
    /**
442
     * Perform a syntax check on the playbook, but do not execute it.
443
     *
444
     * @return AnsiblePlaybookInterface
445
     */
446
    public function syntaxCheck(): AnsiblePlaybookInterface
447
    {
448
        $this->addParameter('--syntax-check');
449
450
        return $this;
451
    }
452
453
    /**
454
     * Only run plays and tasks tagged with these values.
455
     *
456
     * @param string|array $tags list of tags
457
     * @return AnsiblePlaybookInterface
458
     */
459
    public function tags($tags): AnsiblePlaybookInterface
460
    {
461
        $tags = $this->checkParam($tags, ',');
462
        $this->addOption('--tags', $tags);
463
464
        return $this;
465
    }
466
467
    /**
468
     * Override the SSH timeout in seconds (default=10).
469
     *
470
     * @param int $timeout
471
     * @return AnsiblePlaybookInterface
472
     */
473
    public function timeout(int $timeout = 10): AnsiblePlaybookInterface
474
    {
475
        $this->addOption('--timeout', $timeout);
476
477
        return $this;
478
    }
479
480
    /**
481
     * Connect as this user.
482
     *
483
     * @param string $user
484
     * @return AnsiblePlaybookInterface
485
     */
486
    public function user(string $user): AnsiblePlaybookInterface
487
    {
488
        $this->addOption('--user', $user);
489
490
        return $this;
491
    }
492
493
    /**
494
     * Vault password file.
495
     *
496
     * @param string $file
497
     * @return AnsiblePlaybookInterface
498
     */
499
    public function vaultPasswordFile(string $file): AnsiblePlaybookInterface
500
    {
501
        $this->addoption('--vault-password-file', $file);
502
503
        return $this;
504
    }
505
506
    /**
507
     * Verbose mode (vvv for more, vvvv to enable connection debugging).
508
     *
509
     * @param string $verbose
510
     * @return AnsiblePlaybookInterface
511
     */
512
    public function verbose(string $verbose = 'v'): AnsiblePlaybookInterface
513
    {
514
        $this->addParameter('-' . $verbose);
515
516
        return $this;
517
    }
518
519
    /**
520
     * Show program's version number and exit.
521
     *
522
     * @return AnsiblePlaybookInterface
523
     */
524
    public function version(): AnsiblePlaybookInterface
525
    {
526
        $this->addParameter('--version');
527
528
        return $this;
529
    }
530
531
    /**
532
     * clear the fact cache
533
     *
534
     * @return AnsiblePlaybookInterface
535
     */
536
    public function flushCache(): AnsiblePlaybookInterface
537
    {
538
         $this->addParameter('--flush-cache');
539
540
         return $this;
541
    }
542
543
    /**
544
     * the new vault identity to use for rekey
545
     *
546
     * @param string $vaultId
547
     * @return AnsiblePlaybookInterface
548
     */
549
    public function newVaultId(string $vaultId): AnsiblePlaybookInterface
550
    {
551
        $this->addOption('--new-vault-id', $vaultId);
552
553
        return $this;
554
    }
555
556
    /**
557
     * new vault password file for rekey
558
     *
559
     * @param string $passwordFile
560
     * @return AnsiblePlaybookInterface
561
     */
562
    public function newVaultPasswordFile(string $passwordFile): AnsiblePlaybookInterface
563
    {
564
        $this->addOption('--new-vault-password-file', $passwordFile);
565
566
        return $this;
567
    }
568
569
    /**
570
     * specify extra arguments to pass to scp only (e.g. -l)
571
     *
572
     * @param string|array $scpExtraArgs
573
     * @return AnsiblePlaybookInterface
574
     */
575
    public function scpExtraArgs($scpExtraArgs): AnsiblePlaybookInterface
576
    {
577
        $scpExtraArgs = $this->checkParam($scpExtraArgs, ',');
578
        $this->addOption('--scp-extra-args', $scpExtraArgs);
579
580
        return $this;
581
    }
582
583
    /**
584
     * specify extra arguments to pass to sftp only (e.g. -f, -l)
585
     *
586
     * @param string|array $sftpExtraArgs
587
     * @return AnsiblePlaybookInterface
588
     */
589
    public function sftpExtraArgs($sftpExtraArgs): AnsiblePlaybookInterface
590
    {
591
        $sftpExtraArgs = $this->checkParam($sftpExtraArgs, ',');
592
        $this->addOption('--sftp-extra-args', $sftpExtraArgs);
593
594
        return $this;
595
    }
596
597
    /**
598
     * specify common arguments to pass to sftp/scp/ssh (e.g. ProxyCommand)
599
     *
600
     * @param string|array $sshArgs
601
     * @return AnsiblePlaybookInterface
602
     */
603
    public function sshCommonArgs($sshArgs): AnsiblePlaybookInterface
604
    {
605
        $sshArgs = $this->checkParam($sshArgs, ',');
606
        $this->addOption('--ssh-common-args', $sshArgs);
607
608
        return $this;
609
    }
610
611
    /**
612
     * specify extra arguments to pass to ssh only (e.g. -R)
613
     *
614
     * @param string|array $extraArgs
615
     * @return AnsiblePlaybookInterface
616
     */
617
    public function sshExtraArgs($extraArgs): AnsiblePlaybookInterface
618
    {
619
        $extraArgs = $this->checkParam($extraArgs, ',');
620
        $this->addOption('--ssh-extra-args', $extraArgs);
621
622
        return $this;
623
    }
624
625
    /**
626
     * the vault identity to use
627
     *
628
     * @param string $vaultId
629
     * @return AnsiblePlaybookInterface
630
     */
631
    public function vaultId(string $vaultId): AnsiblePlaybookInterface
632
    {
633
        $this->addOption('--vault-id', $vaultId);
634
635
        return $this;
636
    }
637
638
    /**
639
     * Get parameter string which will be used to call ansible.
640
     *
641
     * @param bool $asArray
642
     * @return string|array
643
     */
644
    public function getCommandlineArguments(bool $asArray = true)
645
    {
646
        $this->checkInventory();
647
648
        return $this->prepareArguments($asArray);
649
    }
650
651
    /**
652
     * If no inventory file is given, assume
653
     */
654
    private function checkInventory(): void
655
    {
656
        if (!$this->hasInventory) {
657
            $inventory = str_replace('.yml', '', $this->getBaseOptions());
658
            $this->inventoryFile($inventory);
659
        }
660
    }
661
}
662