ansible_(hostname|distribution("|_version))
'"ansible_distribution": "Debian", "ansible_distribution_version": "9.12", "ansible_hostname": "node1", "ansible_distribution": "RedHat", "ansible_distribution_version": "7.4", "ansible_hostname": "node2",
grep -E "^(NAME|VERSION)=" /etc/os-release
' -bkKnode1 | CHANGED | rc=0 >>
NAME="Debian GNU/Linux"
VERSION="9 (stretch)"
node2 | CHANGED | rc=0 >>
NAME="Red Hat Enterprise Linux Server"
VERSION="7.4 (Maipo)"
--- # ANSIBLE_LOCALHOST_WARNING=false ANSIBLE_STDOUT_CALLBACK=yaml ansible-playbook test.yml - hosts: 127.0.0.1 connection: local gather_facts: no vars: haystack: 'hello world' tasks: - debug: msg: 'found!' when: haystack is match(item) loop: - 'hello' - 'hello world' - 'world' - '..... world' - 'll' - '.*ll' - '.*(.)\1' ...
TASK [debug] ***************************** ok: [127.0.0.1] => (item=hello) => msg: found! ok: [127.0.0.1] => (item=hello world) => msg: found! skipping: [127.0.0.1] => (item=world) ok: [127.0.0.1] => (item=..... world) => msg: found! skipping: [127.0.0.1] => (item=ll) ok: [127.0.0.1] => (item=.*ll) => msg: found! ok: [127.0.0.1] => (item=.*(.)\1) => msg: found!
searchDir='./roles/'; startToken='yum:'; endToken='^$'; separator='---' while read fileName; do awk -v ST="$startToken" -v ET="$endToken" -v SEP="$separator" ' BEGIN { betweenTokens=0 } $0 ~ ST { betweenTokens=1; print FILENAME } betweenTokens == 1 { print $0 } $0 ~ ET && betweenTokens == 1 { betweenTokens=0; print SEP }' "$fileName" done < <(find "$searchDir" -iname '*yml') | awk -v SEP="$separator" ' BEGIN { foundSep=0 } $0 == SEP && foundSep==0 { foundSep=1; print $0 } $0 !~ SEP { foundSep=0; print $0 }' | less
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all' [WARNING]: Could not match supplied host pattern, ignoring: host1 [WARNING]: Could not match supplied host pattern, ignoring: host2
method | output | pros / cons |
---|---|---|
--- - hosts: slave1, slave2 tasks: - name: "task for all hosts" debug: msg: "hello from everybody" - fail: when: inventory_hostname == 'slave1' - name: "task for survivors only" debug: msg: "hello from the survivors" ... |
TASK [task for all hosts] ****************** ok: [slave1] => msg: hello from everybody ok: [slave2] => msg: hello from everybody TASK [fail] ******************************** fatal: [slave1]: FAILED! => changed=false msg: Failed as requested from task skipping: [slave2] TASK [task for survivors only] ************* ok: [slave2] => msg: hello from the survivors |
|
--- - hosts: slave1, slave2 tasks: - name: "task for all hosts" debug: msg: "hello from everybody" - block: - name: "task for survivors only" debug: msg: "hello from the survivors" when: inventory_hostname != 'slave1' ... |
TASK [task for all hosts] ****************** ok: [slave1] => msg: hello from everybody ok: [slave2] => msg: hello from everybody TASK [task for survivors only] ************* skipping: [slave1] ok: [slave2] => msg: hello from the survivors |
|
main.yml
--- - hosts: slave1, slave2 tasks: - name: "task for all hosts" debug: msg: "hello from everybody" - block: - name: "include tasks for survivors only" include_tasks: tasksForSurvivors.yml when: inventory_hostname != 'slave1' ...tasksForSurvivors.yml ---
- name: "task for survivors only"
debug:
msg: "hello from the survivors"
... |
TASK [task for all hosts] ****************** ok: [slave1] => msg: hello from everybody ok: [slave2] => msg: hello from everybody TASK [include tasks for survivors only] ************* skipping: [slave1] included: path/to/tasksForSurvivors.yml for slave2 TASK [task for survivors only] ************* ok: [slave2] => msg: hello from the survivors |
|
--- # ANSIBLE_LOCALHOST_WARNING=false ansible-playbook testVmware.yml -DC - hosts: 127.0.0.1 connection: local gather_facts: no vars: vcenter: structure: hostname: 'vcenter.myCompany.tld' datacenter: 'MY_DATACENTER' cluster: 'MY_CLUSTER' account: username: 'kevin' password: 'P@ssw0rd' virtualMachines: - name: 'test_VM_made_with_ansible__1' folder: '/development' state: 'poweredon' datastore: 'DS_DEVELOPMENT' template: 'TEMPLATE_RHEL8.4' hardware: memoryMb: 2048 nbCpu: 1 networks: - name: 'DvS_DEVELOPMENT' ip: 10.27.25.23 netmask: 255.255.255.224 gateway: 10.27.25.30 - name: 'DvS_TESTING' ip: 10.27.25.200 netmask: 255.255.255.224 gateway: 10.27.25.222 disk: - size_gb: 20 type: thin - size_gb: 1 just trying to create a VM with more disks that the template type: thin - name: 'test_VM_made_with_ansible__2' folder: '/development' state: 'poweredon' datastore: 'DS_DEVELOPMENT' template: 'TEMPLATE_RHEL8.4' hardware: memoryMb: 2048 nbCpu: 1 disk: - size_gb: 21 can the 1st disk be larger than the one specified in the template ? type: thin - size_gb: 2 type: thin networks: - name: 'DvS_DEVELOPMENT' ip: 10.27.25.24 netmask: 255.255.255.224 gateway: 10.27.25.30 - name: 'DvS_TESTING' ip: 10.27.25.201 netmask: 255.255.255.224 gateway: 10.27.25.222 tasks: - name: Test connection to vCenter vmware_vm_facts: hostname: "{{ vcenter.structure.hostname }}" username: "{{ vcenter.account.username }}" password: "{{ vcenter.account.password }}" validate_certs: no - name: "Delete all the VMs" so that I can start clean each time I execute this playbook vmware_guest: hostname: "{{ vcenter.structure.hostname }}" username: "{{ vcenter.account.username }}" password: "{{ vcenter.account.password }}" validate_certs: no name: "{{ vm.name }}" state: absent force: yes necessary when trying to delete a powered on VM loop: "{{ virtualMachines }}" loop_control: loop_var: vm - name: "Create virtual machines" vmware_guest: hostname: "{{ vcenter.structure.hostname }}" username: "{{ vcenter.account.username }}" password: "{{ vcenter.account.password }}" validate_certs: no datacenter: "{{ vcenter.structure.datacenter }}" cluster: "{{ vcenter.structure.cluster }}" name: "{{ vm.name }}" folder: "{{ vm.folder }}" state: "{{ vm.state }}" datastore: "{{ vm.datastore }}" disk: "{{ vm.disk }}" hardware: memory_mb: "{{ vm.hardware.memoryMb }}" num_cpus: "{{ vm.hardware.nbCpu }}" scsi: paravirtual networks: "{{ vm.networks }}" template: "{{ vm.template }} loop: "{{ virtualMachines }}" loop_control: loop_var: vm ...
^[^#]*$ansibleSetting
" ./ansible.cfg ~/.ansible.cfg /etc/ansible/ansible.cfgbecome_method
'DEFAULT_BECOME_METHOD: default: sudo description: Privilege escalation method to use when `become` is enabled. env: - {name: ANSIBLE_BECOME_METHOD} ini: - {key: become_method, section: privilege_escalation} name: Choose privilege escalation method
difference()
filter, which is exactly what I needed. I was totally unaware of it, maybe I should worry about my googling skills .--- # ANSIBLE_LOCALHOST_WARNING=false ansible-playbook test.yml - hosts: 127.0.0.1 connection: local gather_facts: no vars: myList: [ 'a', 'b', 'c', '4', 'd', '9' ] groceryList: [ 'fruit', 'vegetables', 'milk', 'FAT', 'SALT', 'SUGAR' ] unhealthyFood: [ 'FAT', 'SALT', 'SUGAR' ] tasks: - set_fact: rejectSingleItem: "{{ myList | reject('search', '4') | list }}" rejectNonMatching: "{{ myList | reject('match', '[^a-z]') | list }}" healthyGroceryList_forLoop: "[ {% for item in groceryList if item not in unhealthyFood %}'{{ item }}'{{ ', ' if not loop.last else '' }}{% endfor %} ]" healthyGroceryList_reject: "{{ groceryList | reject('in', unhealthyFood) | list }}" healthyGroceryList_difference: "{{ groceryList | difference(unhealthyFood) }}" - debug: var: "{{ item }}" loop: - rejectSingleItem - rejectNonMatching - healthyGroceryList_forLoop - healthyGroceryList_reject - healthyGroceryList_difference ...
TASK [debug] ***************************************************** ok: [127.0.0.1] => (item=rejectSingleItem) => { "ansible_loop_var": "item", "item": "rejectSingleItem", "rejectSingleItem": [ "a", "b", "c", "d", "9" ] } ok: [127.0.0.1] => (item=rejectNonMatching) => { "ansible_loop_var": "item", "item": "rejectNonMatching", "rejectNonMatching": [ "a", "b", "c", "d" ] } ok: [127.0.0.1] => (item=healthyGroceryList_forLoop) => { "ansible_loop_var": "item", "healthyGroceryList_forLoop": [ "fruit", "vegetables", "milk" ], "item": "healthyGroceryList_forLoop" } ok: [127.0.0.1] => (item=healthyGroceryList_reject) => { "ansible_loop_var": "item", "healthyGroceryList_reject": [ "fruit", "vegetables", "milk" ], "item": "healthyGroceryList_reject" } ok: [127.0.0.1] => (item=healthyGroceryList_difference) => { "ansible_loop_var": "item", "healthyGroceryList_difference": [ "fruit", "vegetables", "milk" ], "item": "healthyGroceryList_difference" }
Code | Output | Notes |
---|---|---|
- fail: msg: "ALERT!" |
TASK [fail] ********************************************************************************************* fatal: [myHost]: FAILED! => {"changed": false, "msg": "ALERT!"} PLAY RECAP ********************************************************************************************** myHost : ok=n changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0 |
|
- fail: msg: "ALERT!" ignore_errors: true |
TASK [fail] ********************************************************************************************* fatal: [myHost]: FAILED! => {"changed": false, "msg": "ALERT!"} ...ignoringfollowing tasks, then finally : PLAY RECAP ********************************************************************************************** myHost : ok=n changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1 |
|
- block: - fail: msg: "ALERT!" rescue: - debug: msg: "RESCUE" |
TASK [fail] ********************************************************************************************* fatal: [myHost]: FAILED! => {"changed": false, "msg": "ALERT!"} TASK [debug] ******************************************************************************************** ok: [myHost] => { "msg": "RESCUE" }following tasks, then finally : PLAY RECAP ********************************************************************************************** myHost : ok=n changed=0 unreachable=0 failed=0 skipped=0 rescued=1 ignored=0 |
|
- mail: |
(nothing special, just like any other task) |
|
Target | Syntax | Comment |
---|---|---|
by name | ||
a list of hosts | ansible host1,host2,host3 | |
a list of hosts matching a regular expression | ansible '~server0[12]\.acme\.org' |
|
by group | ||
all hosts of a single group | ansible groupName | |
all hosts known to Ansible | ansible all | |
hosts of several groups | ansible group1:group2:group3 | The colon : actually means a logical OR. This command applies to any host belonging either to group1 or to group2 or to group3 When it comes to complex rules with intersections and exclusions (see examples), it may not be a REAL "logical OR" |
hosts belonging to the 2 specified groups | ansible 'group1:&group2' |
|
hosts belonging to a group, excluding those of another group | ansible 'group1:!group2' | all hosts in group1 except those in group2 |
by name + group | ||
all hosts except those matching an expression |
|
|
all hosts of a group except severalof them |
ansible 'groupName:!~(host1|host2)' |
|
- hosts: 127.0.0.1 connection: local gather_facts: no tasks: - set_fact: fruits: [ 'apple', 'orange', 'banana', ] - debug: var: item loop: - fruits - debug: var: item loop: - "{{ fruits }}" - debug: var: item loop: "{{ fruits }}"
TASK [debug] ******************************************************************** ok: [127.0.0.1] => (item=fruits) => { "item": "fruits" } TASK [debug] ******************************************************************** ok: [127.0.0.1] => (item=[u'apple', u'orange', u'banana']) => { "item": [ "apple", "orange", "banana" ] } TASK [debug] ******************************************************************** ok: [127.0.0.1] => (item=apple) => { "item": "apple" } ok: [127.0.0.1] => (item=orange) => { "item": "orange" } ok: [127.0.0.1] => (item=banana) => { "item": "banana" }
fruits
variable"{{ }}"
to pass a variable-
introduces a list itemContext | Desired status code |
Suggested method |
---|---|---|
|
don't care | fail |
|
failure | |
|
success | end_play |
- fail: msg: "Execution stopped on purpose for whatever reason"
- fail:
fail
command, none of the following commands will be executed. This stops not only the current play but actually the whole playbook execution :
--- # ANSIBLE_LOCALHOST_WARNING=false ansible-playbook test.yml - hosts: 127.0.0.1 connection: local gather_facts: no tasks: - debug: msg: "I'll be back!" - fail: - hosts: 127.0.0.1 connection: local gather_facts: no tasks: - debug: msg: "hello world" ...
PLAY [127.0.0.1] ************************************************************************************** TASK [debug] ****************************************************************************************** ok: [localhost] => msg: I'll be back! TASK [fail] ******************************************************************************************* fatal: [localhost]: FAILED! => changed=false msg: Failed as requested from task PLAY RECAP ******************************************************************************************** localhost : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
fail
, the playbook execution stops. Period.fail
— the execution continued (... or at least _seemed_ to continue). Here's what happened then :
fail
task, everything should go extremely wellfail
fail
, I thought the execution of the task I edited file continued.- meta: end_playBut it's fairly different from the
fail
method :
failureexit status
- block: - name: "End play if nothing to do" states that you're leaving earlier debug: msg: "Nothing to do, ending play" - meta: end_play exits silently when: not somethingToDo
--- - hosts: slave1, slave2 gather_facts: no tasks: - block: - debug: msg: "You shall not pass" - meta: end_play when: inventory_hostname == 'slave1' - debug: msg: "hello world" ...
PLAY [slave1, slave2] *************************************************************************** TASK [debug] ****************************************************************************************** ok: [slave1] => msg: You shall not pass skipping: [slave2] PLAY RECAP ******************************************************************************************** slave1 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 slave2 : ok=0 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
[defaults] host_key_checking = False inventory = /home/stuart/ansible/hosts roles_path = /home/stuart/ansible/roles vault_password_file = /var/lib/ansible/.vault_password
- name: unmount volume groups mount: src: "{{ item.device }}" name: "{{ item.mountPoint }}" will be path in Ansible 2.3+ state: unmounted with_items: - { device: '/dev/mapper/vg_data-data', mountPoint: '/var/lib/docker/devicemapper' } - { device: '/dev/mapper/vg_data-data', mountPoint: '/var/lib/docker' }