Passed
Push — master ( 44cb95...9bfea2 )
by Marc
06:37
created

AnsiblePlaybook::askSuPass()   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
     * Example:
169
     * ```php
170
     * $ansible = new Ansible()->extraVars('path=/some/path');
171
     * ```
172
     * Sends extra variables to Ansible. The $extraVars parameter can be one of the following.
173
     *
174
     * ## Array
175
     * If an array is passed, it must contain the [ 'key' => 'value' ] pairs of the variables.
176
     *
177
     * Example:
178
     * ```php
179
     * $ansible = new Ansible()->playbook()->extraVars(['path' => 'some/path']);
180
     * ```
181
     *
182
     * ## File
183
     * As Ansible also supports extra vars loaded from an YML file, you can also pass a file path.
184
     *
185
     * Example:
186
     * ```php
187
     * $ansible = new Ansible()->playbook()->extraVars('/path/to/extra/vars.yml');
188
     * ```
189
     *
190
     * ## String
191
     * You can also pass the raw extra vars string directly.
192
193
     * Example:
194
     * ```php
195
     * $ansible = new Ansible()->playbook()->extraVars('path=/some/path');
196
     * ```
197
     *
198
     * @param string|array $extraVars
199
     * @return AnsiblePlaybookInterface
200
     */
201
    public function extraVars($extraVars = ''): AnsiblePlaybookInterface
202
    {
203
        if (empty($extraVars))
204
            return $this;
205
206
        // Building the key=>value parameter
207
        if (is_array($extraVars)){
208
            $vars = [];
209
            foreach ($extraVars as $key => $value){
210
                $vars[] = sprintf('%s=%s', $key, $value);
211
            }
212
            $this->addOption('--extra-vars', implode(' ', $vars));
213
            return $this;
214
        }
215
216
        // Should we consider $extraVars as a JSON/YML file?
217
        if (@is_file($extraVars)) {
218
            $this->addOption('--extra-vars', sprintf('@"%s"', $extraVars));
219
            return $this;
220
        }
221
222
        // At this point, the only allowed type is string.
223
        if (!is_string($extraVars))
0 ignored issues
show
introduced by
The condition is_string($extraVars) is always true.
Loading history...
224
            throw new InvalidArgumentException(sprintf('Expected string|array, got "%s"', gettype($extraVars)));
225
226
227
        if (strpos($extraVars, '=') === false) {
228
            throw new InvalidArgumentException('The extra vars raw string should be in the "key=value" form.');
229
        }
230
231
        $this->addOption('--extra-vars', $extraVars);
232
        return $this;
233
    }
234
235
    /**
236
     * Run handlers even if a task fails.
237
     *
238
     * @return AnsiblePlaybookInterface
239
     */
240
    public function forceHandlers(): AnsiblePlaybookInterface
241
    {
242
        $this->addParameter('--force-handlers');
243
244
        return $this;
245
    }
246
247
    /**
248
     * Specify number of parallel processes to use (default=5).
249
     *
250
     * @param int $forks
251
     * @return AnsiblePlaybookInterface
252
     */
253
    public function forks(int $forks = 5): AnsiblePlaybookInterface
254
    {
255
        $this->addOption('--forks', $forks);
256
257
        return $this;
258
    }
259
260
    /**
261
     * Show help message and exit.
262
     *
263
     * @return AnsiblePlaybookInterface
264
     */
265
    public function help(): AnsiblePlaybookInterface
266
    {
267
        $this->addParameter('--help');
268
269
        return $this;
270
    }
271
272
    /**
273
     * @inheritDoc
274
     */
275
    public function inventory(array $hosts = []): AnsiblePlaybookInterface
276
    {
277
        if (empty($hosts))
278
            return $this;
279
280
        // In order to let ansible-playbook understand that the given option is a list of hosts, the list must end by
281
        // comma "," if it contains just an entry. For example, supposing just a single host, "localhosts":
282
        //
283
        //   Wrong: --inventory="locahost"
284
        // Correct: --inventory="locahost,"
285
        $hostList = implode(', ', $hosts);
286
287
        if (count($hosts) === 1)
288
            $hostList .= ',';
289
290
        $this->addOption('--inventory', sprintf('"%s"', $hostList));
291
        $this->hasInventory = true;
292
293
        return $this;
294
    }
