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

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 }}"

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 - set_fact syntax issue

In the below playbook, can someone please tell me what is wrong with the syntax of the final set_fact statement. If i explicitly specify the hostname R9 (as per the first set_fact), then it works without issue. But if I assign a variable to have a value of R9, and then use this in the final set_fact statement, I get the error shown below. Argh.
---
- hosts: all
gather_facts: no
vars:
ansible_network_os: ios
ansible_connection: network_cli
tasks:
- ios_command:
commands: show ip arp
register: results
- set_fact:
some_var: "{{ hostvars['R9'].results }}"
- set_fact:
hostname: "R9"
- set_fact:
another_var: "{{ hostvars['{{hostname}}'].results }}"
- debug:
var=some_var
- debug:
var=another_var
Error:
fatal: [R7]: FAILED! =>
msg: |-
The task includes an option with an undefined variable. The error was: "hostvars['{{hostname}}']" is undefined
The error appears to be in '/root/ansible/Rapid/testsetfact.yml': line 20, column 6, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
- set_fact:
^ here
fatal: [R9]: FAILED! =>
msg: |-
The task includes an option with an undefined variable. The error was: "hostvars['{{hostname}}']" is undefined
The error appears to be in '/root/ansible/Rapid/testsetfact.yml': line 20, column 6, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
- set_fact:
^ here
you can use the inventory_hostname for your purpose:
- set_fact:
another_var: "{{ hostvars[inventory_hostname].results }}"

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 }}" == ""

How to check any services exists by Ansible?

I want to check the service exists in the terminal host.
So, I just did the playbook as below.
---
- hosts: '{{ host }}'
become: yes
vars:
servicename:
tasks:
- name: Check if Service Exists
stat: 'path=/etc/init.d/{{ servicename }}'
register: servicestatus
with_items: '{{ servicename }}'
- name: Show service service status
debug:
msg: '{{ servicename }} is exists.'
with_items: '{{ servicename }}'
when: servicestatus.stat.exists
Then, I try to execute this playbook to my host that was running Nginx already as below.
ansible-playbook cheknginxservice.yml -i /etc/ansible/hosts -e 'host=hostname' -e 'servicename=nginx'
And I got the error like this.
FAILED! => {"failed": true, "msg": "The conditional check 'servicestatus.stat.exists' failed. The error was: error while evaluating conditional (servicestatus.stat.exists): 'dict object' has no attribute 'stat'\n\nThe error appears to have been in '/home/centos/cheknginxservice.yml': line 13, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n with_items: '{{ servicename }}'\n - name: Show service servicestatus\n ^ here\n"}
to retry, use: --limit #/home/centos/cheknginxservice.retry
So, I think the problem is about stat module when using the condition involved.
Why are you using with_items? You plan to pass multiple services? It matters because the results will be a list if you use with_items. Just remove with_items and it will work. If you want to pass multiple services, then you have to loop through with_items and use item instead of servicename.
- name: Check if Service Exists
stat: 'path=/etc/init.d/{{ servicename }}'
register: servicestatus
- name: Show service service status
debug:
msg: '{{ servicename }} is exists.'
when: servicestatus.stat.exists
There is no native way in Ansible to check the status of a service. You can use the shell module. Notice I used sudo. Your case may be different.
- name: check for service status
shell: sudo service {{ servicename }} status
ignore_errors: true
register: servicestatus
- name: Show service service status
debug:
msg: '{{ servicename }} exists.'
when: servicestatus.rc | int == 0

The error was: 'dict object' has no attribute 'ansible_facts

I am iterating over yml file and filtering and keeping those microservice metadata in the list which is in the command line argument passed
ansible-playbook -i inventory/inventory sp-deployer.yml --ask-vault-pass --extra-vars '{"microservices_list":[iwan,csrservice]}'
Finally I need these three value from the yml file based on the criteria mentioned above. I have created ansible sp-deployer.yml for this purpose. I have used set_facts for creating dynamic list. First list works fine but the moment I create second one it fails.
name: "ms_service"
port: "830"
streams: "noti,jk-noti"
vars.yml
version: 1
name: user
jobs:
ns1:
ip: "1.1.1.1"
ns_version: "4.2"
f_packs:
- f-pack-1:
name: "pack1"
microservices:
- microservice-1:
name: "ms_service"
port: "830"
streams: "noti,jk-noti"
- microservice-2:
name: "ms_service1"
port: "830"
streams: "noti1,jk-noti1"
- f-pack-2:
name: "pack4"
microservices:
- microservice-1:
name: "ms_service3"
port: "830"
streams: "noti,jk-noti3"
- microservice-2:
name: "ms_service4"
port: "830"
streams: "noti,jk-noti4"
- microservice-3:
name: "ms_service5"
port: "830"
streams: "noti,jk-noti5"
Script:sp-deployer.yml
---
- hosts: localhost
vars_files:
- ./vars.yml
sudo: yes
tasks:
- name: Reading vars.yml file and preparing list of microservice with its metadata
set_fact: foo_item="{{ item.1 }}"
register: result
with_subelements:
- "{{ jobs.ns1.f_packs }}" ###item.0
- microservices ###item.1
- name: make first list
set_fact: foo="{{ result.results | map(attribute='ansible_facts.foo_item') | list }}"
- name: print register
debug: msg="{{ item }}" verbosity=3
with_items:
- "{{ foo }}"
- name: Filtering micro service list with match found from command line input
when: item[0].name == item[1]
set_fact: foo_item1="{{ item.0 }}"
register: result_final
with_nested:
- "{{ foo }}"
- "{{ microservices_list }}"
- name: make a list
set_fact: foo1="{{ result_final.results | map(attribute='ansible_facts.foo_item1') | list }}"
ERROR
TASK [make a list] *************************************************************
fatal: [localhost]: FAILED! => {"failed": true, "msg": "the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: 'dict object' has no attribute 'ansible_facts'\n\nThe error appears to have been in '/home/user/ansible/sp-deployer1.yml': line 40, 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: make a list\n ^ here\n"}
to retry, use: --limit #/home/user/ansible/sp-deployer1.retry
PLAY RECAP *********************************************************************
localhost : ok=4 changed=0 unreachable=0 failed=1
Friendly advice: always check registered variables with debug if you bump on such errors.
The reason for your error is that set_fact don't yield ansible_facts dict if the loop iteration is skipped.
And I see you have when statement in your loop.
To overcome this error, you should select only those loop iterations, that have ansible_facts dict defined:
- name: make a list
set_fact: foo1="{{ result_final.results | selectattr('ansible_facts','defined') | map(attribute='ansible_facts.foo_item1') | list }}"

Resources