How to skip a hostname from ansible inventory file? - ansible

My ansible inventory file has the following entry
[non_prod_servers]
oracle[1:13]
How can I eliminate hosts "oracle7" and "oracle10" from the above specification, without having to create the following entries?
[non_prod_servers]
oracle[1:6]
oracle[8:9]
oracle[11:13]
Essentially, looking for an elegant solution than what I have come up with.
Thanks in advance.
FR

IMHO, the functionality, you're looking for, is not available. You can use Python slicing inside the inventory. The inventory patterns do not apply inside the inventory file.
If you need it for automation, i.e. you want to control the process by a couple of variables the inventory and playbook below create the group dynamically
shell> cat hosts
[non_prod_servers]
localhost
[non_prod_servers:vars]
_name=oracle
_from=1
_to=13
_deny=[7,10]
shell> cat playbook.yml
---
- hosts: non_prod_servers
gather_facts: false
tasks:
- add_host:
hostname: "{{ _name }}{{ item }}"
groups: non_prod_servers_dyn
loop: "{{ range(_from, _to + 1)|difference(_deny) }}"
- hosts: non_prod_servers_dyn
gather_facts: false
tasks:
- debug:
var: ansible_play_hosts_all
run_once: true
gives
shell> ansible-playbook -i hosts playbook.yml
PLAY [non_prod_servers] *************************************************
TASK [add_host] *********************************************************
ok: [localhost] => (item=1)
ok: [localhost] => (item=2)
ok: [localhost] => (item=3)
ok: [localhost] => (item=4)
ok: [localhost] => (item=5)
ok: [localhost] => (item=6)
ok: [localhost] => (item=8)
ok: [localhost] => (item=9)
ok: [localhost] => (item=11)
ok: [localhost] => (item=12)
ok: [localhost] => (item=13)
PLAY [non_prod_servers_dyn] **********************************************
TASK [debug] *************************************************************
ok: [oracle1] =>
ansible_play_hosts_all:
- oracle1
- oracle2
- oracle3
- oracle4
- oracle5
- oracle6
- oracle8
- oracle9
- oracle11
- oracle12
- oracle13

Related

Ansible special tag 'never' is not working with import_playbook and --tags

The special tag 'never' is not applied in my second use case. I can't find out in the Ansible document if this is normal behavior, or if it is a bug.
playbook-parent.yml
- name: parent playbook
import_playbook: playbook-child.yml
tags:
- toto
playbook-child.yml
- hosts: local
roles:
- role: test
tags:
- never
roles/test/tasks/main.yml
- name: hello word
copy:
content: hello world
dest: testfile.txt
Test Case 1: Tag never is applied with the command below ==> OK :)
shell> ansible-playbook playbook-parent.yml
PLAY [local] **********************************
TASK [Gathering Facts] ************************
ok: [127.0.0.]
PLAY RECAP ************************************
...
Test Case 2: Tag 'never' is not applied with the command below ==> Normal? Bug?
ansible-playbook playbook-parent.yml --tags toto
PLAY [local] **********************************
TASK [Gathering Facts] ************************
ok: [127.0.0.]
TASK [test: help word] ************************
changed: [127.0.0.]
PLAY RECAP ************************************
...
Q: "The special tag 'never' is not applied in my second use case, I can't find out in the Ansible document if this is normal behavior."
A: Quoting from Special tags: always and never
If you assign the never tag to a task or play, Ansible will skip that task
or play unless you specifically request it (--tags never).
Given the role
shell> cat roles/test/tasks/main.yml
- debug:
var: ansible_run_tags
The play
shell> cat playbook-child.yml
- hosts: localhost
roles:
- role: test
tags:
- never
works as expected
shell> ansible-playbook playbook-child.yml -t never
displays the debug message
TASK [test : debug] ***************************************************
ok: [localhost] =>
ansible_run_tags:
- never
and the play without the tag does nothing
shell> ansible-playbook playbook-child.yml
The next playbook applies the tag toto to all tasks in the playbook playbook-child.yml
shell> cat playbook-parent.yml
- name: parent playbook
import_playbook: playbook-child.yml
tags:
- toto
As expected, without any tag the play does nothing
shell> ansible-playbook playbook-parent.yml
But if any of the tags toto or never or both are applied the play displays the debug message
shell> ansible-playbook playbook-parent.yml -t toto
TASK [test : debug] ********************************************************
ok: [localhost] =>
ansible_run_tags:
- toto
shell> ansible-playbook playbook-parent.yml -t never
TASK [test : debug] ********************************************************
ok: [localhost] =>
ansible_run_tags:
- never
shell> ansible-playbook playbook-parent.yml -t never,toto
TASK [test : debug] ********************************************************
ok: [localhost] =>
ansible_run_tags:
- never
- toto
You appear to be misunderstanding the function of the never tag. As the documentation says:
If you assign the never tag to a task or play, Ansible will skip that task or play unless you specifically request it
You have specifically requested that play to run by passing --tags toto, so it ran. Your example is overly complex; you can demonstrate the behaviour clearly in a single playbook.
- hosts: localhost
gather_facts: false
tasks:
- debug:
msg: task 1
tags:
- never
- debug:
msg: task 2
tags:
- never
- foo
- debug:
msg: task 3
tags:
- foo
- debug:
msg: task 4
ansible-playbook test.yml:
PLAY [localhost] ***************************************************************
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "task 3"
}
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "task 4"
}
ansible-playbook test.yml --tags foo:
PLAY [localhost] ***************************************************************
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "task 2"
}
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "task 3"
}
ansible-playbooks --tags foo --skip-tags never:
PLAY [localhost] ***************************************************************
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "task 3"
}