295
296
    /**
297
     * Specify inventory host file (default=/etc/ansible/hosts).
298
     *
299
     * @param string $inventory filename for hosts file
300
     * @return AnsiblePlaybookInterface
301
     */
302
    public function inventoryFile(string $inventory = '/etc/ansible/hosts'): AnsiblePlaybookInterface
303
    {
304
        $this->addOption('--inventory-file', $inventory);
305
        $this->hasInventory = true;
306
307
        return $this;
308
    }
309
310
    /**
311
     * Further limit selected hosts to an additional pattern.
312
     *
313
     * @param array|string $subset list of hosts
314
     * @return AnsiblePlaybookInterface
315
     */
316
    public function limit($subset = ''): AnsiblePlaybookInterface
317
    {
318
        $subset = $this->checkParam($subset, ',');
319
320
        $this->addOption('--limit', $subset);
321
322
        return $this;
323
    }
324
325
    /**
326
     * Outputs a list of matching hosts; does not execute anything else.
327
     *
328
     * @return AnsiblePlaybookInterface
329
     */
330
    public function listHosts(): AnsiblePlaybookInterface
331
    {
332
        $this->addParameter('--list-hosts');
333
334
        return $this;
335
    }
336
337
    /**
338
     * List all tasks that would be executed.
339
     *
340
     * @return AnsiblePlaybookInterface
341
     */
342
    public function listTasks(): AnsiblePlaybookInterface
343
    {
344
        $this->addParameter('--list-tasks');
345
346
        return $this;
347
    }
348
349
    /**
350
     * Specify path(s) to module library (default=/usr/share/ansible/).
351
     *
352
     * @param array $path list of paths for modules
353
     * @return AnsiblePlaybookInterface
354
     */
355
    public function modulePath(array $path = ['/usr/share/ansible/']): AnsiblePlaybookInterface
356
    {
357
        $this->addOption('--module-path', implode(',', $path));
358
359
        return $this;
360
    }
361
362
    /**
363
     * Disable cowsay
364
     *
365
     * @codeCoverageIgnore
366
     * @return AnsiblePlaybookInterface
367
     */
368
    public function noCows(): AnsiblePlaybookInterface
369
    {
370
        $this->processBuilder->setEnv('ANSIBLE_NOCOWS', 1);
371
372
        return $this;
373
    }
374
375
    /**
376
     * Enable/Disable Colors
377
     *
378
     * @param bool $colors
379
     * @return AnsiblePlaybookInterface
380
     */
381
    public function colors(bool $colors = true): AnsiblePlaybookInterface
382
    {
383
        $this->processBuilder->setEnv('ANSIBLE_FORCE_COLOR', intval($colors));
384
385
        return $this;
386
    }
387
388
    /**
389
     * Enable/Disable Json Output
390
     *
391
     * @return AnsiblePlaybookInterface
392
     */
393
    public function json(): AnsiblePlaybookInterface
394
    {
395
        $this->processBuilder->setEnv('ANSIBLE_STDOUT_CALLBACK','json');
396
397
        return $this;
398
    }
399
400
    /**
401
     * Use this file to authenticate the connection.
402
     *
403
     * @param string $file private key file
404
     * @return AnsiblePlaybookInterface
405
     */
406
    public function privateKey(string $file): AnsiblePlaybookInterface
407
    {
408
        $this->addOption('--private-key', $file);
409
410
        return $this;
411
    }
412
413
    /**
414
     * Only run plays and tasks whose tags do not match these values.
415
     *
416
     * @param array|string $tags list of tags to skip
417
     * @return AnsiblePlaybookInterface
418
     */
419
    public function skipTags($tags = ''): AnsiblePlaybookInterface
420
    {
421
        $tags = $this->checkParam($tags, ',');
422
        $this->addOption('--skip-tags', $tags);
423
424
        return $this;
425
    }
426
427
    /**
428
     * Start the playbook at the task matching this name.
429
     *
430
     * @param string $task name of task
431
     * @return AnsiblePlaybookInterface
432
     */
433
    public function startAtTask(string $task): AnsiblePlaybookInterface
