Ansible variable check in playbook - ansible

I have in the vars file the databases configured as the following:
project_dbs:
- { project_db_name: "project1", project_db_user: "user", tenon_db_password: "pass" }
- { project_db_name: "project2", project_db_user: "dev", tenon_db_password: "pass2"}
- { project_db_name: "project3", project_db_user: "{{datadog_mysql_username}}", project_db_password: "{{datadog_mysql_password}}" }
Now in a playbook I have a check:
- name: copy config.json template to server
tags: provision
template: src=config.json dest={{ project_root }}/config
when: item.project_db_name == "project2"
with_items: project_dbs
But the when check is failing. Any idea how to make that work?
The error message looks like this:
fatal: [test]: FAILED! => {"failed": true, "msg": "The conditional check 'item.projects_db_name == \"project2\"' failed. The error was: error while evaluating conditional (item.projects_db_name == \"project2\"): 'unicode object' has no attribute 'projects_db_name'\n\nThe error appears to have been in '/var/lib/jenkins/project/ansible/roles/project2/tasks/main.yml': line 28, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: copy config.json template to server\n ^ here\n"}

You use an outdated syntax called "bare variables" in with_items:
with_items: project_dbs
This way your item becomes a string object with the value of project_dbs and Ansible reports it doesn't have the attribute ("'unicode object' has no attribute 'projects_db_name'").
In Ansible 2.x you should quote variables in the following way:
with_items: "{{ project_dbs }}"
That said, your task makes no use of the values from the loop. The following will have the same effect:
- name: copy config.json template to server
tags: provision
template: src=config.json dest={{ project_root }}/config

Instead of using when you could just filter the list of project_dbs so it looks like this:
- name: "copy config.json template to server"
tags: provision
template: src=config.json dest={{ project_root }}/config
with_items: "{{ project_dbs | selectattr("project_db_name", "project2") }}"

Related

azure-network_interface says variable is undefined

