Cannot get customized facts when pushing with "--check"

83 views
Skip to first unread message

Dong Guo

unread,
Dec 18, 2014, 10:35:27 PM12/18/14
to ansible...@googlegroups.com
Hi gentlemen,
We are using the Ansible to manage many servers, and we like the dry run mode which with parameters "--check" and "--diff". We always run with these parameters first to verify that if the changes will be made correctly.
The customized facts are very helpful, to generate some dynamic facts. But the trouble is, when we ran with "--check", ansible skipped the customized module.
So we can't use the dry run to check before we push if there are some customized facts used in templates files.
Is there a way to fix this or work around?

Here are the detailed informations:

[root@idc1-server1 ansible]#  cat roles/myfacts/tasks/main.yml
---
- name: run myfacts module to get customized facts
  myfacts: get_facts=yes

- name: update file with the customized facts
  template: src=myfacts.txt.j2 dest=/tmp/myfacts.txt

[root@idc1-server1 ansible]#  cat roles/myfacts/templates/myfacts.txt.j2
ansible_private_ipv4_address : {{ ansible_private_ipv4_address }}

[root@idc1-server1 ansible]# cat library/heylinux/myfacts
#!/usr/bin/python

import sys
import json
import shlex
import commands
import re

def get_ansible_private_ipv4_address():
    iprex = "(^192\.168)|(^10\.)|(^172\.1[6-9])|(^172\.2[0-9])|(^172\.3[0-1])"
    output = commands.getoutput("""/sbin/ifconfig |grep "Link encap" |awk '{print $1}' |grep -wv 'lo'""")
    nics = output.split('\n')
    for i in nics:
        ipaddr = commands.getoutput("""/sbin/ifconfig %s |grep -w "inet addr" |cut -d: -f2 | awk '{print $1}'""" % (i))
        if re.match(iprex,ipaddr):
            ansible_private_ipv4_address = ipaddr
            return ansible_private_ipv4_address

ansible_facts_dict = {
        "changed" : False,
        "ansible_facts" : {
            }
    }

args_file = sys.argv[1]
args_data = file(args_file).read()

arguments = shlex.split(args_data)
for arg in arguments:
    if "=" in arg:
        (key, value) = arg.split("=")
        if key == "get_facts" and value == "yes":
            ansible_private_ipv4_address = get_ansible_private_ipv4_address()
            ansible_facts_dict['ansible_facts']['ansible_private_ipv4_address'] = ansible_private_ipv4_address

print json.dumps(ansible_facts_dict)

[root@idc1-server1 ansible]# cat myfacts.yml
---
- hosts: all
  roles:
  - myfacts

[root@idc1-server1 ansible]#ansroot myfacts.yml -i hosts.idc1 --limit idc1-server1
PLAY [all] ********************************************************************

GATHERING FACTS ***************************************************************
ok: [idc1-server1]

TASK: [myfacts | run myfacts module to get customized facts] **************
ok: [idc1-server1]

TASK: [myfacts | update file with the customized facts] *********************
changed: [idc1-server1]

PLAY RECAP ********************************************************************
idc1-server1                  : ok=3    changed=1    unreachable=0    failed=0

[root@idc1-server1 ansible]#ansroot myfacts.yml -i hosts.idc1 --limit idc1-server1 --check --diff
PLAY [all] ********************************************************************

GATHERING FACTS ***************************************************************

ok: [idc1-server1]

TASK: [myfacts | run myfacts module to get customized facts] **************
skipping: [idc1-server1]

TASK: [myfacts | update file with the customized facts] *********************
fatal: [idc1-server1] => {'msg': "One or more undefined variables: 'ansible_private_ipv4_address' is undefined", 'failed': True}
fatal: [idc1-server1] => {'msg': "One or more undefined variables: 'ansible_private_ipv4_address' is undefined", 'failed': True}

FATAL: all hosts have already failed -- aborting

PLAY RECAP ********************************************************************
           to retry, use: --limit @/root/myfacts.retry

idc1-server1                  : ok=1    changed=0    unreachable=1    failed=0

Brian Coca

unread,
Dec 19, 2014, 10:09:37 AM12/19/14
to ansible...@googlegroups.com
You need to let ansible know your module supports check mode, this is
done by instantiating the module class and adding
'supports_check_mode=True'.

--
Brian Coca

Dong Guo

unread,
Dec 25, 2014, 5:44:14 AM12/25/14
to ansible...@googlegroups.com
Thanks Brian Coca!
I fixed the issue by updating my custom module as follow:
#!/usr/bin/python

import json
import commands
import re

def get_ansible_private_ipv4_address():
    iprex = "(^192\.168)|(^10\.)|(^172\.1[6-9])|(^172\.2[0-9])|(^172\.3[0-1])"
    output = commands.getoutput("""/sbin/ifconfig |grep "Link encap" |awk '{print $1}' |grep -wv 'lo'""")
    nics = output.split('\n')
    for i in nics:
        ipaddr = commands.getoutput("""/sbin/ifconfig %s |grep -w "inet addr" |cut -d: -f2 | awk '{print $1}'""" % (i))
        if re.match(iprex,ipaddr):
            ansible_private_ipv4_address = ipaddr
            return ansible_private_ipv4_address

def main():
    global module
    module = AnsibleModule(
        argument_spec = dict(
            get_facts=dict(default="yes", required=False),
        ),
        supports_check_mode = True,
    )

    ansible_facts_dict = {
        "changed" : False,
        "ansible_facts": {
            }
    }

    if module.params['get_facts'] == 'yes':
        ansible_private_ipv4_address = get_ansible_private_ipv4_address()
        ansible_facts_dict['ansible_facts']['ansible_private_ipv4_address'] = ansible_private_ipv4_address

    print json.dumps(ansible_facts_dict)

from ansible.module_utils.basic import *
from ansible.module_utils.facts import *
main()
Reply all
Reply to author
Forward
0 new messages