434
    {
435
        $this->addOption('--start-at-task', $task);
436
437
        return $this;
438
    }
439
440
    /**
441
     * One-step-at-a-time: confirm each task before running.
442
     *
443
     * @return AnsiblePlaybookInterface
444
     */
445
    public function step(): AnsiblePlaybookInterface
446
    {
447
        $this->addParameter('--step');
448
449
        return $this;
450
    }
451
452
    /**
453
     * Run operations with su.
454
     *
455
     * @return AnsiblePlaybookInterface
456
     */
457
    public function su(): AnsiblePlaybookInterface
458
    {
459
        $this->addParameter('--su');
460
461
        return $this;
462
    }
463
464
    /**
465
     * Run operations with su as this user (default=root).
466
     *
467
     * @param string $user
468
     * @return AnsiblePlaybookInterface
469
     */
470
    public function suUser(string $user = 'root'): AnsiblePlaybookInterface
471
    {
472
        $this->addOption('--su-user', $user);
473
474
        return $this;
475
    }
476
477
    /**
478
     * Perform a syntax check on the playbook, but do not execute it.
479
     *
480
     * @return AnsiblePlaybookInterface
481
     */
482
    public function syntaxCheck(): AnsiblePlaybookInterface
483
    {
484
        $this->addParameter('--syntax-check');
485
486
        return $this;
487
    }
488
489
    /**
490
     * Only run plays and tasks tagged with these values.
491
     *
492
     * @param string|array $tags list of tags
493
     * @return AnsiblePlaybookInterface
494
     */
495
    public function tags($tags): AnsiblePlaybookInterface
496
    {
497
        $tags = $this->checkParam($tags, ',');
498
        $this->addOption('--tags', $tags);
499
500
        return $this;
501
    }
502
503
    /**
504
     * Override the SSH timeout in seconds (default=10).
505
     *
506
     * @param int $timeout
507
     * @return AnsiblePlaybookInterface
508
     */
509
    public function timeout(int $timeout = 10): AnsiblePlaybookInterface
510
    {
511
        $this->addOption('--timeout', $timeout);
512
513
        return $this;
514
    }
515
516
    /**
517
     * Connect as this user.
518
     *
519
     * @param string $user
520
     * @return AnsiblePlaybookInterface
521
     */
522
    public function user(string $user): AnsiblePlaybookInterface
523
    {
524
        $this->addOption('--user', $user);
525
526
        return $this;
527
    }
528
529
    /**
530
     * Vault password file.
531
     *
532
     * @param string $file
533
     * @return AnsiblePlaybookInterface
534
     */
535
    public function vaultPasswordFile(string $file): AnsiblePlaybookInterface
536
    {
537
        $this->addoption('--vault-password-file', $file);
538
539
        return $this;
540
    }
541
542
    /**
543
     * Verbose mode (vvv for more, vvvv to enable connection debugging).
544
     *
545
     * @param string $verbose
546
     * @return AnsiblePlaybookInterface
547
     */
548
    public function verbose(string $verbose = 'v'): AnsiblePlaybookInterface
549
    {
550
        $this->addParameter('-' . $verbose);
551
552
        return $this;
553
    }
554
555
    /**
556
     * Show program's version number and exit.
557
     *
558
     * @return AnsiblePlaybookInterface
559
     */
560
    public function version(): AnsiblePlaybookInterface
561
    {
562
        $this->addParameter('--version');
563
564
        return $this;
565
    }
566
567
    /**
568
     * clear the fact cache
569
     *
570
     * @return AnsiblePlaybookInterface
571
     */
572
    public function flushCache(): AnsiblePlaybookInterface
573
    {
574
         $this->addParameter('--flush-cache');
575
576
         return $this;
577
    }
578
579
    /**
580
     * the new vault identity to use for rekey
581
     *
582
     * @param string $vaultId
583
     * @return AnsiblePlaybookInterface
584
     */
585
    public function newVaultId(string $vaultId): AnsiblePlaybookInterface
586
    {
587
        $this->addOption('--new-vault-id', $vaultId);
588
589
        return $this;
590
    }
591
592
    /**
593
     * new vault password file for rekey
594
     *
595
     * @param string $passwordFile
596
     * @return AnsiblePlaybookInterface
597
     */
