-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAnsibleLabNOTES
More file actions
1014 lines (603 loc) · 34 KB
/
Copy pathAnsibleLabNOTES
File metadata and controls
1014 lines (603 loc) · 34 KB
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
The Ansible Inventory File
The Ansible Inventory File defines all the hosts and groups of hosts that you want to automate with Ansible. Also called the Ansible Hosts File it tells Ansible about the hosts that it can connect to, you can also define custom options per host e.g. different port number or credentials
The default Ansible inventory file is located in /etc/ansible/hosts. You can also create project-specific inventory files in alternate locations.
The inventory file can list individual hosts or user-defined groups of hosts.
For Ansible to automate a Linux Server, Network device or Cloud server it has to exist within the inventory file (also known as the Ansible hosts file) and saved in either YAML or INI format.
The file can also be static or created dynamically by a script.
The default inventory file is named hosts by default and is one of the default files installed with Ansible – the other main one being ansible.cfg. If you cat the file you can see it does not contain any entries (they are all commented out) but what it does do is give you a template of how to start formatting your inventory file.
Ansible Inventory Example
The Ansible hosts file is written in either YAML or INI format. The most common format is INI. Check the ansible/hosts file examples below.
Devices or hosts or nodes are referenced by their DNS name, hostname or with the ansible inventory ip address variable.
host1.domain.com
192.168.1.193
[routers]
router1.domain.com
router2.domain.com
CSR-1 ansible_host=192.168.1.199
[switches]
switch1.domain.com
switch2.domain.com
Hosts can be defined either by IP address or DNS name or if DNS is not resolvable using the ansible_host command syntax.
In the example above the display name is CSR-1 and the ansible host command specifies the IP address as 192.168.1.199
Hosts can also grouped together by putting under groups named by a name in square brackets e.g. [Routers]
[database servers]
[webservers group]
The file can live anywhere but it’s a best practice to put it in the same directory as your project files.
Ansible Inventory YAML
The hosts file above is written in the default INI format, an Ansible YAML Inventory is show below
ansible inventory file as yaml
Ansible Inventory file Example YAML syntax
In the above example we have the same inventory file but in a YAML format.
Best Practices
Keep your hosts file names simple – I always use hosts
Comment were required to ensure someone else can understand your inventory
Use children to address multiple groups at once
Do no put passwords in your inventory file – reference them in group_vars or host_vars or even better use Ansible vault within those files.
Ansible Hosts File Comments
If you want to put a comment next to any item in your Ansible Hosts file just start a new line with a #
How do I know if my host is reachable in Ansible?
You can use the Ansible ping module to check successful ssh connectivity to target devices – use the command ansible all -m ping -v
Ansible-Playbook Command
ansible-playbook is a command-line tool used to run Ansible Playbooks. A playbook is a collection of instructions in YAML format that define a set of tasks to be executed by Ansible on a group of targeted hosts or machines.
The ansible-playbook command is used to execute a playbook, and it takes the path to the playbook file as an argument. It connects to the targeted hosts specified in the playbook, and runs the tasks defined in the playbook on those hosts.
The basic syntax of the ansible-playbook command is:
ansible-playbook [options] playbook.yml
For example, to run a playbook called playbook.yml, the command would be:
ansible-playbook playbook.yml
Some of the options that can be used with the ansible-playbook command include:
-i or –inventory to specify a custom inventory file
-l or –limit to limit the execution to a specific subset of hosts
-v or –verbose to increase the output verbosity
-e or –extra-vars to pass extra variables to the playbook
-t or –tags to run specific tasks or groups of tasks
–check to check the playbook without making any changes
It’s important to note that the ansible-playbook command must be run on the control machine and it will communicate with the target host over SSH, unless you have configured a different connection method.
Ansible Playbook Elements
Plays – A play is a top level specification of a group of tasks
Tasks – A Task defines which module to use to perform a certain task
Modules – Ansible modules are reusable, standalone scripts that can be used by the Ansible API, or by the ansible or ansible-playbook programs. They return information to ansible by printing a JSON string to stdout before exiting. They take arguments in one of several ways which we’ll go into as we work through this tutorial.
Plugins – Technically Modules are plugins, but a plugin is a piece of code that augment Ansible’s core functionality
Inventory – The Ansible Inventory is a file that contains a list of all the hosts you want to automate. They can put into groups i.e [DB-Servers]
Roles – Roles are re-useable playbooks that you can call on to perform similar tasks
The control machine does not have to be anything special, it can even run on your laptop, it only requires SSH connectivity to the target device. You install Ansible and setup a few configuration files and you are ready to automate!
The basic concepts are:
You define a list of managed nodes in the hosts file
Ansible code is written in a playbook file to describe what tasks to perform on those hosts
You run the playbook
Ansible executes the tasks in order and provides an output of success or fail of the tasks
The first thing you can do with Ansible is to check you have connectivity to your devices. We can issue a ping command that will make sure the inventory is configured correctly and we can ssh to the ip address of each device.
To use the ping module use the following command.
$ ansible -i hosts all -m ping
Ansible Documention
For all the latest Ansible documentation always reference
https://docs.ansible.com/
Ansible Tower / AAP
This was the GUI front end to Ansible Engine that enables you to delegate tasks to users and it also provides logging, this has now been replaced with Ansible Automation Platform which is actually a suite of tools which allows you to automate your entire infrastructure with ease.
I created 3 ansible hosts in an ansible lab environment - using 3 virtual ubuntu machines on virt-manager (KVM) on asus laptop.
Asus laptop is the control host
ubuntu101
ubuntu102
ubuntu103
which are
192.168.122.101
192.168.122.102
192.168.122.103
then created an ansible hosts file on asus under /etc/ansible/hosts
root@asus:/etc/ansible# ansible all --list-hosts
hosts (3):
192.168.122.101
192.168.122.102
192.168.122.103
root@asus:/etc/ansible#
next Set up SSH connections so Ansible can connect to the managed nodes.
Add your public SSH key to the authorized_keys file on each remote system.
I am using root in this case, so we copy paste the id_rsa.pub from asus /root/.ssh/id_rsa.pub to each machine into /root/.ssh/authorized_keys
then we can login without password for root:
root@asus:~/.ssh# ssh root@ubuntu101
do this on all 3 machines - done.
next, Ping the managed nodes.
ansible all -m ping
root@asus:~/.ssh# ansible all -m ping
192.168.122.103 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
192.168.122.102 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
192.168.122.101 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
root@asus:~/.ssh#
NOTE: you must first ssh login using the IP address and not the hostname, otherwise this test will fail!!
eg
192.168.122.102 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: Host key verification failed.",
"unreachable": true
}
so make sure you first do a
ssh root@192.168.122.102 instead of root@ubuntu102
Next create an inventory file on the control host:
under /home/kevin/LOCAL/WORK/AnsibleLab (so it gets synced to my GitHab repo)
virtualmachines:
hosts:
ubuntu101:
ansible_host: 192.168.122.101
ubuntu102:
ansible_host: 192.168.122.102
ubuntu103:
ansible_host: 192.168.122.103
next,
Verify your inventory. If you created your inventory in a directory other than your home directory, specify the full path with the -i option.
ansible-inventory -i inventory.yaml --list
kevin@asus:~/LOCAL/WORK/AnsibleLab$ ansible-inventory -i inventory.yaml --list
{
"_meta": {
"hostvars": {
"ubuntu101": {
"ansible_host": "192.168.122.101"
},
"ubuntu102": {
"ansible_host": "192.168.122.102"
},
"ubuntu103": {
"ansible_host": "192.168.122.103"
}
}
},
"all": {
"children": [
"ungrouped",
"virtualmachines"
]
},
"virtualmachines": {
"hosts": [
"ubuntu101",
"ubuntu102",
"ubuntu103"
]
}
}
kevin@asus:~/LOCAL/WORK/AnsibleLab$
then ping the managed nodes in your inventory.
In this example, the group name is virtualmachines which you can specify with the ansible command instead of all.
ansible virtualmachines -m ping -i inventory.yaml
kevin@asus:~/LOCAL/WORK/AnsibleLab$ ansible virtualmachines -m ping -i inventory.yaml
The authenticity of host '192.168.122.102 (192.168.122.102)' can't be established.
ED25519 key fingerprint is SHA256:vK5DgpWSrkMChzW18QCfI3NqhI0VzZcL/4+xI7pZTI0.
This host key is known by the following other names/addresses:
~/.ssh/known_hosts:35: ubuntu1
~/.ssh/known_hosts:38: ubuntu-base
~/.ssh/known_hosts:39: 192.168.122.101
~/.ssh/known_hosts:40: 192.168.122.100
~/.ssh/known_hosts:41: ubuntu102
~/.ssh/known_hosts:42: ubuntu103
~/.ssh/known_hosts:43: ubuntu101
The authenticity of host '192.168.122.103 (192.168.122.103)' can't be established.
ED25519 key fingerprint is SHA256:vK5DgpWSrkMChzW18QCfI3NqhI0VzZcL/4+xI7pZTI0.
This host key is known by the following other names/addresses:
~/.ssh/known_hosts:35: ubuntu1
~/.ssh/known_hosts:38: ubuntu-base
~/.ssh/known_hosts:39: 192.168.122.101
~/.ssh/known_hosts:40: 192.168.122.100
~/.ssh/known_hosts:41: ubuntu102
~/.ssh/known_hosts:42: ubuntu103
~/.ssh/known_hosts:43: ubuntu101
Are you sure you want to continue connecting (yes/no/[fingerprint])? ubuntu101 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: kevin@192.168.122.101: Permission denied (publickey,password,keyboard-interactive).",
"unreachable": true
}
ubuntu102 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: Host key verification failed.",
"unreachable": true
}
ubuntu103 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: Host key verification failed.",
"unreachable": true
}
kevin@asus:~/LOCAL/WORK/AnsibleLab$
REASON FOR THE ABOVE ERRORS:
I had switched out of root and back to user kevin for ssh ... and this means my ssh keys arent corresponding to what is on the virtual machines on my lab.
#
below is how the output looks as root user:
root@asus:/home/kevin/LOCAL/WORK/AnsibleLab# ansible virtualmachines -m ping -i inventory.yaml
ubuntu102 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
ubuntu101 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
ubuntu103 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
root@asus:/home/kevin/LOCAL/WORK/AnsibleLab#
Congratulations! You have successfully built an inventory.
Tips for building inventories
Ensure that group names are meaningful and unique. Group names are also case sensitive.
Avoid spaces, hyphens, and preceding numbers (use floor_19, not 19th_floor) in group names.
Group hosts in your inventory logically according to their What, Where, and When.
What
Group hosts according to the topology, for example: db, web, leaf, spine.
Where
Group hosts by geographic location, for example: datacenter, region, floor, building.
When
Group hosts by stage, for example: development, test, staging, production.
TIP:
Use metagroups
Create a metagroup that organizes multiple groups in your inventory with the following syntax:
metagroupname:
children:
also, Create variables
Variables set values for managed nodes, such as the IP address, FQDN, operating system, and SSH user, so you do not need to pass them when running Ansible commands.
Variables can apply to specific hosts.
webservers:
hosts:
webserver01:
ansible_host: 192.0.2.140
http_port: 80
webserver02:
ansible_host: 192.0.2.150
http_port: 443
Variables can also apply to all hosts in a group.
webservers:
hosts:
webserver01:
ansible_host: 192.0.2.140
http_port: 80
webserver02:
ansible_host: 192.0.2.150
http_port: 443
vars:
ansible_user: my_server_user
kevin@asus:~/DATAVOLUME/ANSIBLECODE$ ansible-inventory -i inventory --list
{
"_meta": {
"hostvars": {
"asusvpn": {
"ansible_host": "10.147.18.14"
},
"kevinvm1vpn": {
"ansible_host": "10.147.18.72"
},
"lenvpn": {
"ansible_host": "10.147.18.1"
}
}
},
"all": {
"children": [
"ungrouped",
"vpnhosts"
]
},
"laptops": {
"hosts": [
"asusvpn",
"lenvpn"
]
},
"vpnhosts": {
"children": [
"laptops",
"webservers"
],
"hosts": [
"asusvpn",
"kevinvm1vpn",
"lenvpn"
]
},
"webservers": {
"hosts": [
"kevinvm1vpn"
]
}
note the file here is just called inventory - not inventory.yaml or inventory.yml
To run Ansible commands using a custom inventory file, use the -i option:
ansible all -i inventory -m ping
This example runs the ping module on all hosts listed in the inventory file.
This is also how you execute Ansible playbooks with a custom inventory file:
ansible-playbook -i inventory playbook.yml
kevin@asus:~/DATAVOLUME/ANSIBLECODE$ ansible-playbook -i inventory playbook.yml
PLAY [all] ****************************************************************************************************************************
TASK [Gathering Facts] ****************************************************************************************************************
[DEPRECATION WARNING]: Distribution ubuntu 22.04 on host asusvpn should use /usr/bin/python3, but is using /usr/bin/python for
backward compatibility with prior Ansible releases. A future Ansible release will default to using the discovered platform python for
this host. See https://docs.ansible.com/ansible/2.10/reference_appendices/interpreter_discovery.html for more information. This
feature will be removed in version 2.12. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
ok: [asusvpn]
fatal: [lenvpn]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: ssh: connect to host 10.147.18.1 port 22: No route to host", "unreachable": true}
ok: [kevinvm1vpn]
TASK [Print message] ******************************************************************************************************************
ok: [asusvpn] => {
"msg": "Hello Ansible World"
}
ok: [kevinvm1vpn] => {
"msg": "Hello Ansible World"
}
PLAY RECAP ****************************************************************************************************************************
asusvpn : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
kevinvm1vpn : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
lenvpn : ok=0 changed=0 unreachable=1 failed=0 skipped=0 rescued=0 ignored=0
kevin@asus:~/DATAVOLUME/ANSIBLECODE$
the fatal error for lenvpn (UNREACHABLE) is expected as the nachine lenvpn is currently switched off.
the other two machines are live and online.
kevin@asus:~/DATAVOLUME/ANSIBLECODE/lamp$ ansible-playbook -i inventory playbook.lamp.yml --ask-become-pass
BECOME password:
PLAY [my lamp playbook] ***************************************************************************************************************
TASK [Gathering Facts] ****************************************************************************************************************
[DEPRECATION WARNING]: Distribution ubuntu 22.04 on host asusvpn should use /usr/bin/python3, but is using /usr/bin/python for
backward compatibility with prior Ansible releases. A future Ansible release will default to using the discovered platform python for
this host. See https://docs.ansible.com/ansible/2.10/reference_appendices/interpreter_discovery.html for more information. This
feature will be removed in version 2.12. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
ok: [asusvpn]
TASK [Update apt cache if needed.] ****************************************************************************************************
fatal: [asusvpn]: FAILED! => {"changed": false, "msg": "Failed to update apt cache: E:Failed to fetch https://ppa.launchpadcontent.net/yt-dlp/stable/ubuntu/dists/jammy/InRelease 403 Forbidden [IP: 185.125.190.52 443], E:The repository 'https://ppa.launchpadcontent.net/yt-dlp/stable/ubuntu jammy InRelease' is no longer signed., W:Updating from such a repository can't be done securely, and is therefore disabled by default., W:See apt-secure(8) manpage for repository creation and user configuration details., W:An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: https://pkg.jenkins.io/debian-stable binary/ Release: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 5BA31D57EF5975CA"}
PLAY RECAP ****************************************************************************************************************************
asusvpn : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
kevin@asus:~/DATAVOLUME/ANSIBLECODE/lamp$
kevin@asus:~/DATAVOLUME/ANSIBLECODE/lamp$ ansible-playbook -i inventory playbook.lamp.yml --list-tasks
playbook: playbook.lamp.yml
play #1 (asusvpn): my lamp playbook TAGS: []
tasks:
Update apt cache if needed. TAGS: []
Get software for apt repository management. TAGS: []
Add ondrej repository for later versions of PHP. TAGS: []
Install Apache, MySQL, PHP, and other dependencies. TAGS: []
Start Apache, MySQL, and PHP. TAGS: []
Enable Apache rewrite module TAGS: []
Remove the MySQL test database. TAGS: []
Create a database for kevwells TAGS: []
kevin@asus:~/DATAVOLUME/ANSIBLECODE/lamp$
yamllint
apt install yamllint
yamllint performs syntax checks
root@asus:/media/kevin/STORAGEVOLUMELUKS/DATAVOLUME/ANSIBLECODE/lamp# yamllint playbook.lamp.yml
playbook.lamp.yml
1:1 warning missing document start "---" (document-start)
1:25 error trailing spaces (trailing-spaces)
13:1 error trailing spaces (trailing-spaces)
35:1 error trailing spaces (trailing-spaces)
49:1 error too many blank lines (3 > 2) (empty-lines)
root@asus:/media/kevin/STORAGEVOLUMELUKS/DATAVOLUME/ANSIBLECODE/lamp#
to add to git:
cd root@asus:/home/kevin/LOCAL/WORK/AnsibleLab#
git add inventory.yaml
git commit -m "added inventory.yaml"
git branch -M main
you only need this when creating a new git:
git remote add origin https://github.com/KevWellsLinux/AnsibleLab.git
then finally do:
git push -u origin main
kevin@asus:~/LOCAL/WORK/AnsibleLab$
kevin@asus:~/LOCAL/WORK/AnsibleLab$ git add AnsibleLabNOTES
kevin@asus:~/LOCAL/WORK/AnsibleLab$ git commit -m "added AnsibleLabNOTES"
[main 61729d0] added AnsibleLabNOTES
1 file changed, 488 insertions(+)
create mode 100644 AnsibleLabNOTES
kevin@asus:~/LOCAL/WORK/AnsibleLab$ git branch -M main
kevin@asus:~/LOCAL/WORK/AnsibleLab$ git remote add origin https://github.com/KevWellsLinux/AnsibleLab.git
error: remote origin already exists.
kevin@asus:~/LOCAL/WORK/AnsibleLab$ git push -u origin main
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 5.30 KiB | 5.30 MiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/KevWellsLinux/AnsibleLab.git
b1e3ea2..61729d0 main -> main
Branch 'main' set up to track remote branch 'main' from 'origin'.
kevin@asus:~/LOCAL/WORK/AnsibleLab$
14. How do you use Ansible to handle different operating systems and versions?
Ansible can handle different operating systems and versions by using different modules and conditional statements, here are a few ways to do it:
Use the ansible_os_family variable: Ansible automatically sets the ansible_os_family variable which can be used to check the family of the target operating system. For example, you can use this variable in a conditional statement to run specific tasks for different operating system families, such as Debian or Red Hat.
Use the ansible_distribution variable: Ansible automatically sets the ansible_distribution variable which can be used to check the specific distribution of the target operating system. For example, you can use this variable in a conditional statement to run specific tasks for different distributions, such as Ubuntu or Fedora.
Use the ansible_distribution_version variable: Ansible automatically sets the ansible_distribution_version variable which can be used to check the specific version of the target operating system. For example, you can use this variable in a conditional statement to run specific tasks for different versions of the same distribution, such as Ubuntu 18.04 or Ubuntu 20.04
Use the when statement: You can use the when statement to conditionally execute tasks based on the operating system and version. For example, you can use the when statement to run a task only on Ubuntu 18.04 and not on other versions.
Use different modules: Some modules are specific to certain operating systems or versions. For example, the apt module is specific to Debian-based systems, while the yum module is specific to Red Hat-based systems.
Use the setup module: The setup module can be used to gather information about the target system, such as the operating system and version. You can use this information in conjunction with the when statement to conditionally execute tasks based on the operating system and version.
#
16. How do you test Ansible playbooks before deploying them to production?
Testing Ansible playbooks before deploying them to production is an important step to ensure that your playbooks are functioning correctly and will not cause any issues in production. Here are a few ways to test Ansible playbooks:
Use a test environment: Create a test environment that closely mirrors your production environment. This allows you to test your playbooks in a realistic setting, and to identify and fix any issues before deploying to production.
Use the --check flag: Use the --check flag with the ansible-playbook command to run a “dry run” of your playbook. This will show you the tasks that would be executed, but will not actually make any changes to your servers.
Use the --diff flag: Use the --diff flag with the ansible-playbook command to show the differences that would be made to your servers. This can be useful for identifying any unintended changes that your playbooks might make.
Use test-driven development (TDD): Use a TDD approach to test playbooks, by writing test cases and testing the playbooks using testing tools such as molecule or testinfra.
Use Continuous integration and Continuous delivery (CI/CD): Use a CI/CD pipeline to automate the testing of your playbooks, by using tools such as Jenkins, Travis CI, and CircleCI to automatically run tests and deploy playbooks to test environments.
Use Ansible Lint: Use Ansible Lint to check for errors, best practices, and formatting issues in your playbooks.
Use Ansible’s assert module : The assert module can be used to check for certain conditions within the playbook execution and fail the execution if the conditions are not met.
ently and correctly.
Assigning a variable to many machines: group variables
If all hosts in a group share a variable value, you can apply that variable to an entire group at once.
In INI:
[atlanta]
host1
host2
[atlanta:vars]
ntp_server=ntp.atlanta.example.com
proxy=proxy.atlanta.example.com
In YAML:
atlanta:
hosts:
host1:
host2:
vars:
ntp_server: ntp.atlanta.example.com
proxy: proxy.atlanta.example.com
Group variables are a convenient way to apply variables to multiple hosts at once. Before executing, however, Ansible always flattens variables, including inventory variables, to the host level. If a host is a member of multiple groups, Ansible reads variable values from all of those groups. If you assign different values to the same variable in different groups, Ansible chooses which value to use based on internal rules for merging.
Ansible Inventory File Groups
virtualmachines:
hosts:
ubuntu101:
ansible_host: 192.168.122.101
ubuntu102:
ansible_host: 192.168.122.102
ubuntu103:
ansible_host: 192.168.122.103
children:
webservers:
hosts:
ubuntu101:
dbservers:
hosts:
ubuntu102:
fileservers:
hosts:
ubuntu103:
virtualmachines:
hosts:
ubuntu101:
ansible_host: 192.168.122.101
ubuntu102:
ansible_host: 192.168.122.102
ubuntu103:
ansible_host: 192.168.122.103
children:
webservers:
hosts:
ubuntu101:
dbservers:
hosts:
ubuntu102:
fileservers:
hosts:
ubuntu103:
Best Practices
Keep your hosts file names simple – I always use hosts
Comment were required to ensure someone else can understand your inventory
Use children to address multiple groups at once
Do not put passwords in your inventory file – reference them in group_vars or host_vars or even better use Ansible vault within those files.
all:
hosts:
mail.example.com:
children:
webservers:
hosts:
foo.example.com:
bar.example.com:
dbservers:
hosts:
one.example.com:
two.example.com:
three.example.com:
east:
hosts:
foo.example.com:
one.example.com:
two.example.com:
west:
hosts:
bar.example.com:
three.example.com:
prod:
hosts:
foo.example.com:
one.example.com:
two.example.com:
test:
hosts:
bar.example.com:
three.example.com:
Add the following content to your playbook-01.yml file:
~/ansible-practice/playbook-01.yml
---
- hosts: all
tasks:
- name: Print message
debug:
msg: Hello Ansible World
To try this playbook on the server(s) that you set up in your inventory file, run ansible-playbook with the same connection arguments you used when running a connection test within the introduction of this series. Here, we’ll be using an inventory file named inventory and the sammy user to connect to the remote server, but be sure to change these details to align with your own inventory file and administrative user:
ansible-playbook -i inventory playbook-01.yml -u sammy
ansible-playbook -i inventory.yml playbook-01.yml -u kevin
Ansible stores facts in JSON format, with items grouped in nodes. To check what kind of information is available for the systems you’re provisioning, you can run the setup module with an ad hoc command:
ansible all -i inventory.yaml -m setup -u kevin
This command will output an extensive JSON containing information about your server. To obtain a subset of that data, you can use the filter parameter and provide a pattern. For instance, if you’d like to obtain information about all IPv4 addresses in the remote nodes, you can use the following command:
ansible all -i inventory -m setup -a "filter=*ipv4*" -u sammy
YAML
YAML is a syntax for storing structured data in plain text. It’s an alternative to JSON and XML, which you’ve probably seen and used before. Like many things in web programming today, it was originally popularised by the Ruby On Rails framework.
All YAML Files Start With Three Hyphens
As you work your way through this book, you'll notice that every example YAML file starts with three hyphens on the first line. This is part of the YAML spec.
If you leave out the three hyphens, your YAML file won't load.
Don't Mix Tabs And Spaces In YAML Files
Like Python, YAML uses indentation to understand the scope of an instruction on a line. If you indent your lines using a mixture of tabs and spaces, YAML can't tell what you mean, and Ansible will report a syntax error.
Roles
A role is a single change that Ansible will make to a computer. On disk, each role is a folder that contains:
One or more tasks
Handlers to restart services when a task has run
Files to copy up to the computer you are provisioning
Templates to expand and then copy up to the computer you are provisioning
Metadata to tell Ansible which roles this role depends on
A role must contain at least a task, metadata or a handler.
Roles are said to be applied to a computer when they have successfully run.
Roles are fundamental to how to work with Ansible.
Play
A play is a YAML file that tells Ansible which roles to apply to a set of computers.
---
- hosts: build-servers
roles:
- stuartherbert.gcc
- stuartherbert.autotools
- stuartherbert.distcc
This play tells Ansible to apply the roles stuartherbert.gcc, stuartherbert.autotools, stuartherbert.distcc to every host in the Inventory that’s in the build-servers set.
Tasks
A task is a YAML file stored inside a role’s folder. It contains instructions that tell Ansible how to apply a role to the target computer. A role must contain at least one task file, and can contain more than one.
Modules
An Ansible module is an Ansible code library that you can call from a task or handler. Ansible ships with a large (and growing) set of modules. You can also write your own modules.
Handlers
A handler is a task that gets called when a notify event is triggered by one of your tasks. They’re originally intended to restart services and daemons after you’ve made a change (so that your change is picked up and becomes active), but you can use them to do whatever you need done.
Files
A file is part of a role; it is a file to copy from your playbook repo to the target computer. It can be a plain-text file (such as a configuration file), a script that you want to run on the target computer, or even a binary of some kind.
A role can contain as many, or as few files as needed.
Templates
A template is part of a role; it is a file that is expanded using Jinja2 and then copied from your playbook repo to the target computer. Templates are normally used for plain-text configuration files.
A role can contain as many, or as few templates as needed.
I explain templates in detail in Working With Config Files
Metadata
Metadata is part of a role, and is currently used to tell Ansible which roles it needs to run before it runs the current role. Or, in other words, which roles the current role depends upon.
I look at metadata in these chapters:
Adding Dependencies To Roles
Facts
A fact is a constant that Ansible defines. The first thing Ansible does when it runs is to example each computer listed in the Inventory, and define a set of facts that describe that computer’s current state (known as gathering facts).
You can use facts and variables in your tasks, handlers and templates.
Gathering Facts
Gathering facts is what Ansible does before it executes a playbook. Ansible logs into the target computer (normally via SSH) and defines a set of facts that describes the computer’s current state. These facts are then available to use in your tasks, handlers and templates.
Variables
A variable is a piece of data that you define. Variables can be set statically in the Inventory, host_vars or group_vars, or you can set variables dynamically whilst executing tasks.
You can use facts and variables in your tasks, handlers and templates.
Inventory
The Inventory is a list of hosts that you want Ansible to apply roles to, and a list of which roles apply to which hosts. Hosts can also be grouped so that you can update groups separately, or apply different variables to different groups of hosts. The Inventory is stored in a file on disk, and can be committed to source control.
The Inventory can also be dynamic: generated by code, or otherwise retrieved from another software system of some kind. You can even mix and match the two approaches, having some of the Inventory in static files, and some of it dynamic. It’s an advanced topic that’s beyond the scope of this book, and covered in the official Ansible docs.