Running ansible playbook in serial over hostgroups

Im trying to run a playbook for n host groups serially (but 100% parallel within the host group). How do I achieve this?
I've tried things like:
- name: Test
hosts: group1:group2
serial: 100%
and even
- name: Test
hosts: group1:group2
serial: 1
Thinking it would do group by group, however these do not work.
How do I get it to run over all of group1, then after, all of group2 (but fail if anything in group1 fails)?
Also, how do I get it to run over n groups? (There are many hostgroups, which might be tough to define in the hosts key)
You can't control a playbook from another playbook. You'll have to control the playbook from outside, for example by a script. Given the inventory
shell> cat hosts-497
[group1]
srv1
[group2]
srv2
srv3
[group3]
srv4
srv5
srv6
and the playbook
shell> cat test-497.yml
- name: Test
hosts: all
gather_facts: false
tasks:
- debug:
msg: "{{ '%H:%M:%S'|strftime }}: {{ inventory_hostname }}"
the debug task is executed in parallel by all hosts
shell> ansible-playbook -i hosts-497 test-497.yml
PLAY [Test] ***************************************************************
TASK [debug] **************************************************************
ok: [srv3] =>
msg: '20:51:30: srv3'
ok: [srv1] =>
msg: '20:51:30: srv1'
ok: [srv4] =>
msg: '20:51:30: srv4'
ok: [srv2] =>
msg: '20:51:30: srv2'
ok: [srv5] =>
msg: '20:51:30: srv5'
ok: [srv6] =>
msg: '20:51:30: srv6'
If you want to control the hosts create a script and iterate the groups, e.g.
shell> cat test-497.sh
#!/usr/bin/sh
for i in group1 group2 group3; do
ansible-playbook -i hosts-497 --limit $i test-497.yml
done
gives (abridged)
shell> ./test-497.sh
PLAY [Test] *************************************************************
TASK [debug] ************************************************************
ok: [srv1] =>
msg: '20:56:41: srv1'
PLAY [Test] *************************************************************
TASK [debug] ************************************************************
ok: [srv3] =>
msg: '20:56:45: srv3'
ok: [srv2] =>
msg: '20:56:45: srv2'
PLAY [Test] *************************************************************
TASK [debug] ************************************************************
ok: [srv5] =>
msg: '20:56:52: srv5'
ok: [srv6] =>
msg: '20:56:52: srv6'
ok: [srv4] =>
msg: '20:56:53: srv4'

In Ansible, how can I iterate over stdout with an array?

Ansible v2.6.3
I have the simple task, which gets the AWS ARNs in my jenkins ECS cluster
tasks:
- command: aws ecs list-container-instances --cluster jenkins
register: jenkins_ecs_containers
- debug: var=jenkins_ecs_containers.stdout
and has the following output
TASK [debug] *******************************************************************
ok: [localhost] => {
"jenkins_ecs_containers.stdout": {
"containerInstanceArns": [
"arn:aws:ecs:us-east-1:arn0",
"arn:aws:ecs:us-east-1:arn1"
]
}
}
How can I iterate over the ARNs? I tried
- debug: var=item
with_items: jenkins_ecs_containers.stdout.containerInstanceArns
gives
TASK [debug] *******************************************************************
ok: [localhost] => (item=jenkins_ecs_containers.stdout.containerInstanceArns) => {
"item": "jenkins_ecs_containers.stdout.containerInstanceArns"
}
or
- debug: var=item
with_items: "{{ jenkins_ecs_containers.stdout.containerInstanceArns }}"
gives
TASK [debug] *******************************************************************
fatal: [localhost]: FAILED! => {"msg": "'ansible.utils.unsafe_proxy.AnsibleUnsafeText object' has no attribute 'containerInstanceArns'"}
to retry, use: --limit #/Users/cfouts/git-repos/ansible/playbooks/loop.retry
Thanks!
I created a file with your output. So I used set_fact. Otherwise, it's just a string, not a JSON object:
tasks:
- command: cat files/stdout.txt
register: result
- debug: var=result.stdout
- set_fact:
jenkins_ecs_containers: "{{ result.stdout }}"
- debug:
msg: "{{ item }}"
with_items: "{{ jenkins_ecs_containers.containerInstanceArns }}"
This gave me the following output:
PLAY [localhost] ***************************************************************
TASK [Gathering Facts] *********************************************************
ok: [localhost]
TASK [command] *****************************************************************
changed: [localhost]
TASK [debug] *******************************************************************
ok: [localhost] => {
"result.stdout": {
"containerInstanceArns": [
"arn:aws:ecs:us-east-1:arn0",
"arn:aws:ecs:us-east-1:arn1"
]
}
}
TASK [set_fact] ****************************************************************
ok: [localhost]
TASK [debug] *******************************************************************
ok: [localhost] => (item=None) => {
"msg": "arn:aws:ecs:us-east-1:arn0"
}
ok: [localhost] => (item=None) => {
"msg": "arn:aws:ecs:us-east-1:arn1"
}
PLAY RECAP *********************************************************************
localhost : ok=5 changed=1 unreachable=0 failed=0
You can iterate over like this:
- debug:
msg: "{{ item[1] }}"
with_subelements:
- "{{ jenkins_ecs_containers }}"
- containerInstanceArns
Go through this link, it will make it clearer.