598
    public function newVaultPasswordFile(string $passwordFile): AnsiblePlaybookInterface
599
    {
600
        $this->addOption('--new-vault-password-file', $passwordFile);
601
602
        return $this;
603
    }
604
605
    /**
606
     * specify extra arguments to pass to scp only (e.g. -l)
607
     *
608
     * @param string|array $scpExtraArgs
609
     * @return AnsiblePlaybookInterface
610
     */
611
    public function scpExtraArgs($scpExtraArgs): AnsiblePlaybookInterface
612
    {
613
        $scpExtraArgs = $this->checkParam($scpExtraArgs, ',');
614
        $this->addOption('--scp-extra-args', $scpExtraArgs);
615
616
        return $this;
617
    }
618
619
    /**
620
     * specify extra arguments to pass to sftp only (e.g. -f, -l)
621
     *
622
     * @param string|array $sftpExtraArgs
623
     * @return AnsiblePlaybookInterface
624
     */
625
    public function sftpExtraArgs($sftpExtraArgs): AnsiblePlaybookInterface
626
    {
627
        $sftpExtraArgs = $this->checkParam($sftpExtraArgs, ',');
628
        $this->addOption('--sftp-extra-args', $sftpExtraArgs);
629
630
        return $this;
631
    }
632
633
    /**
634
     * specify common arguments to pass to sftp/scp/ssh (e.g. ProxyCommand)
635
     *
636
     * @param string|array $sshArgs
637
     * @return AnsiblePlaybookInterface
638
     */
639
    public function sshCommonArgs($sshArgs): AnsiblePlaybookInterface
640
    {
641
        $sshArgs = $this->checkParam($sshArgs, ',');
642
        $this->addOption('--ssh-common-args', $sshArgs);
643
644
        return $this;
645
    }
646
647
    /**
648
     * specify extra arguments to pass to ssh only (e.g. -R)
649
     *
650
     * @param string|array $extraArgs
651
     * @return AnsiblePlaybookInterface
652
     */
653
    public function sshExtraArgs($extraArgs): AnsiblePlaybookInterface
654
    {
655
        $extraArgs = $this->checkParam($extraArgs, ',');
656
        $this->addOption('--ssh-extra-args', $extraArgs);
657
658
        return $this;
659
    }
660
661
    /**
662
     * the vault identity to use
663
     *
664
     * @param string $vaultId
665
     * @return AnsiblePlaybookInterface
666
     */
667
    public function vaultId(string $vaultId): AnsiblePlaybookInterface
668
    {
669
        $this->addOption('--vault-id', $vaultId);
670
671
        return $this;
672
    }
673
674
    /**
675
     * Get parameter string which will be used to call ansible.
676
     *
677
     * @param bool $asArray
678
     * @return string|array
679
     */
680
    public function getCommandlineArguments(bool $asArray = true)
681
    {
682
        $this->checkInventory();
683
684
        return $this->prepareArguments($asArray);
685
    }
686
687
    /**
688
     * @inheritDoc
689
     */
690
    public function rolesPath(string $path): AnsiblePlaybookInterface
691
    {
692
        if (empty($path))
693
            return $this;
694
695
        if (!file_exists($path))
696
            throw new InvalidArgumentException(sprintf('The path "%s" does not exist.', $path));
697
698
        $this->processBuilder->setEnv('ANSIBLE_ROLES_PATH', $path);
699
        return $this;
700
    }
701
702
    /**
703
     * @inheritDoc
704
     */
705
    public function hostKeyChecking(bool $enable = true): AnsiblePlaybookInterface
706
    {
707
        $enable ?
708
            $flag = 'True' :
709
            $flag = 'False';
710
711
        $this->processBuilder->setEnv('ANSIBLE_HOST_KEY_CHECKING', $flag);
712
        return $this;
713
    }
714
715
    /**
716
     * If no inventory file is given, assume
717
     */
718
    private function checkInventory(): void
719
    {
720
        if (!$this->hasInventory) {
721
            $inventory = str_replace('.yml', '', $this->getBaseOptions());
722
            $this->inventoryFile($inventory);
723
        }
724
    }
725
}
726