Passed
Branch master (44cb95)
by Marc
05:51
created

AnsiblePlaybook::limit()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 7
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
     * Use this file to authenticate the connection.
390
     *
391
     * @param string $file private key file
392
     * @return AnsiblePlaybookInterface
393
     */
394
    public function privateKey(string $file): AnsiblePlaybookInterface
395
    {
396
        $this->addOption('--private-key', $file);
397
398
        return $this;
399
    }
400
401
    /**
402
     * Only run plays and tasks whose tags do not match these values.
403
     *
404
     * @param array|string $tags list of tags to skip
405
     * @return AnsiblePlaybookInterface
406
     */
407
    public function skipTags($tags = ''): AnsiblePlaybookInterface
408
    {
409
        $tags = $this->checkParam($tags, ',');
410
        $this->addOption('--skip-tags', $tags);
411
412
        return $this;
413
    }
414
415
    /**
416
     * Start the playbook at the task matching this name.
417
     *
418
     * @param string $task name of task
419
     * @return AnsiblePlaybookInterface
420
     */
421
    public function startAtTask(string $task): AnsiblePlaybookInterface
422
    {
423
        $this->addOption('--start-at-task', $task);
424
425
        return $this;
426
    }
427
428
    /**
429
     * One-step-at-a-time: confirm each task before running.
430
     *
431
     * @return AnsiblePlaybookInterface
432
     */
433
    public function step(): AnsiblePlaybookInterface
434
    {
435
        $this->addParameter('--step');
436
437
        return $this;
438
    }
439
440
    /**
441
     * Run operations with su.
442
     *
443
     * @return AnsiblePlaybookInterface
444
     */
445
    public function su(): AnsiblePlaybookInterface
446
    {
447
        $this->addParameter('--su');
448
449
        return $this;
450
    }
451
452
    /**
453
     * Run operations with su as this user (default=root).
454
     *
455
     * @param string $user
456
     * @return AnsiblePlaybookInterface
457
     */
458
    public function suUser(string $user = 'root'): AnsiblePlaybookInterface
459
    {
460
        $this->addOption('--su-user', $user);
461
462
        return $this;
463
    }
464
465
    /**
466
     * Perform a syntax check on the playbook, but do not execute it.
467
     *
468
     * @return AnsiblePlaybookInterface
469
     */
470
    public function syntaxCheck(): AnsiblePlaybookInterface
471
    {
472
        $this->addParameter('--syntax-check');
473
474
        return $this;
475
    }
476
477
    /**
478
     * Only run plays and tasks tagged with these values.
479
     *
480
     * @param string|array $tags list of tags
481
     * @return AnsiblePlaybookInterface
482
     */
483
    public function tags($tags): AnsiblePlaybookInterface
484
    {
485
        $tags = $this->checkParam($tags, ',');
486
        $this->addOption('--tags', $tags);
487
488
        return $this;
489
    }
490
491
    /**
492
     * Override the SSH timeout in seconds (default=10).
493
     *
494
     * @param int $timeout
495
     * @return AnsiblePlaybookInterface
496
     */
497
    public function timeout(int $timeout = 10): AnsiblePlaybookInterface
498
    {
499
        $this->addOption('--timeout', $timeout);
500
501
        return $this;
502
    }
503
504
    /**
505
     * Connect as this user.
506
     *
507
     * @param string $user
508
     * @return AnsiblePlaybookInterface
509
     */
510
    public function user(string $user): AnsiblePlaybookInterface
511
    {
512
        $this->addOption('--user', $user);
513
514
        return $this;
515
    }
516
517
    /**
518
     * Vault password file.
519
     *
520
     * @param string $file
521
     * @return AnsiblePlaybookInterface
522
     */
523
    public function vaultPasswordFile(string $file): AnsiblePlaybookInterface
524
    {
525
        $this->addoption('--vault-password-file', $file);
526
527
        return $this;
528
    }
529
530
    /**
531
     * Verbose mode (vvv for more, vvvv to enable connection debugging).
532
     *
533
     * @param string $verbose
534
     * @return AnsiblePlaybookInterface
535
     */
536
    public function verbose(string $verbose = 'v'): AnsiblePlaybookInterface
537
    {
538
        $this->addParameter('-' . $verbose);
539
540
        return $this;
541
    }
542
543
    /**
544
     * Show program's version number and exit.
545
     *
546
     * @return AnsiblePlaybookInterface
547
     */
548
    public function version(): AnsiblePlaybookInterface
549
    {
550
        $this->addParameter('--version');
551
552
        return $this;
553
    }
554
555
    /**
556
     * clear the fact cache
557
     *
558
     * @return AnsiblePlaybookInterface
559
     */
560
    public function flushCache(): AnsiblePlaybookInterface
