-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathansible.txt
1376 lines (1220 loc) · 59.6 KB
/
ansible.txt
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
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
## Apropos:
Content is versioned in git. commits, issues and pull-requests welcome!
<https://www.github.com/earizon/DevOps>
## Ansible External Links: [[{]]
- https://docs.ansible.com/ansible/latest/user_guide/index.html
- Ansible in practice[Video]
<https://sysadmincasts.com/episodes/46-configuration-management-with-ansible-part-3-4>
- Playbooks best practices:
<https://docs.ansible.com/ansible/latest/user_guide/playbooks_best_practices.html>
- Ronald Kurr has lot of very-useful and professional Ansible powered code to
provide JVM, Python, Desktops, ... machines. For example:
- Ansible Study Group Labs: https://github.com/kurron/ansible-study-group-labs
- An OpenVPN server in the cloud:
https://github.com/kurron/aws-open-vpn/blob/master/ansible/playbook.yml
- Installation of tools than any self-respecting Operation person loves and needs:
https://github.com/kurron/ansible-role-operations/blob/master/tasks/main.yml
- Installation of tools than any self-respecting JVM developer loves and needs.
https://github.com/kurron/ansible-role-jvm-developer/blob/master/tasks/main.yml
- Installation of tools than any self-respecting AWS command-line user loves and needs.
https://github.com/kurron/ansible-role-aws/blob/master/tasks/main.yml
- Connect to a Juniper VPN under Ubuntu.
https://github.com/kurron/ansible-role-jvpn/blob/master/tasks/main.yml
- Installation of tools than any self-respecting Atlassian user loves and needs.
https://github.com/kurron/ansible-role-atlassian/blob/master/tasks/main.yml
- Installation of tools than any self-respecting cross-platform .NET developer loves and needs.
https://github.com/kurron/ansible-role-dot-net-developer/blob/master/tasks/main.yml
- Docker container that launches a pipeline of Docker containers that
ultimately deploy Docker containes via Ansible into EC2 instances
https://github.com/kurron/docker-ec2-pipeline
- Increase operating system limits for Database workloads.
https://github.com/kurron/ansible-role-os-limits/blob/master/tasks/main.yml
- Creation of an Amazon VPC. Public and private subnets are created
in all availability zones.
https://github.com/kurron/ansible-role-vpc
- Command line tools
<https://docs.ansible.com/ansible/latest/user_guide/command_line_tools.html>
- run a single task 'playbook' against a set of hosts
<https://docs.ansible.com/ansible/latest/cli/ansible.html>
- ansible-config view, edit, and manage ansible configuration
<https://docs.ansible.com/ansible/latest/cli/ansible-config.html>
- ansible-console interactive console for executing ansible tasks
<https://docs.ansible.com/ansible/latest/cli/ansible-console.html>
- manage Ansible roles in shared repostories (default to [https://galaxy.ansible.com] )
<https://docs.ansible.com/ansible/latest/cli/ansible-galaxy.html>
- display/dump configured inventory:
<https://docs.ansible.com/ansible/latest/cli/ansible-inventory.html>
- ansible-pull pulls playbooks from a VCS repo and executes them for the local host:
<https://docs.ansible.com/ansible/latest/cli/ansible-pull.html>
- ansible-vault encryption/decryption utility for Ansible data files:
<https://docs.ansible.com/ansible/latest/cli/ansible-vault.html>
[[}]]
# Ansible Summary: [[{ansible.101]]
View on:
https://earizon.github.io/txt_world_domination/viewer.html?payload=../DevOps/ansible.txt
- ansible-doc: 101,security.secret_management,qa #[ansible_summary]
<https://docs.ansible.com/ansible/latest/cli/ansible-doc.html>
<https://github.com/tldr-pages/tldr/blob/master/pages/common/ansible*>
Display information on modules installed in Ansible libraries.
Display a terse listing of plugins and their short descriptions.
$ ansible-doc --list \ ← List available action plugins (modules):
--type $pluginType (optional) filter by type
$ ansible-doc $plugName \ ← Show information for plugin
$ --type $pluginType (optional) filter by type
$ ansible-doc \ ← Show the playbook snippet for
$ --snippet $plugName action plugin (modules)
$ --json* (optional) dump as JSON
- ansible-playbook:
<https://docs.ansible.com/ansible/latest/cli/ansible-playbook.html>
Execute tasks defined in playbook over SSH.
$ ansible-playbook $playbook \ ← Run tasks in playbook:
-i $inventory_file01 \ ← Optional. def /etc/ansible/hosts → ./hosts
-i $inventory_file02 \ ← Optional.
-e "$var1=val1 $var2=val2" \ ← Optional. Inject env.vars into task execution
-e "@$variables.json" \ ← Optional. Inject env.vars into task execution from json
--tags $tag1,tag2 \ ← Optional. Run tasks in playbook matching tags.
--start-at $task_name \ ← Optional. Run tasks in playbook starting at task.
--ask-vault-pass* ← alt.1. Ask for secrets interatively
(alt.B_1 --vault-password-file*passFile*)
(alt.B_2 export ANSIBLE_VAULT_PASSWORD_FILE=...)
See <#ansible_handling_secrets>
for more info on secret management
- ansible-galaxy: Create and manage Ansible roles.
<https://docs.ansible.com/ansible/latest/cli/ansible-galaxy.html>
$ ansible-galaxy install $username.$role_name ← Install a role
$ ansible-galaxy remove $username.$role_name ← Remove a role
$ ansible-galaxy list ← List installed roles
$ ansible-galaxy search $role_name ← Search for a given role:
$ ansible-galaxy init $role_name ← Create a new role
- ansible : Manage groups of computers (/etc/ansible/hosts) over SSH
$ ansible $group --list-hosts ← List hosts belonging to a group
$ ansible $group -m ping ← Ping host group
$ ansible $group -m setup ← Display facts about host-group
$ ansible $group -m command -a 'command' \ ← Execute a command on host-group
$ --become \ ← (Optional) add admin privileges
$ -i inventory_file ← (Optional) Use custom inventory
- *layout best practices* ║ *Controller* 1 ←→ N ┌─→ *Module*
(Recommended, non─mandatory) ║ │
best practice file layout approach: ║ *Machine * │ (community pre─packaged)
──────────────────────────────────────────────── ║ ^ │ ─ abstracts recurrent system task
production # inventory file ║─ host with │ ─ Provide the real power of Ansible
staging # inventory file ║ installed Ansible │ avoiding custom scripts
║ with modules │ ─ $ ansible─doc "module_name"
group_vars/ # ← assign vars. ║ prepakaged ←─────────┘ ─ Ex:
# to particular groups. ║ and*config.files* user: name=deploy group=web
all.yml # ← Ex: ║ └─┬────────┘ ^ ^ ^
│--- ║ 1) $ANSIBLE_CONFIG module ensure creation of'deploy'
│ntp: ntp.ex1.com ║ 2) ./ansible.cfg name account in 'web' group
│backup: bk.ex1.com ║ 3) ~/.ansible.cfg (executions are idempotent)
║ 4) /etc/ansible/ansible.cfg
webservers.yml # ← Ex: ║ Ex:
│--- ║ [defaults]
│apacheMaxClients: 900 ║ inventory = hosts
│apacheMaxRequestsPerChild: 3000 ║ remote_user = vagrant
║ private_key_file = ~/.ssh/private_key
dbservers.yml # ← Ex: ║ host_key_checking = False
│--- ║─ "host" inventory file
│maxConnectionPool: 100 ║ listing target servers,groups
│... ║
║
host_vars/ ║ Role N ←────→ 1 Playbook 1 ←─────→ N tasks
hostname1.yml # ←assign variables ║ ^ ^ ^
hostname2.yml # to particular systems ║ Mechanism to ─ main yaml defining single proc.
║ share files/... task to be executed to execute
library/ # (opt) custom modules ║ for reuse *2 ─ Created by DevOps team
module_utils/ # (opt) custom module_utils ║<https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html>
# to support modules ║
filter_plugins/ # (opt) filter plugins ║*RUN SEQUENCE*
║ |playbook| 1←→N |Play| 1 → apply to → N |Hosts|
webservers.yml # ← Ex playbook: ║ ↑
│--- # Map ║ 1
│- hosts: webservers # ← webservers─group ║ └─(contains)→ N |Task| 1→1 |Module|
│ # to ║ ┌────────────────────────────────┘
│ roles: # ← roles ║ └→ each task is run in parallel across hosts in order
│ - common # ║ waiting until all hosts have completed the task before
│ - webtier # ║ moving to the next.(default exec.strategy, can be switched to "free")
║ | - name: ....
dbservers.yml # ← Ex playbook for db─tier ║ | hosts: groupTarget01
site.yml #*master playbook* ║ | *serial:* # ← Alt1: serial schedule-tunning.
│--- (whole infra) ║ | * - 1 # ← first in 1 host
│# file: site.yml ║ | * - "10%" # ← if OK, runs 10% simultaneously
│- import_playbook: webservers.yml ║ | * - 30 # ← finally 30 hosts in parallel
│- import_playbook: dbservers.yml ║ | tasks: ...
║ |# *strategy: free* ← Alt2: Don't wait for other hosts
║
*Role layout* ║*|Playbook Play|*
roles/ ║ INPUT
├ webtierRole/ # ← same layout that common ║ |Playbook| → *ansible─playbook* → Gather ────→ exec tasks
│ ... ║ ^ host facts │
├ monitoringRole/ # ← same layout that common ║ exec tasks on (network, v
│ ... ║ the target host** * storage,...) async Handlers
├─common/ # ← Common Role. ║ └────┬────┘ use to:
│ ├─tasks/ # ║ Ussually gathered facts service restart,
│ │ └─ main.yml # ║ are used for ...
│ ├─handlers/ # ║ *Conditional*Include. Ex:
│ │ └─ main.yml # ║ ...
│ ├─templates/ # ║ - *include*: Redhat.yml
│ │ └─ ntp.conf.j2 # ← notice .j2 extension ║ *when*: ansible_os_family == 'Redhat'
│ ├─files/ # ║ Reminder:
│ │ ├─ bar.txt # ← input to copy─resource ║<https://docs.ansible.com/ansible/2.4/playbooks_reuse_includes.html>
│ │ └─ foo.sh # ← input to script─resource ║ "include" ← evaluated @ playbook parsing
│ ├─vars/ # ║ "import" ← evaluated @ playbook execution
│ │ └─ main.yml # ← role related vars ║ "import_playbook"← plays&tasks in each playbook
│ ├─defaults/ # ║ "include_tasks"
│ │ └─ main.yml # ← role related vars ║ "import_tasks"
│ │ ← with lower priority ║
│ ├─meta/ # ║*command module*
│ │ └─ main.yml # ← role dependencies ║─ Ex:
│ ├─library/ # (opt) custom modules ║. $ ansible server01 -m command -a uptime
│ ├─module_utils/ # (opt) custom module_utils ║ ^^^^^^^^^^
│ └─lookup_plugins/# (opt) a given 'lookup_plugins'║ default module. Can be ommited
│ is used ║ testserver │ success │ rc=0 &&
... ║ 17:14:07 up 1:16, 1 user, load average: 0.16, ...
═══════════════════════════════════════════════════╩════════════════════════════════════════════════════════════════
**1:*<https://docs.ansible.com/ansible/latest/cli/ansible-playbook.html>
────────────────────────────────────────────────────────────────────────────────
## playbook-layout
*TASK vs ROLES PLAYBOOK LAYOUT*
──────────────────────────────────────────────────────────┬───────────────────────────────────────────────────────────────────
PLAYBOOK YAML LAYOUT WITH*TASKS* │ PLAYBOOK YAML LAYOUT WITH*ROLES*
──────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────
--- │ *based on a well known file structure*.
- hosts: webservers ← targeted (ssh) servers │ ---
connection: ssh ← :=ssh, localhost,. .. │ - name : my list of Task name
│ hosts: database
vars: ← yaml-file-scoped var.list │ vars_files:
- myYmlVar01 : "myVal01" │ - secrets.yml
│
enviroment: ← runtime-scoped env.var.list │ *# pre_tasks execute before roles *
- myEnvVar01 : "myEnv01" │ *pre_tasks*:
│ - name: update the apt cache
tasks: ← ordered task list to │ apt: update_cache=yes
be executed │
- name: install apache2 ← task1 │ roles:
apt: | │ - role: *databaseRole*
name=apache2 │ # next vars override those in (vars|defaults)/main.yml
update_cache=yes │ database_name: " {{ myProject_ddbb_name }}"
state=lates │ database_user: " {{ myProject_ddbb_user }}"
notify: │ - { role: consumer, when: tag | default('provider') == 'consumer'}
- *restart-apache2-id* │ - { role: provider, when: tag | default('provider') == 'provider'}
- name: next_task_to_exec │
"module": ... │
│ *# post_tasks execute after roles *
handlers: ← tasks triggered by events │ *post_tasks*:
- name: restart-apache2 ← *name as a Unique-ID* │ - name: notify Slack
service: name=apache2 state=restarted │ local_action: >
│ slack
- hosts: localhost │ domain=acme.slack.com
connection: local │ token={{ slack_token }}
gather_facts: False │ msg="database {{ inventory_hostname }} configured"
│
vars: │ ...
... │ ===========================
│ roles search path: ./roles → /etc/ansible/roles
│ role file layout:
│ roles/B*databaseRole*/tasks/main.yml
│ roles/B*databaseRole*/files/
│ roles/B*databaseRole*/templates/
│ roles/B*databaseRole*/handlers/main.yml
│ roles/B*databaseRole*/vars/main.yml # should NO be overrriden
│ roles/B*databaseRole*/defaults/main.yml # can be overrriden
│ roles/B*databaseRole*/meta/main.yml # dependency info about role
──────────────────────────────────────────────────────────┴───────────────────────────────────────────────────────────────────
- hosts: web_servers
tasks:
- shell: /usr/bin/foo
*register*:*foo_result* ← *STDOUT exec ouput to ansible var*
ignore_errors: True Json schema output depends on module
STDOUT to .rc in case.
- shell: /usr/bin/bar Use -v on each module to investigate
when: *foo_result*.rc == 5
## Error Handling [[qa.error_handling]]
- default behavior:
- take a host out of the play if a task fails
and continue with the other hosts.
- *serial*, *max_fail_percentage* can be
used to define a playbook-play as failed.
<https://docs.ansible.com/ansible/2.5/user_guide/playbooks_delegation.html#maximum-failure-percentage>
- Using 'block' (task grouping) inside tasks:
- hosts: app-servers
*max_fail_percentage:*"10%" ← abort if surpassed.
tasks:
- name: Take VM out of the load balancer
- name: Create a VM snapshot before the app upgrade
- block: ← scope error/recovery/rollback
- name: Upgrade the application
- name: Run smoke tests
*rescue:*
- name: Revert a VM to the snapshot after a failed upgrade
*always:*
- name: Re-add webserver to the loadbalancer
- name: Remove a VM snapshot
────────────────────────────────────────────────────────────────────────────────
## inventory file
(defaults to /etc/ansible/hosts)
- if marked as executable (+x) it's executed
and the json-output taken as effective-inventory.
- script must then support '--host=' and '--list=' flags
Ex: hosts inventory file ┌─→ Ex: test("ssh─ping") host in inventory
───────────────────────── │ using 'ping' module:
*development* ←─────────┘ $ ansible -i ./hosts*-m ping* *development*
*production*
[all:vars] <span xsmall>group patterns</span>
ntp_server=ntp.ubuntu.com Other patterns:A
All hosts *all*
[ *production*:vars] All ***
db_primary_host=rhodeisland.example.com Union devO*:*staging
db_replica_host=virginia.example.com Intersection stagingO*:&*database
db_name=widget_production Exclusion devO*:!*queue
rabbitmq_host=pennsylvania.example.com Wildcard ***.example.com
Range webO*[5:10]*
[ *development*:vars] Regex O*~web\d+\.example\.(com|org)*
db_primary_host=quebec.example.com
db_name=widget_staging
rabbitmq_host=quebec.example.com
[ *vagrant*:vars]
db_primary_host=vagrant3
db_name=widget_vagrant
rabbitmq_host=vagrant3
[ *vagrant*]
*vagrant1 ansible_host=127.0.0.1 ansible_port=2222*
*vagrant2 ansible_host=127.0.0.1 ansible_port=2200*
[web_group01]
*georgia.example.com*
*newhampshire.example.com*
*newjersey.example.com*
*vagrant1*
[rabbitmq]
*pennsylvania.example.com*
*vagrant2*
[django:children] ← Group of groups
web_group01
rabbitmq
[web_group02]
web_group01[01:20].example.com ← ranges
web-[a-t].example.com ←
## variable "scopes"
Playbook Variable Main Scopes
-*Global:*set by config, ENV.VARS and cli
-*Play :*each play and contained structures,
vars|vars_files|vars_prompt entries
role defaults
-*Host :*directly associated to a host,
like inventory, include_vars,
facts or registered task outputs
Variable scope Overrinding rules:
- The more explicit you get in scope, the more precedence
1 command line values (eg “-u user”) *(SMALLEST PRECEDENCE)*
2 role defaults
3 *1 inventory file || script group vars
4 *2 inventory group_vars/all
5 *2 playbook group_vars/all
6 *2 inventory group_vars/*
7 *2 playbook group_vars/*
8 *1 inventory file or script host vars
9 *2 inventory host_vars/*
10 *2 playbook host_vars/*
11 *4 host facts || cached set_facts
12 play vars
13 play vars_prompt
14 play vars_files
15 role vars (defined in role/vars/main.yml)
16 block vars (only for tasks in block)
17 task vars (only for the task)
18 include_vars
19 set_facts || registered vars
20 role (and include_role) params
21 include params
22 (-e) extra vars *(BIGEST PRECEDENCE)*
↑
*1 Vars defined in inventory file or dynamic inventory
*2 Includes vars added by ‘vars plugins’ as well as
host_vars and group_vars which are added by the default
vars plugin shipped with Ansible.
*4 When created with set_facts’s cacheable option,
variables will have the high precedence in the play,
but will be the same as a host facts precedence when
they come from the cache.
- Ad-hoc command [[{troubleshooting,ansible.debugging,PM.TODO]]
<https://www.howtoforge.com/ansible-guide-ad-hoc-command/>
- Ad-Hoc allows to perform tasks without creating a playbook
first, such as rebooting servers, managing services, editing the line
configuration, copy a file to only one host, install only one package.
- An Ad-Hoc command will only have two parameters, the group of a host
that you want to perform the task and the Ansible module to run.
[[}]]
# MUST-KNOW MODULES:
## Package management
- module for major package managers (DNF, APT, ...)
- install, upgrade, downgrade, remove, and list packages.
- dnf_module
- yum_module (required for Python 2 compatibility)
- apt_module
- slackpkg_module
- Ex:
|- name: install Apache,MariaDB
| dnf: # ← dnf,yum,
| name:
| - httpd
| - mariadb-server
| state: latest # ← !=latest|present|...
## 'service' module
- start, stop, and reload installed packages;
- Ex:
|- name: Start service foo, based on running process /usr/bin/foo
| service:
| name: foo
| pattern: /usr/bin/foo
| state: started # ← started|restarted|...
| args: arg0value
## 'copy' module
- copies file: local_machine → remote_machine
|- name: Copy a new "ntp.conf file into place,
| copy:
| src: /mine/ntp.conf
| dest: /etc/ntp.conf
| owner: root
| group: root
| mode: '0644' # or u=rw,g=r,o=r
| backup: yes # back-up original if different to new
## 'debug' module (print values to STDOUT/file during execution)
|- name: Display all variables/facts known for a host
| debug:
| var: hostvars[inventory_hostname]
| verbosity: 4
| dest: /tmp/foo.txt # ← By default to STDOUT
| verbosity: 2 # ← optional. Display only with
$ ansible-playbook demo.yaml*-vv*
## 'file' module: manage file and its properties.
- set attributes of files, symlinks, or directories.
- removes files, symlinks, or directories.
- Ex:
|- name: Change file ownership/group/perm
| file:
| path: /etc/foo # ← create if needed
| owner: foo
| group: foo
| mode: '0644'
| state: file ← file*|directory|...
## 'lineinfile' module
- ensures that particular line is in file
- replaces existing line using regex.
- Ex:
|- name: Ensure SELinux is set to enforcing mode
| lineinfile:
| path: /etc/selinux/config
| regexp: '^SELINUX=' # ← (optional) creates if not found.
| line: SELINUX=enforcing # new value, do nothing if found
## 'git' module
- manages git checkouts of repositories to deploy files or software.
- Ex: Create git archive from repo
|- git:
| repo: https://github.com/ansible/ansible-examples.git
| dest: /src/ansible-examples
| archive: /tmp/ansible-examples.zip
## 'cli_config'
- platform-agnostic way of pushing text-based configurations
to network devices
- Ex1:
| - name: commit with comment
| cli_config:
| config: set system host-name foo
| commit_comment: this is a test
- Ex2:
set switch-hostname and exits with a commit message.
|- name: configurable backup path
| cli_config:
| config: "{{ lookup('template', 'basic/config.j2') }}"
| backup: yes
| backup_options:
| filename: backup.cfg
| dir_path: /home/user
## 'archive' module
- create compressed archive of 1+ files.
- Ex:
|- name: Compress directory /path/to/foo/ into /path/to/foo.tgz
| archive:
| path:
| - /path/to/foo
| - /path/wong/foo
| dest: /path/to/foo.tar.bz2
| format: bz2
## Command
- takes the command name followed by a list of space-delimited arguments.
Ex1:
- name: return motd to registered var
command: cat /etc/motd .. ..
become: yes # ← "sudo"
become_user: db_owner # ← effective user
register: mymotd # ← STDOUT to Ansible var mymotd
args: # (optional) command-module args
# (vs executed command arguments)
chdir: somedir/ # ← change to dir
creates: /etc/a/b # ← Execute command if path doesn't exists
# host facts to Play Vars
<https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html>
- UsingO*setup* module at play/run-time. Ex:
tasks:
- ...
- name: re-read facts after adding custom fact
*setup:*filter=ansible_local ← re-run *setup module*
$ ansible targetHost01 -m *setup*
(Output will be similar to)
Next facts are available with:
- hosts: ...
*gather_facts: yes* ← Will execute the module "setup"
{
*"ansible_os_family": "Debian", *
*"ansible_pkg_mgr": "apt", *
*"ansible_architecture": "x86_64",*
b*"ansible_nodename": "ubuntu2.example.com",
"ansible_all_ipv4_addresses": [ "REDACTED IP ADDRESS" ],
"ansible_all_ipv6_addresses": [ "REDACTED IPV6 ADDRESS" ],
"ansible_bios_date": "09/20/2012",
...
"ansible_date_time": {
"date": "2013-10-02",
...
},
*"ansible_default_ipv4": {*
* ... *
*}, *
...
"ansible_devices": {
"sda": {
"partitions": {
...
*"size": "19.00 GB",*
},
...
},
...
},
...
"ansible_env": {
"HOME": "/home/mdehaan",
*"PWD": "/root/ansible",*
*"SHELL": "/bin/bash",*
...
},
*"ansible_fqdn": "ubuntu2.example.com",*
*"ansible_hostname": "ubuntu2",*
...
"ansible_processor_cores": 1,
"ansible_ssh_host_key_dsa_public": ...
...
}
## /etc/ansible/facts.d
(Local provided facts, 1.3+)
Way to provide "locally supplied user values" as opposed to
"centrally supplied user values" or
"locally dynamically determined values"
If any files inside /etc/ansible/facts.d (@remotely managed host)
ending in *.fact (JSON, INI, execs generating JSON, ...) can supply local facts
Ex: /etc/ansible/facts.d/preferences.fact contains:
[general]
asdf=1 ← Will be available as {{ ansible_local.preferences.general.asdf }}
bar=2 (keys are always converted to lowercase)
To copy local facts and make the usable in current play:
- hosts: webservers
tasks:
- name: create directory for ansible custom facts
file: state=directory recurse=yes path=/etc/ansible/facts.d
- name: install custom ipmi fact
copy: src=ipmi.fact dest=/etc/ansible/facts.d ← Copy local facts
- name: re-read facts after adding custom fact
*setup:*filter=ansible_local ← re-run *setup module* to make
← locals facts available in current play
## Lookups: Query ext.data: file sh KeyValDB .. ──────────────────────────────────
<https://docs.ansible.com/ansible/latest/user_guide/playbooks_lookups.html>
...
vars:
motd_value: "{{ *lookup*( *'file'*, '/etc/motd') }}"
^^^^^^ ^^^^
Use lookup One of:
modules - file
- password
- pipe STDOUT of local exec.
- env ENV.VAR.
- template j2 tpl evaluation
- csvfile Entry in .csv file
- dnstxt
- redis_kv Redis key lookup
- etcd etcd key lookup
# "Jinja2" template ex.
nginx.conf.j2
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
listen 443 ssl;
root /usr/share/nginx/html;
index index.html index.htm;
server_name *{{* server_name *}}*;
ssl_certificate *{{* cert_file *}}*;
ssl_certificate_key *{{* key_file *}}*;
location / {
try_files $uri $uri/ =404;
}
}
┌─ templates/000_default.conf.tpl ───
│<VirtualHost *:80>
│ ServerAdmin webmaster@localhost
│ DocumentRoot {{ doc_root }}
│
│ <Directory {{ doc_root }}>
│ AllowOverride All
│ Require all granted
│ </Directory>
│</VirtualHost>
Task:
| - name: Setup default virt.host
| template: src=templates/default.conf.tpl dest=/etc/apache2/sites-available/000-default.conf
*(j2) filters*
*|* must be interpreted as the "pipe" (input) to filter, not the "or" symbol.
# default if undefined:
- ...
"HOST": "{{ database_host *| default('localhost')* }}"
# fail after some debuging
- ...
register: result
*ignore_errors: True*
...
failed_when: resultO*| failed*
...
*failed * True if registered value is a failed task
*changed* True if registered value is a changed task
*success* True if registered value is a succeeded task
*skipped* True if registered value is a skipped task
*path filters*
*basename *
*dirname *
*expanduser* '~' replaced by home dir.
*realpath * resolves sym.links
Ej:
vars:
homepage: /usr/share/nginx/html/index.html
tasks:
- name: copy home page
copy: <
src={{ homepage *| basename* }}
dest={{ homepage }}
*Custom filters*
filter_plugins/surround_by_quotes.py
# From http://stackoverflow.com/a/15515929/742
def surround_by_quote(a_list):
return ['"%s"' % an_element for an_element in a_list]
class FilterModule(object):
def filters(self):
return {'surround_by_quote': surround_by_quote}
# notify vs register [[{doc_has.comparative]]
<https://stackoverflow.com/questions/33931610/ansible-handler-notify-vs-register>
some tasks ... | some tasks ...
*notify:*nginx_restart | *register:*nginx_restart
|
# our handler | # do this after nginx_restart changes
- name: nginx_restart | *when:*nginx_restart|changed
^^^^^^^^^^^^^
- only fired when
tasks report changes
- only visible in playbook ← With register task is displayed as skipped
if actually executed. if 'when' condition is false.
- can be called from any
role.
- (by default) executed at
the end of the playbook.
*This can be dangerous*if playbook
fails midway, handler is NOT
notified. Second run can ignore
the handle since task could have
not changed now. Actually it will
*NOT be idempotent* (unless
--force-handler is set )
- To fire at specific point flush
all handlers by defining a task like:
- meta: flush_handlers
- called only once no matter how many
times it was notified.
[[}]]
#[ansible_handling_secrets]
# ansible-vault Handling secrets [[{security.secret_management]]
En/de-crypts values/data structures/files
<https://github.com/tldr-pages/tldr/blob/master/pages/common/ansible-vault.md>
<https://docs.ansible.com/ansible/latest/user_guide/vault.html#id17>
$*$ ansible-vault create $vault_file * ← Create new encrypted vault file with
a prompt for a password.
$*$ ansible-vault create \ * ← Create new encrypted vault file
$* --vault-password-file=$pass_file \ * using a vault key file to encrypt it
$* $vault_file *
$*$ ansible-vault encrypt \ * ← Encrypt existing file using optional
$* --vault-password-file=$pass_file \ * password file
$* $vault_file *
$*$ ansible-vault encrypt_string * ← Encrypt string using Ansible's encrypted
string format, interactively
$*$ ansible-vault view \ * ← View encrypted file, using pass.file
$* --vault-password-file={{password_file}} \* to decrypt
$* $vault_file *
$*$ ansible-vault rekey \ * ← Re-key already encrypted vault file
$* --vault-password-file=$old_password_file * with new password file
$* --new-vault-password-file=$new_pass_file *
$* $vault_file *
<https://docs.ansible.com/ansible/latest/user_guide/playbooks_vault.html>
- Ansible vaults use symetric-chiper encryption
INPUT ENCRYPTING OUTPUT Ussage
COMMAND (can be added to SCM) (Play.Execution)
────────────── ───────────── ──────────────────── ──────────────────
external pass─┐ ┌→ $ ansible─vault \ (alt1)→ protectedPB.yml ──┬→ $ ansible-playbook protectedPB.yml \ *1
│ │ create protectedPB.yml │ *--ask-vault-pass* ← alt.A
secret needed─┤(alt1) │ *--vault-password-file*passFile* ← alt.B_1
at playbook └──┤ │ ^^^^^^^^
execution │ │ content/exec.STDOUT
│ │ should be a single-line-string
│ │ export ANSIBLE_VAULT_PASSWORD_FILE=... ← alt.B_2
(alt.2) │
│ │
│ │
└→ $ ansible-vault \ (alt2)→ yml to be embeded ──┘
encrypt_string into existing playbook
Ex:
→ mySecretToEncrypt
→ bla bla blah(Ctrl+D)→ !vault ← C&P to a yml file:
→ $ANSIBLE_VAULT;1.1;AES256 - vars:
→ 66386439653236336462... - secret01: !vault |
→ 64316265363035303763... $ANSIBLE_VAULT;1.1;AES256
→ ... 66386439653236336462...
*1: *WARN:* Currently requires all files to be encrypted with same password
[[}]]
## Ex. (yum install) [[{]]
┌ apache@localhost ─────────────────────
│ ---
│ # file: ansible.yml
│ - hosts: localhost
│ connection: local
│ gather_facts: False
│
│ vars:
│ var_yum_prerequisites: [ 'httpd24' , 'vim', 'tmux' ]
│ var_apt_prerequisites: [ 'apache-server', 'vim', 'tmux' ]
│
│ vars_files:
│ - /vars/vars_not_in_git.yml ← add to .gitignore
│ avoid sharing sensitive data
│ /vars/vars_not_in_git.yml will look like:
│ password: !vault |
│ $ANSIBLE_VAULT;1.1;AES256
│ ...
│
│ tasks:
│ - name: install yum pre-requisites
│ when: ansible_os_family == "RedHat"
│ become: true
│ yum:
│ name: {{ var_yum_prerequisites }}
│ state: present
│ notify:
│ - restart-apache2
│
│ - name: install apt pre-requisites
│ when: ansible_os_family == "Debian"
│ become: true
│ apt:
│ name: {{ var_apt_prerequisites }}
│ state: latest
│ notify:
│ - restart-apache2
│
│
│ handlers:
│ - name: restart-apache2
│ service: name=httpd state=restarted
└────────────────────────────────────────── [[}]]
## Ex: Installing nginx [[{]]
┌ web-tls.yml
│ - name: wait in control host for ssh server to be running
│ local_action: wait_for port=22 host="{{ inventory_hostname }}"
│ search_regex=OpenSSH
│
│ - name: Configure nginx
│ *hosts:* webservers
│ become: True
│ *vars:*
│ *key_file*: /etc/nginx/ssl/nginx.key
│ *cert_file*: /etc/nginx/ssl/nginx.crt
│ *conf_file*: /etc/nginx/sites-available/default
│ server_name: localhost
│ *tasks:*
│ - name: install nginx
│ *apt*: *name*=nginx *update_cache*=yes
│
│ - name: create directories for ssl certificates
│ *file*: *path*=/etc/nginx/ssl *state*=directory
│
│ - name: copy TLS key
│ *copy*: *src*=files/nginx.key *dest*={{ *key_file* }} owner=root *mode*=0600
│ *notify*: restart nginx
│
│ - name: copy TLS certificate
│ *copy*: *src*=files/nginx.crt *dest*={{ *cert_file* }}
│ *notify*: restart nginx
│
│ - name: copy config file
│ *copy*: *src*=files/nginx.conf*.j2* *dest*={{ *conf_file* }}
│
│ - name: enable configuration
│ # set attributes of file, symlink or directory
│ *file*: *dest*=/etc/nginx/sites-enabled/default *src*={{ *conf_file* }} state=link
│ - name: copy index.html
│ # template → new file → remote host
│ *template*: *src*=templates/index.html.j2 *dest*=/usr/share/nginx/html/index.html
│ mode=0644
│
│ - name: show a debug message
│ debug: "msg='Example debug message: conf_file {{ *conf_file* }} included!'"
│
│ - name: Example to register new ansible variable
│ command: whoami
│ register: login
│ # (first debug helps to know who to write the second debug)
│ - debug: var=login
│ - debug: msg="Logged in as user {{ login.stdout }}"
│
│ - name: Example to *ignore errors*
│ command: /opt/myprog
│ register: result
│ ignore_errors: *True*
│ - debug: var=result
│
│ *handlers:*
│ - name: restart nginx
│ *service*: *name*=nginx *state*=restarted
└────────────────────────────────────────────────────── [[}]]
## Ex: Insanely complet Ansible playbook [[{]]
<https://gist.github.com/marktheunissen/2979474>
--- <- YAML documents must begin with doc.separator "---"
####
#### descriptive comment at the top of my playbooks.
####
#
# Overview: Playbook to bootstrap a new host for configuration management.
# Applies to: production
# Description:
# Ensures that a host is configured for management with Ansible.
###########
#
# Note:
# *YAML, like Python, cares about whitespace*: *Indent consistently* .
# Be aware! Unlike Python, YAML refuses to allow the tab character for
# indentation, so always use spaces.
#
# Two-space indents feel comfortable to me, but do whatever you like.
# vim:ff=unix ts=2 sw=2 ai expandtab
#
# If you're new to YAML, keep in mind that YAML documents, like XML
# documents, represent a tree-like structure of nodes and text. More
# familiar with JSON? Think of YAML as a strict and more flexible JSON
# with fewer significant characters (e.g., :, "", {}, [])
#
# The curious may read more about YAML at:
# http://www.yaml.org/spec/1.2/spec.html
#
###
# Notice the minus on the line below -- this starts the playbook's record
# in the YAML document. Only one playbook is allowed per YAML file. Indent
# the body of the playbook.
-
hosts: all
###########
# Playbook attribute: hosts
# Required: yes
# Description:
# The name of a host or group of hosts that this playbook should apply to.
#
## Example values:
# hosts: all -- applies to all hosts
# hosts: hostname -- apply ONLY to the host 'hostname'
# hosts: groupname -- apply to all hosts in groupname
# hosts: group1,group2 -- apply to hosts in group1 & group2
# hosts: group1,host1 -- mix and match hosts
# hosts: *.mars.nasa.gov wildcard matches work as expected
#
## Using a variable value for 'hosts'
#
# You can, in fact, set hosts to a variable, for example:
#
# hosts: $groups -- apply to all hosts specified in the variable $groups
#
# This is handy for testing playbooks, running the same playbook against a
# staging environment before running it against production, occasional
# maintenance tasks, and other cases where you want to run the playbook
# against just a few systems rather than a whole group.
#
# If you set hosts as shown above, then you can specify which hosts to
# apply the playbook to on each run as so:
#
# ansible-playbook playbook.yml --extra-vars="groups=staging"
#
# Use --extra-vars to set $groups to any combination of groups, hostnames,
# or wildcards just like the examples in the previous section.
#
sudo: True
###########
# Playbook attribute: sudo
# Default: False
# Required: no
# Description:
# If True, always use sudo to run this playbook, just like passing the
# --sudo (or -s) flag to ansible or ansible-playbook.
user: remoteuser
###########
# Playbook attribute: user
# Default: "root'
# Required: no
# Description
# Remote user to execute the playbook as
###########
# Playbook attribute: vars
# Default: none
# Required: no
# Description:
# Set configuration variables passed to templates & included playbooks
# and handlers. See below for examples.
vars:
color: brown
web:
memcache: 192.168.1.2
httpd: apache
# Tree-like structures work as expected, but be careful to surround
# the variable name with ${} when using.
#
# For this example, ${web.memcache} and ${web.apache} are both usable
# variables.
########
# The following works in Ansible 0.5 and later, and will set $config_path
# "/etc/ntpd.conf" as expected.
#
# In older versions, $config_path will be set to the string "/etc/$config"
#