ansible find first undefined value in list

I have a list in ansible and I want to find the first "unused" item in that list.
Example list:
item001
item002
item004
item005
item100
item101
The prefix numbers in the items could be up to 999
In the example above the result should be item003.
Here is an example playbook of what I want
---
- name: Test
connection: local
hosts: localhost
vars:
my_list: []
list1:
- item107
- item002
- item004
- item001
- item007
- item101
- item604
tasks:
- name: Initialize a dummy list
set_fact:
my_list: "{{ my_list|sort }} + [ '{{ item }}' ]"
with_sequence: start=1 end=19 format=item%.3d
- name: print first unused value in my_list
debug:
msg: "{{ (my_list | difference(list1))[0] }}"
output:
PLAY [Test] *******************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************************************************************************************************
ok: [localhost]
TASK [Initialize a dummy list] ************************************************************************************************************************************************************************************
ok: [localhost] => (item=item001)
ok: [localhost] => (item=item002)
ok: [localhost] => (item=item003)
ok: [localhost] => (item=item004)
ok: [localhost] => (item=item005)
ok: [localhost] => (item=item006)
ok: [localhost] => (item=item007)
ok: [localhost] => (item=item008)
ok: [localhost] => (item=item009)
ok: [localhost] => (item=item010)
ok: [localhost] => (item=item011)
ok: [localhost] => (item=item012)
ok: [localhost] => (item=item013)
ok: [localhost] => (item=item014)
ok: [localhost] => (item=item015)
ok: [localhost] => (item=item016)
ok: [localhost] => (item=item017)
ok: [localhost] => (item=item018)
ok: [localhost] => (item=item019)
TASK [print first unused value in my_list] ************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": "item003"
}
PLAY RECAP ********************************************************************************************************************************************************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0
But if I change with_sequence: start=1 end=19 to with_sequence: start=1 end=999 the tasks takes very long time and also prints 999 lines in the output I really would love to not see.
This actually worked better, didn't print any large output and was much quicker:
- name: Initialize a dummy list
set_fact:
my_list: "{{ lookup('sequence', 'start=1 count=999 format=item%.3d', wantlist=True) }}"

Ansible hostvars undefined

I have a very simple play which saves vars and looks them up in hostvars.
- name: Set hostvars
hosts: localhost
vars:
var_one: "I am a"
var_two: "test"
tasks:
- debug: var=hostvars['localhost']['var_one']
- debug: var=hostvars['localhost']['var_two']
However, when I run this play the vars aren't defined:
PLAY [Set hostvars] ************************************************************
TASK [setup] *******************************************************************
ok: [localhost]
TASK [debug] *******************************************************************
ok: [localhost] => {
"hostvars['localhost']['var_one']": "VARIABLE IS NOT DEFINED!"
}
TASK [debug] *******************************************************************
ok: [localhost] => {
"hostvars['localhost']['var_two']": "VARIABLE IS NOT DEFINED!"
}
How can I save these vars in hostvars?
You can set host facts runtime using set_fact module:
---
- name: Set hostvars
hosts: localhost
tasks:
- set_fact: var_one="I am a"
- set_fact: var_two="test"
- debug: var=hostvars['localhost']['var_one']
- debug: var=hostvars['localhost']['var_two']
Quoting the documentation:
These variables will survive between plays during an Ansible run, but will not be saved across executions even if you use a fact cache.
This is where the difference between facts (variables bound to Ansible target hosts) and regular variables can be seen.
Variables are internally stored in vars structure, so you can access them with:
tasks:
- debug: var=vars['var_one']
- debug: var=vars['var_two']
Facts, on the other hand are stored in hostvars.
In either case, unless you were referring to a variable name with a dynamic name, or a fact bound to another host than the one executing the task, you can simply use the variable/fact name by using its name:
tasks:
- debug: var=var_one
- debug: var=var_two
Try using
msg=
instead of var=. As per help of debug module
var - A variable name to debug. Mutually exclusive with the 'msg' option.
- name: Set hostvars
hosts: localhost
vars:
var_one: I am a
var_two: est
tasks:
- debug: msg=hostvars['localhost']['var_one']
- debug: msg=hostvars['localhost']['var_two']
...
PLAY [Set hostvars] ************************************************************
TASK [setup] *******************************************************************
ok: [localhost]
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "hostvars['localhost']['var_one']"
}
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "hostvars['localhost']['var_two']"
}
PLAY RECAP *********************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0

Resources