Work with Ansible facts. Get interface not active - interface

I need to configure an IP address for a new interface.
For this I want to get all the interfaces available on the server and find out which one is inactive.
I use the ansible_interfaces variable first to discover which interfaces exist. It depends on the existing interfaces (example: eth0 and lo), I will have access to the information with ansible_eth0 and ansible_lo
What I need to do later is to see the "active" parameter for each of its interfaces, so get the name of the interface that has that parameter to "false" and then use it to modify a file.
Example:
A server has 3 interfaces ens3 ens7 and lo. ens7 is incativa and I will use it to configure a new IP address. What I want is to obtain and save in a variable this value ens7 for later use.
How can I do this with Ansible?

Using this answer as reference, you can do the following task:
- set_fact:
ansible_eth: "{% set ansible_eth = ansible_eth|default([]) + [hostvars[inventory_hostname]['ansible_' + item]] %}{{ ansible_eth|list }}"
when: hostvars[inventory_hostname]['ansible_' + item]['type'] == 'ether' and hostvars[inventory_hostname]['ansible_' + item]['active'] == false
with_items:
- "{{ hostvars[inventory_hostname]['ansible_interfaces'] }}"
- debug:
msg: "Free device: {{ item.device }}"
with_items: "{{ ansible_eth }}"
This will select ether cards that are non-active.

Related

List all my hetzner server names and their IPv4 addresses - getting error