We switched to ansible 2.10
Before it was azure_rm_networkinterface_facts (working) now is azure_rm_networkinterface_info
- name: "Get facts for network interface by it's name"
azure_rm_networkinterface_facts:
resource_group: "{{ target_resourcegroup }}"
name: "{{ target_nic_name }}"
- name: "Define private IP address"
set_fact:
private_ip_address: "{{ ansible_facts | json_query(query) }}"
vars:
query: "azure_networkinterfaces[0].properties.ipConfigurations[0].properties.privateIPAddress"
when: azure_networkinterfaces|length > 0
Error I get is:
4 TASK [azure_preconditions : Define private IP address] *************************
00:01:38.844 [0;31mfatal: [40.118.86.58]: FAILED! => {"msg": "The conditional check 'azure_networkinterfaces|length > 0' failed. The error was: error while evaluating conditional (azure_networkinterfaces|length > 0): 'azure_networkinterfaces' is undefined\n\nThe error appears to be in '/var/lib/jenkins/workspace/PA-28544-ansible-version-upgrade/roles/azure_preconditions/tasks/main.yml': line 143, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: \"Define private IP address\"\n ^ here\n"}[0m
00:01:38.844
azure_networkinterfaces seems to be a return value of azure_rm_networkinterface_facts so it's normal that it doesn't exist...
I'd write a playbook like this:
- name: "Get facts for network interface by it's name"
azure_rm_networkinterface_facts:
resource_group: "{{ target_resourcegroup }}"
name: "{{ target_nic_name }}"
register: output
I suggest you debug the output variable to check your return values. I don't know the version of Azure you are using and a lot of changes can exist depending on it.
- name: "Display return value"
debug:
msg: "{{ output }}"
You could play with output.azure_networkinterfaces or output.networkinterfaces
Following the last documentation, its seems azure_rm_networkinterface_fact is deprecated, replaced by azure_rm_networkinterface_info
azure_rm_networkinterface_info

Ansible: how to get dynamic service state with a variable within another

I'm new to Ansible and trying to get a service state where the service name is dynamic and set by set_fact before in the playbook.
How can you build a variable within another variable?
I wish I could use something like that to display my service state :
{{ ansible_facts.services['{{ servicename }}'].state }}
But well it doesn't work.
So I tried this way with vars :
- name: set service name
ansible.builtin.set_fact:
servicename: "'myservice'"
when: ansible_distribution_major_version == "7"
- name: print service state
debug: msg={{ vars['ansible_facts.services[' + servicename + '].state'] }}
vars:
servicename: "{{ servicename }}"
I got the following error :
fatal: [myhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute u\"ansible_facts.services['myservice'].state\"\n\nThe error appears to be in '/etc/ansible/playbook/myplaybook.yaml': line 20, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - name: print service state\n ^ here\n"}
When the following works just fine :
- name: print service state
debug:
msg: "{{ ansible_facts.services['myservice'].state }}"
Inside a {{ … }} block, you can access the variables directly. And from my point of view, you can leave the ansible_facts out, as well as the variable assignment in the second task.
This will do what you want (and as Zeitounator already wrote):
- hosts: localhost
vars:
services:
myservice:
state: foo
tasks:
- name: set service name
ansible.builtin.set_fact:
servicename: "myservice"
- name: print service state
debug:
msg: "{{ services[servicename].state }}"

Ansible: how to check if a variable is being loaded in a playbook?

I'm trying to write a playbook that will load vars from a group vars file then check if a variable exists
my playbook is like this:
---
- hosts: "{{ target }}"
roles:
- app
tasks:
- name: alert if variable does not exist
fail:
msg: "{{ item }} is not defined"
when: "{{ item }}" is not defined
with_items:
- country
- city
- street
...
My inventory file contains
[app]
ansible-slave1
ansible-slave2
[db]
ansible-db
[multi:children]
app
db
and I have the roles/app/vars/main.yml containing
country: "France"
city: "Paris"
What I was expecting is the playbook to output "street is not defined" but I have a syntax issue I can't resolve
[vagrant#ansible-master vagrant]$ ansible-playbook --inventory-file=ansible_master_hosts test_variables.yml --extra-vars "target=ansible-slave1" --syntax-check
ERROR! Syntax Error while loading YAML.
The error appears to have been in '/vagrant/test_variables.yml': line 10, column 24, but may be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
msg: "{{ item }} is not defined"
when: "{{ item }}" is not defined
^ here
We could be wrong, but this one looks like it might be an issue with
missing quotes. Always quote template expression brackets when they
start a value. For instance:
with_items:
- {{ foo }}
Should be written as:
with_items:
- "{{ foo }}"
I'd be happy with any hints.
Thanks
You have "" in invalid place of "when" statement. This should be like this:
msg: "{{ item }} is not defined"
when: "{{ item }} is not defined"
So the output will be:
failed: [hostname] (item=street) => {"changed": false, "item": "street", "msg": "street is not defined"}
there is on open issue conditional is defined fails to capture undefined var .
as a workaround I'd suggest to change the where condition to the following:
when: "{{ item }}" == ""

ansible AttributeError: 'list' object has no attribute 'startswith'

I am running ansible and trying to make this task work, it fails with this error:
An exception occurred during task execution. To see the full
traceback, use -vvv. The error was: AttributeError: 'list' object has
no attribute 'startswith' fatal: [test-1]: FAILED! =>
{"failed": true, "msg": "Unexpected failure during module execution.",
"stdout": ""} msg: Unexpected failure during module execution.
The code is:
- name: Register env Type
shell: facter configured_setup
register: setup
- name: foo tasks
shell: {{some_script}} -t -a {{hosts}} -i {{inventory_hostname}}
register: test
when: setup.stdout == "something"
- name: fetch group_vars
fetch:
src:
- { "{{ item }}", when: setup.stdout == "something" }
dest: "{{group_vars}}"
flat: yes
with_items:
- "{{ test.stdout_lines[0] }}"
- "{{ test.stdout_lines[1] }}"
"fetch group_vars" is the task that always fails, any idea how this can work?
What I am trying to do is add more source files to fetch from different setvers.
So I want to have more lines under "src:", saying - { filename, when setup.stdout =="something else" }
The full error is:
An exception occurred during task execution. The full traceback is:
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/ansible/executor/task_executor.py", line 96, in run
item_results = self._run_loop(items)
File "/usr/lib/python2.7/site-packages/ansible/executor/task_executor.py", line 252, in _run_loop
res = self._execute(variables=task_vars)
File "/usr/lib/python2.7/site-packages/ansible/executor/task_executor.py", line 446, in _execute
result = self._handler.run(task_vars=variables)
File "/usr/lib/python2.7/site-packages/ansible/plugins/action/fetch.py", line 62, in run
source = self._remote_expand_user(source)
File "/usr/lib/python2.7/site-packages/ansible/plugins/action/init.py", line 460, in _remote_expand_user
if not path.startswith('~'): # FIXME: Windows paths may start with "~ instead of just ~
AttributeError: 'list' object has no attribute 'startswith'
fatal: [test-1]: FAILED! => {"failed": true, "msg":
"Unexpected failure during module execution.", "stdout": ""} msg:
Unexpected failure during module execution.
The ansible documentation clearly states that fetch, fetches a file, not a list of files. Although one can program an application to deal with both a scalar and a sequence loaded from a YAML document, that is not automatic and would almost certainly have been reflected in the documentation.
Since you already have a sequence at a higher level, just extend that.
- name: Register env Type
shell: facter configured_setup
register: setup
- name: transparency tasks
shell: {{some_script}} -t -a {{hosts}} -i {{inventory_hostname}}
register: test
when: setup.stdout == "something"
- name: fetch group_vars
fetch:
src: { "{{ item }}", when: setup.stdout == "something" }
dest: "{{group_vars}}"
flat: yes
with_items:
- "{{ test.stdout_lines[0] }}"
- "{{ test.stdout_lines[1] }}"
- name: fetch group_vars2
fetch:
src: { filename, when setup.stdout =="something else" }
dest: "{{group_vars}}"
flat: yes
with_items:
- "{{ test.stdout_lines[0] }}"
- "{{ test.stdout_lines[1] }}"
You might be able to reduce the repetitiveness somewhat by using YAML's anchor and merge:
- name: Register env Type
shell: facter configured_setup
register: setup
- name: transparency tasks
shell: {{some_script}} -t -a {{hosts}} -i {{inventory_hostname}}
register: test
when: setup.stdout == "something"
- &fetchtask
name: fetch group_vars
fetch: &fetchsrc
src: { "{{ item }}", when: setup.stdout == "something" }
dest: "{{group_vars}}"
flat: yes
with_items:
- "{{ test.stdout_lines[0] }}"
- "{{ test.stdout_lines[1] }}"
- <<: *fetchtask
name: fetch group_vars2
fetch:
<<: *fetchsrc
src: { filename, when setup.stdout =="something else" }
Ansible probably expands the {{...}} before handing the document to the YAML parser, otherwise the value for shell in the "transparency task" would throw an error. But you should probably still quote that like you do with the value for dest
So I ended up doing this (which is working):
- name: fetch group_vars test
fetch:
src: "{{ item }}"
dest: "{{group_vars}}"
flat: yes
with_items:
- "{{ test.stdout_lines[0] }}"
- "{{ test.stdout_lines[1] }}"
when: setup.stdout == "something" and {{something_else}} == True
I also noticed that there might be a bug in ansible related to registers.
while using the "when" statement, even if the condition is not met, the register statement takes affect:
- name: test tasks something enabled
shell: /tmp/{{populate_script}} -u -a {{hosts}} -r
register: variable
when: setup.stdout == "test" and something == True
- name: test tasks something disabled
shell: /tmp/{{populate_script}} -u -a {{hosts}}
register: variable
when: setup.stdout == "test" and something == False
only one of these conditions will be met, in case the first one is met the second condition will override "variable"

ansible reading variable from json file

i am new to ansible world. trying to providing all variable from json file, but its not accepting. it shows and error variable undefined
below is my json file
{
"Tomcat":{
"SHPN":"8905",
"HTPN":"8980",
"SSPN":"8943",
"AJPN":"8909",
"Server":"test.example.com",
"JENKINS_HOME":"/apps/tech/jenkins/jenkins-configuration",
"PName":"Tomcat-Installation",
"IName":"ansible_test",
"IUID":"jbosscfg",
"IGID":"staff",
"IDEPT":"tech",
"IRECPT":"test#example.com"
}
}
below is my playbook
---
-
gather_facts: false
hosts: "{{Server}}"
tasks:
-
ignore_errors: true
name: "find no of Tomcat Instance available on the Server"
copy:
src: "{{ JENKINS_HOME }}/workspace/{{ PName }}/instance/"
dest: /apps/tech/{{IName}}
group: "{{IGID}}"
owner: "{{IUID}}"
mode: 0755
-
replace: "dest='/apps/tech/{{IName}}/scripts/set_env.sh' regexp='<DEPARTMENT NAME>' replace='{{IDEPT}}'"
-
replace: "dest='/apps/tech/{{IName}}/scripts/set_env.sh' regexp='<RECIPIENT>' replace='{{IRECPT}}'"
-
replace: "dest='/apps/tech/{{IName}}/scripts/set_env.sh' regexp='<TOMCAT INSTANCE NAME>' replace='{{IName}}'"
-
replace: "dest='/apps/tech/{{IName}}/scripts/set_env.sh' regexp='<USER ID>' replace='{{IUID}}'"
-
name: "Ansible Template Example"
template:
src: tomcat_server.j2
dest: /apps/tech/{{IName}}/conf/server.xml
mode: 0777
i am below while executing the ansible playbook - error says variable undefined
test.example.com:~/final:$ ansible-playbook configure-tomcat-instance.yml --extra-vars "#test.json"
ERROR! the field 'hosts' has an invalid value, which appears to include a variable that is undefined. The error was: 'Server' is undefined
The error appears to have been in '/home/jbosscfg/final/configure-tomcat-instance.yml': line 3, column 3, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
-
gather_facts: false
^ here
You refer variables as if they are at the top level, whereas they are under Tomcat key.
Use hosts: "{{Tomcat.Server}}" or reformat your json file to eliminate Tomcat level.

Resources