561
    {
562
         $this->addParameter('--flush-cache');
563
564
         return $this;
565
    }
566
567
    /**
568
     * the new vault identity to use for rekey
569
     *
570
     * @param string $vaultId
571
     * @return AnsiblePlaybookInterface
572
     */
573
    public function newVaultId(string $vaultId): AnsiblePlaybookInterface
574
    {
575
        $this->addOption('--new-vault-id', $vaultId);
576
577
        return $this;
578
    }
579
580
    /**
581
     * new vault password file for rekey
582
     *
583
     * @param string $passwordFile
584
     * @return AnsiblePlaybookInterface
585
     */
586
    public function newVaultPasswordFile(string $passwordFile): AnsiblePlaybookInterface
587
    {
588
        $this->addOption('--new-vault-password-file', $passwordFile);
589
590
        return $this;
591
    }
592
593
    /**
594
     * specify extra arguments to pass to scp only (e.g. -l)
595
     *
596
     * @param string|array $scpExtraArgs
597
     * @return AnsiblePlaybookInterface
598
     */
599
    public function scpExtraArgs($scpExtraArgs): AnsiblePlaybookInterface
600
    {
601
        $scpExtraArgs = $this->checkParam($scpExtraArgs, ',');
602
        $this->addOption('--scp-extra-args', $scpExtraArgs);
603
604
        return $this;
605
    }
606
607
    /**
608
     * specify extra arguments to pass to sftp only (e.g. -f, -l)
609
     *
610
     * @param string|array $sftpExtraArgs
611
     * @return AnsiblePlaybookInterface
612
     */
613
    public function sftpExtraArgs($sftpExtraArgs): AnsiblePlaybookInterface
614
    {
615
        $sftpExtraArgs = $this->checkParam($sftpExtraArgs, ',');
616
        $this->addOption('--sftp-extra-args', $sftpExtraArgs);
617
618
        return $this;
619
    }
620
621
    /**
622
     * specify common arguments to pass to sftp/scp/ssh (e.g. ProxyCommand)
623
     *
624
     * @param string|array $sshArgs
625
     * @return AnsiblePlaybookInterface
626
     */
627
    public function sshCommonArgs($sshArgs): AnsiblePlaybookInterface
628
    {
629
        $sshArgs = $this->checkParam($sshArgs, ',');
630
        $this->addOption('--ssh-common-args', $sshArgs);
631
632
        return $this;
633
    }
634
635
    /**
636
     * specify extra arguments to pass to ssh only (e.g. -R)
637
     *
638
     * @param string|array $extraArgs
639
     * @return AnsiblePlaybookInterface
640
     */
641
    public function sshExtraArgs($extraArgs): AnsiblePlaybookInterface
642
    {
643
        $extraArgs = $this->checkParam($extraArgs, ',');
644
        $this->addOption('--ssh-extra-args', $extraArgs);
645
646
        return $this;
647
    }
648
649
    /**
650
     * the vault identity to use
651
     *
652
     * @param string $vaultId
653
     * @return AnsiblePlaybookInterface
654
     */
655
    public function vaultId(string $vaultId): AnsiblePlaybookInterface
656
    {
657
        $this->addOption('--vault-id', $vaultId);
658
659
        return $this;
660
    }
661
662
    /**
663
     * Get parameter string which will be used to call ansible.
664
     *
665
     * @param bool $asArray
666
     * @return string|array
667
     */
668
    public function getCommandlineArguments(bool $asArray = true)
669
    {
670
        $this->checkInventory();
671
672
        return $this->prepareArguments($asArray);
673
    }
674
675
    /**
676
     * @inheritDoc
677
     */
678
    public function rolesPath(string $path): AnsiblePlaybookInterface
679
    {
680
        if (empty($path))
681
            return $this;
682
683
        if (!file_exists($path))
684
            throw new InvalidArgumentException(sprintf('The path "%s" does not exist.', $path));
685
686
        $this->processBuilder->setEnv('ANSIBLE_ROLES_PATH', $path);
687
        return $this;
688
    }
689
690
    /**
691
     * @inheritDoc
692
     */
693
    public function hostKeyChecking(bool $enable = true): AnsiblePlaybookInterface
694
    {
695
        $enable ?
696
            $flag = 'True' :
697
            $flag = 'False';
698
699
        $this->processBuilder->setEnv('ANSIBLE_HOST_KEY_CHECKING', $flag);
700
        return $this;
701
    }
702
703
    /**
704
     * If no inventory file is given, assume
705
     */
706
    private function checkInventory(): void
707
    {
708
        if (!$this->hasInventory) {
709
            $inventory = str_replace('.yml', '', $this->getBaseOptions());
710
            $this->inventoryFile($inventory);
711
        }
712
    }
713
}
714