I'm trying to receive a list of all my server names and their IPs on Hetzner using ansible and hcloud module however I'm receiving the following error;
ERROR! couldn't resolve module/action 'hcloud'. This often indicates a misspelling, missing collection, or incorrect module path.
The error appears to be in '/home/melvmagr/repos/ansible/server-content/server-content.yml': line 8, column 7, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
tasks:
- name: List servers
^ here
Here is my YAML file;
---
- name: List Hetzner server names and IP addresses
hosts: servername_example
gather_facts: false
vars:
hcloud_token: "MY_HETZNER_API_TOKEN"
tasks:
- name: List servers
hcloud:
api_token: "MY_HETZNER_API_TOKEN"
state: present
command: server_list
register: server_list
- name: Print server names and IP addresses
debug:
msg: "Server {{ item.name }} has IP address {{ item.public_net.ipv4.ip }}"
loop: "{{ server_list.servers }}"
More info that could prove to be helpful:
❯ ansible --version
ansible [core 2.12.10]
config file = /home/melvmagr/repos/ansible/ansible.cfg
configured module search path = ['/home/melvmagr/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3/dist-packages/ansible
ansible collection location = /home/melvmagr/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/bin/ansible
python version = 3.8.10 (default, Nov 14 2022, 12:59:47) [GCC 9.4.0]
jinja version = 2.10.1
libyaml = True
This is my ansible.cfg file;
[defaults]
inventory=./inventories
host_key_checking = False
log_path=/var/tmp/ansible_history
timeout=300
I've also installed the following collections;
ansible-galaxy collection install hetzner.hcloud
❯ ls ~/.ansible/collections/ansible_collections/hetzner/hcloud/
CHANGELOG.rst COPYING FILES.json MANIFEST.json README.md changelogs meta plugins tests
Any help would be greatly appreciated. Thank you!
Managed to solve it by simplifying my playbook the following way;
---
- name: Get server information from Hetzner Cloud
hosts: myservername
gather_facts: false
tasks:
- name: Print server names and IP addresses
debug:
msg: "{{ inventory_hostname }} IP is {{ ansible_ssh_host }}"

Ansible IP Adress from Host to Variable and use in Playbook - Save Switch Config with Ansible

I want to save the startup and running config with ansible. My script works but only on one host. I need to change the name from the save file otherwise it will overwrite the old Configuration.
---
- hosts: switches
gather_facts: yes
vars:
ansible_network_os: icx
ansible_become: True
ansible_become_method: enable
tasks:
- name: Backup Config Files
icx_command:
commands:
- copy startup-config tftp 192.168.10.5 Ansible-startup-config.cfg
- copy running-config tftp 192.168.10.5 Ansible-running-config.cfg
Now I want to have the ip address, time and date in the name so that they will not be overwritten when I start the script again.
I think about something like this as filename:
192.168.9.13-2021-04-08-18:25-startup-config.cfg
or an consecutive number
How can I do this?
The rough idea below.
I'm not 100% sure facts gathered on ios populate ansible_default_ipv4. You will have to check that point and find the correct variable if needed. Note also you may have to run explicitly the icx_facts module to get all the info from your device.
You can run the following ad-hoc commands to browse all available facts and choose the correct one if ever:
ansible -i your_inventory some_host -m setup
ansible -i your_inventory some_host -m icx_facts
You can debug the ansible_date_time variable to see if an other key suits your needs better than below to create a time stamp. I reconstructed exactly the pattern in your question.
Of course, you need to gather facts for these vars to be available (gather_facts: true on your play meets that requirement).
And here is the sample task (untested, I don't have an ios device available for that)
- name: Backup Config Files
vars:
ip: "{{ ansible_default_ipv4.address }}"
stamp: "{{ ansible_date_time.date }}-{{ ansible_date_time.hour }}:{{ ansible_date_time.minute }}"
prefix: "{{ ip }}-{{ stamp }}"
icx_command:
commands:
- "copy startup-config tftp 192.168.10.5 {{ prefix }}-startup-config.cfg"
- "copy running-config tftp 192.168.10.5 {{ prefix }}-running-config.cfg"

How Exactly Does Ansible Parse Boolean Variables?

In Ansible, there are several places where variables can be defined: in the inventory, in a playbook, in variable files, etc. Can anyone explain the following observations that I have made?
When defining a Boolean variable in an inventory, it MUST be capitalized (i.e., True/False), otherwise (i.e., true/false) it will not be interpreted as a Boolean but as a String.
In any of the YAML formatted files (playbooks, roles, etc.) both True/False and true/false are interpreted as Booleans.
For example, I defined two variables in an inventory:
abc=false
xyz=False
And when debugging the type of these variables inside a role...
- debug:
msg: "abc={{ abc | type_debug }} xyz={{ xyz | type_debug }}"
... then abc becomes unicode but xyz is interpreted as a bool:
ok: [localhost] => {
"msg": "abc=unicode xyz=bool"
}
However, when defining the same variables in a playbook, like this:
vars:
abc: false
xyz: False
... then both variables are recognized as bool.
I had to realize this the hard way after executing a playbook on production, running something that should not have run because of a variable set to 'false' instead of 'False' in an inventory. Thus, I'd really like to find a clear answer about how Ansible understands Booleans and how it depends on where/how the variable is defined. Should I simply always use capitalized True/False to be on the safe side? Is it valid to say that booleans in YAML files (with format key: value) are case-insensitive, while in properties files (with format key=value) they are case-sensitive? Any deeper insights would be highly appreciated.
Variables defined in YAML files (playbooks, vars_files, YAML-format inventories)
YAML principles
Playbooks, vars_files, and inventory files written in YAML are processed by a YAML parser first. It allows several aliases for values which will be stored as Boolean type: yes/no, true/false, on/off, defined in several cases: true/True/TRUE (thus they are not truly case-insensitive).
YAML definition specifies possible values as:
y|Y|yes|Yes|YES|n|N|no|No|NO
|true|True|TRUE|false|False|FALSE
|on|On|ON|off|Off|OFF
Ansible docs confirm that:
You can also specify a boolean value (true/false) in several forms:
create_key: yes
needs_agent: no
knows_oop: True
likes_emacs: TRUE
uses_cvs: false
Variables defined in INI-format inventory files
Python principles
When Ansible reads an INI-format inventory, it processes the variables using Python built-in types:
Values passed in using the key=value syntax are interpreted as Python literal structure (strings, numbers, tuples, lists, dicts, booleans, None), alternatively as string. For example var=FALSE would create a string equal to FALSE.
If the value specified matches string True or False (starting with a capital letter) the type is set to Boolean, otherwise it is treated as string (unless it matches another type).
Variables defined through --extra_vars CLI parameter
All strings
All variables passed as extra-vars in CLI are of string type.
The YAML principles define the possible Boolean values that are accepted by Ansible. However after parsing only two values remain (true and false), these are valid in JSON too, so if you do some things with these values in Ansible, then true and false are good choices. Also the Ansible documentation states
Use lowercase ‘true’ or ‘false’ for boolean values in dictionaries if
you want to be compatible with default yamllint options.
#!/usr/bin/env ansible-playbook
---
- name: true or false?
hosts: all
gather_facts: false
tasks:
- name: "all these boolean inputs evaluate to 'true'"
debug:
msg: "{{ item }}"
with_items:
- true
- True
- TRUE
- yes
- Yes
- YES
- on
- On
- ON
- name: "all these boolean inputs evaluate to 'false'"
debug:
msg: "{{ item }}"
with_items:
- false
- False
- FALSE
- no
- No
- NO
- off
- Off
- OFF
The YAML principles define the possible Boolean values that are accepted by Ansible. However after parsing only two values remain (true and false), these are valid in JSON too, so if you do things with JSON in Ansible, then true and false are good choices. The best IMHO.
#!/usr/bin/env ansible-playbook
---
- name: true or false?
hosts: all
gather_facts: false
tasks:
- name: "all these boolean inputs evaluate to 'true'"
debug:
msg: "{{ item }}"
with_items:
- true
- True
- TRUE
- yes
- Yes
- YES
- on
- On
- ON
- name: "all these boolean inputs evaluate to 'false'"
debug:
msg: "{{ item }}"
with_items:
- false
- False
- FALSE
- no
- No
- NO
- off
- Off
- OFF

Ansible passing variables between host contexts

As the title says when I'd like to be able to pass a variable that is registered under one host group to another, but I'm not sure how to do that and I couldn't find anything relevant under the variable documentation http://docs.ansible.com/ansible/playbooks_variables.html
This is a simplified example of what I am trying to see. I have a playbook that calls many different groups and checks where a symlink points. I'd like to be able to report all of the symlink targets to console at the end of the play.
The problem is the registered value is only valid under the host group that it was defined in. Is there a proper way of exporting these variables?
---
- hosts: max_logger
tasks:
- shell: ls -la /home/ubuntu/apps/max-logger/active | awk -F':' '{print $NF}'
register: max_logger_old_active
- hosts: max_data
tasks:
- shell: ls -la /home/ubuntu/apps/max-data/active | awk -F':' '{print $NF}'
register: max_data_old_active
- hosts: "localhost"
tasks:
- debug: >
msg="The old max_logger build is {{ max_logger_old_active.stdout }}
The old max_data build is {{ max_data_old_active.stdout }}"
You don't need to pass anything here (you just need to access). Registered variables are stored as host facts and they are stored in memory for the time the whole playbook is run, so you can access them from all subsequent plays.
This can be achieved using magic variable hostvars.
You need however to refer to a host name, which doesn't necessarily match the host group name (e.g. max_logger) which you posted in the question:
- hosts: "localhost"
tasks:
- debug: >
msg="The old max_logger build is {{ hostvars['max_logger_host'].max_logger_old_active.stdout }}
The old max_data build is {{ hostvars['max_data_host'].max_data_old_active.stdout }}"
You can also write hostvars['max_data_host']['max_data_old_active']['stdout'].

Copy file to ansible host with custom variables substituted

I'm working on an ansible-playbook which should help to generate build agents for a continuous delivery pipeline. Among other issues, I'll need to install an oracle client on such an agent. I want to do something like
- name: "Provide response file"
copy: src=/custom.rsp dest=/opt/oracle
Within the custom.rsp file I've got some variables to be substituted. Normally, one could do it with a separate shell command like this:
- name: "Substitute Vars"
shell: "sed 's|<PARAMETER>|<VALUE>|g' -i /opt/oracle/custom.rsp"
I don't like it, though. There should be a more convinient way to do this. Anybody giving me a hint?
You want to be using a template rather than copying a static file.
Also, when using the copy or template modules, the dest parameter is a full path AND filename, not just a path. So if you want to end up with a copy of custom.rsp in the directory /opt/oracle then you need to do this:
- name: "Provide response file"
template: src=/custom.rsp dest=/opt/oracle/custom.rsp
I'm going to extend Bruce's answer with an example:
This is part of my inventory.yaml:
kafka_stage:
children:
kafka_with_zookeeper_stage:
kafka_only_stage:
vars:
zookeeper_hosts: "kafka-stage01:2181,kafka-stage02:2181,kafka-stage03:2181"
kafka_with_zookeeper_stage:
hosts:
kafka-stage01:
broker_id: 0
kafka-stage02:
broker_id: 1
vars:
services:
kafka:
zookeeper:
This is part of a configuration file:
# The id of the broker. This must be set to a unique integer for each broker.
broker.id={{ broker_id }}
# {{ zookeeper_hosts }}
advertised.listeners=PLAINTEXT://{{ ansible_host }}:9092
# {{ services }}
This command in a playbook:
- name: Copy to Host
ansible.builtin.template:
src: my_configfile.properties
dest: /tmp/hejsan.properties
Gave me this on the remote host kafka-stage02:
# The id of the broker. This must be set to a unique integer for each broker.
broker.id=1
# kafka-stage01:2181,kafka-stage02:2181,kafka-stage03:2181
advertised.listeners=PLAINTEXT://kafka-stage02:9092
# {'kafka': None, 'zookeeper': None}