James8
(James)
August 22, 2012, 7:57pm
1
Hi,
I'm not sure if I have missed the way to do this, but essentially I
want to generate parts of my config file with Ansible. This is due in
part because often I'm working late into the night and making mistakes
when half asleep.
Here is what I need to generate:
datacenter VXNY {
dc-node-address-port cl201.domainname.net 3000
dc-node-address-port cl202.domainname.net 3000
dc-node-address-port cl203.domainname.net 3000
dc-node-address-port cl204.domainname.net 3000
dc-node-address-port cl205.domainname.net 3000
dc-node-address-port cl206.domainname.net 3000
dc-node-address-port cl207.domainname.net 3000
dc-node-address-port cl208.domainname.net 3000
dc-int-ext-ipmap 172.30.17.162 170.6.108.162
dc-int-ext-ipmap 172.30.17.163 170.6.108.163
dc-int-ext-ipmap 172.30.17.164 170.6.108.164
dc-int-ext-ipmap 172.30.17.165 170.6.108.165
dc-int-ext-ipmap 172.30.17.166 170.6.108.166
dc-int-ext-ipmap 172.30.17.167 170.6.108.167
dc-int-ext-ipmap 172.30.17.14 170.6.108.168
dc-int-ext-ipmap 172.30.17.15 170.6.108.169
the variables are the hostnames and eth0 and eth1. I understand how
to call these with discovery, but how do I tell Ansible to check 8
machines for this information?
Thanks,
James
When using a template, in Jinja2 syntax, you can iterate through the variable groups in a loop, which is a hash of all machine names in a group, keyed off the name of the group, and then with each group name access something like {{ hostvars[systemName][“ansible_some_fact”] }}.
So getting facts for other machines is pretty easy.
James8
(James)
August 22, 2012, 8:43pm
3
Reading the advanced playbooks section on accessing information about
other hosts
So I have been able to set this easily.
${ansible_eth1.ipv4.address}
But when you say group, am I access my hosts file?
is my hostvars the group in the hosts file?
is this closer?
${CL800.cl801.domain.net.ansible_eth1.ipv4.address)
Feel like I'm not getting it.
James
Here's a simple example that shows the first IP address of every
machine in the webservers group:
{% for host in groups['webservers'] %}
HOST: {{ host }} IP: {{ hostvars[host]['ansible_all_ipv4_addresses'][0] }}
{% endfor %}
From this, the JInja2 reference documentation, and the output of
"ansible hostname -m setup" you should be able to get the facts you
want.
James8
(James)
August 23, 2012, 6:15pm
5
What is the easiest way to test this on the command line?
Is this code supposed to be in the .j2 template or in vars/somevariable.yml?
When I understand the answers to those questions, how then do I
reference the generated list? is it:
${{{ hostvars[groups['CL000']]['ansible_all_ipv4_addresses'][0] }}
CL000 is a group in the hosts file with FQDNs
ansible-playbook deploy.smart.citrusleaf.config.yml -u jmarcus -K -vvvvvv
sheepchase:tasks jmarcus$ ansible --version
ansible 0.7
Thanks,
James
What is the easiest way to test this on the command line?
Make a template, test it in a minimal playbook that writes something
to /tmp/somefile.txt
Is this code supposed to be in the .j2 template or in vars/somevariable.yml?
It's a template.
When I understand the answers to those questions, how then do I
reference the generated list? is it:
${{{ hostvars[groups['CL000']]['ansible_all_ipv4_addresses'][0] }}
I kind of answered your template problem for you already.
James8
(James)
August 24, 2012, 1:34pm
7
Here is what I have tried:
sheepchase:tasks jmarcus$ cat deploy.smart.citrusleaf.config.yml
- hosts: CL801
user: jmarcus
sudo: True
gather_facts: True
tasks:
- name: Create the CitrusLeaf config file
action: template
src=/Users/jmarcus/ServerConfig/IT/CitrusLeaf/Sites/CL800/templates/citrusleaf.conf.j2
dest=/etc/citrusleaf/citrusleaf.test.conf
tags:
sheepchase:templates jmarcus$ cat citrusleaf.conf.j2
dc-node-address-port
[CL000]
{% for host in groups['CL000'] %}
HOST: {{ host }} IP: {{ hostvars[host]['ansible_all_ipv4_addresses'][0] }}
{% endfor %}
${{{ hostvars[groups['CL000']]['ansible_all_ipv4_addresses'][0] }}}
Here is what I get:
sheepchase:tasks jmarcus$ ansible-playbook
deploy.smart.citrusleaf.config.yml -u jmarcus -K -vvvvvv
sudo password:
PLAY [CL801] *********************
GATHERING FACTS *********************
<cl801.domain.net> ESTABLISH CONNECTION FOR USER: jmarcus
<cl801.domain.net> EXEC "$SHELL" -c 'mkdir -p
$HOME/.ansible/tmp/ansible-1345815117.08-219950512120727 && chmod a+rx
$HOME/.ansible/tmp/ansible-1345815117.08-219950512120727 && echo
$HOME/.ansible/tmp/ansible-1345815117.08-219950512120727'
<cl801.domain.net> REMOTE_MODULE setup
<cl801.domain.net> PUT
/var/folders/_s/lmr53wfd0xz81v8_0x317x4h0000gn/T/tmpfV8h3w TO
/home/jmarcus/.ansible/tmp/ansible-1345815117.08-219950512120727/setup
<cl801.domain.net> EXEC "$SHELL" -c 'chmod u+x
/home/jmarcus/.ansible/tmp/ansible-1345815117.08-219950512120727/setup'
<cl801.domain.net> EXEC sudo -k && sudo -p "[sudo via ansible,
key=xriwjqswerornwtwqhlrfbwzasdfoqqmji] password: " -u root "$SHELL"
-c /home/jmarcus/.ansible/tmp/ansible-1345815117.08-219950512120727/setup
<cl801.domain.net> EXEC "$SHELL" -c 'rm -rf
/home/jmarcus/.ansible/tmp/ansible-1345815117.08-219950512120727/'
ok: [cl801.domain.net]
TASK: [Create the CitrusLeaf config file] *********************
<cl801.domain.net> ESTABLISH CONNECTION FOR USER: jmarcus
<cl801.domain.net> EXEC "$SHELL" -c 'mkdir -p
$HOME/.ansible/tmp/ansible-1345815120.45-88585705088006 && chmod a+rx
$HOME/.ansible/tmp/ansible-1345815120.45-88585705088006 && echo
$HOME/.ansible/tmp/ansible-1345815120.45-88585705088006'
<cl801.domain.net> EXEC "$SHELL" -c 'rm -rf
/home/jmarcus/.ansible/tmp/ansible-1345815120.45-88585705088006/'
fatal: [cl801.domain.net] => {'msg': "expected token ':', got '}'",
'failed': True, 'module': 'template'}
fatal: [cl801.domain.net] => {'msg': "expected token ':', got '}'",
'failed': True, 'module': 'template'}
PLAY RECAP *********************
cl801.domain.net : ok=1 changed=0 unreachable=1
failed=0
I hope this will shed some more light on the problem I'm having.
Sorry if this seems obvious to everyone else, but it doesn't to me.
Thanks,
James
${{{ hostvars[groups[‘CL000’]][‘ansible_all_ipv4_addresses’][0] }}}
This above line is basically nonsense
Print out what groups[‘CL000’] and it should become more clear. The value is a list of hostnames, not a string.
James8
(James)
August 24, 2012, 1:45pm
9
[CL000]
cl001.domain.net
cl002.domain.net
cl003.domain.net
cl004.domain.net
cl005.domain.net
cl006.domain.net
cl007.domain.net
cl008.domain.net
cl009.domain.net
cl010.domain.net
When you say print, what is in CL000 is this something I do with Jinja2?
James
James8
(James)
August 24, 2012, 2:59pm
10
So I have been working with a coworker on this issue.
I can get the hosts to print with
{% for host in groups['CL000'] %}
HOST: {{ host }} IP: {{ hostvars[host] }}
{% endfor %}
but when we get hostvars, they are the hostvars of the servers in the
CL000 group, they are the hostvars or "setup" of the target system..
How do we get the hostvars of the servers in the group CL000?
Thanks
James
James8
(James)
August 24, 2012, 3:31pm
11
So in working through this issue we now have a play that looks like this:
- hosts: CL000
user: jmarcus
gather_facts: True
tasks:
- name: Create the CitrusLeaf config file
action: template
src=/Users/jmarcus/ServerConfig/IT/CitrusLeaf/Sites/CL800/templates/citrusleaf.conf.j2
dest=/home/jmarcus/citrusleaf.test.conf
tags:
- clconfigfile
delegate_to: cl801.domain.net
But I'm guessing this isn't the way to do things, because it presents
authentication problems.
This is the only way we have been able to get "setup" information in
citrusleaf.test.conf from the hosts in CL000.
James
There's no reason to use delegate_to here.
Step 1) run a play on all your hosts to gather facts, it doesn't even
need any tasks.
Step 2) run a play just against cl801.domain.net
Any time you are using delegate_to without a variable you are doing it
wrong. You could quite literally be executing that 200 times if you
had 200 hosts.
Just do 2 plays.
James8
(James)
August 24, 2012, 5:27pm
13
So I have done this, to gather facts, normally I do this in the play.
ansible all -m setup
I may have missed it in the documentation, does this get stored somewhere?
James
James8
(James)
August 24, 2012, 5:53pm
14
I dont' need this last question answered
James8
(James)
August 24, 2012, 10:14pm
15
Thanks for the help.
I had lots of help from someone at my office too and now I'm getting some where:
sheepchase:tasks jmarcus$ cat deploy.smart.citrusleaf.config.yml
- hosts: CL000
user: jmarcus
gather_facts: True
- hosts: CL801
user: jmarcus
gather_facts: False
tasks:
- name: Create the CitrusLeaf config file
action: template
src=/Users/jmarcus/ServerConfig/IT/CitrusLeaf/Sites/CL800/templates/citrusleaf.conf.j2
dest=/home/jmarcus/citrusleaf.test.conf
tags:
- clconfigfile
sheepchase:templates jmarcus$ cat citrusleaf.conf.j2
{% for host in groups['CL000'] %}
dc-node-address-port {{
hostvars[host]['ansible_eth0']['ipv4']['address'] }} 3000 {% endfor %}
{% for host in groups['CL000'] %}
dc-int-ext-ipmap {{
hostvars[host]['ansible_eth1']['ipv4']['address'] }} {{
hostvars[host]['ansible_eth0']['ipv4']['address'] }} {% endfor %}
[jmarcus@cl801 ~]$ cat citrusleaf.test.conf
dc-node-address-port 143.48.118.70 3000
dc-node-address-port 143.48.118.72 3000
dc-node-address-port 143.48.118.74 3000
dc-node-address-port 143.48.118.76 3000
dc-node-address-port 143.48.118.78 3000
dc-node-address-port 143.48.118.80 3000
dc-node-address-port 143.48.118.82 3000
dc-node-address-port 143.48.118.84 3000
dc-node-address-port 143.48.118.86 3000
dc-node-address-port 143.48.118.88 3000
dc-int-ext-ipmap 10.1.0.170 143.48.118.70
dc-int-ext-ipmap 10.1.0.172 143.48.118.72
dc-int-ext-ipmap 10.1.0.174 143.48.118.74
dc-int-ext-ipmap 10.1.0.176 143.48.118.76
dc-int-ext-ipmap 10.1.0.178 143.48.118.78
dc-int-ext-ipmap 10.1.0.180 143.48.118.80
dc-int-ext-ipmap 10.1.0.82 143.48.118.82
dc-int-ext-ipmap 10.1.0.84 143.48.118.84
dc-int-ext-ipmap 10.1.0.86 143.48.118.86
dc-int-ext-ipmap 10.1.0.88 143.48.118.88
James8
(James)
August 25, 2012, 12:10am
16
- hosts: CL000
user: jmarcus
gather_facts: True
- hosts: CL300
user: jmarcus
gather_facts: True
- hosts: CL801
user: jmarcus
gather_facts: False
tasks:
- name: Create the CitrusLeaf config file
action: template
src=/Users/jmarcus/ServerConfig/IT/CitrusLeaf/Sites/CL800/templates/citrusleaf.conf.j2
dest=/home/jmarcus/citrusleaf.test.conf
tags:
- clconfigfile
citrusleaf.conf.j2
{% for host in groups['CL000'] %}
dc-node-address-port {{
hostvars[host]['ansible_eth0']['ipv4']['address'] }} 3000 {% endfor %}
{% for host in groups['CL000'] %}
dc-int-ext-ipmap {{
hostvars[host]['ansible_eth1']['ipv4']['address'] }} {{
hostvars[host]['ansible_eth0']['ipv4']['address'] }} {% endfor %}
}
datacenter AM {
{% for host in groups['CL300'] %}
dc-node-address-port {{
hostvars[host]['ansible_eth0']['ipv4']['address'] }} 3000 {% endfor %}
But I'm getting this error when running the play:
TASK: [Create the CitrusLeaf config file] *********************
fatal: [cl801.domain.net] => {'msg': "'dict object' has no attribute
'ansible_eth0'", 'failed': True}
fatal: [cl801.domain.net] => {'msg': "'dict object' has no attribute
'ansible_eth0'", 'failed': True}
Does this have to do with how I setup the playbook?
James
James,
A few questions are ok, but I need you do some investigation of your
own too, else I'm going to start charging you
Think about why that host might not have that attribute, print out the
dictionaries (don't paste them back here, but read them and try to
understand them), and so on.
You can easily also test what facts a host supplies by:
ansible hostname -m setup
You clearly got the interface information for most of the hosts, but
perhaps this one doesn't have an eth0, and you were trying it on other
hosts before.
There are other facts to choose from, like the ipv4 address list, that
may be more appropriate.
--Michael