Ansible way of replacing a line in config - ansible

I have a json as follows:
{
"bootstrap": true,
"server": true,
"datacenter": "aws",
"data_dir": "/var/consul",
"log_level": "INFO",
"enable_syslog": true
}
This is on 3 servers which are in ansible inventory file as
[consul]
10.0.0.1
10.0.0.2
10.0.0.3
Now to make the nodes join the cluster i will have to actually add the following config line as well
"start_join": ["ip_of_other_node_1", "ip_of_other_node_2"]
and this will go on each of the 3 servers
So basically it means if 10.0.0.1 is one of those nodes in cluster, it's config will look like
{
"bootstrap": true,
"server": true,
"datacenter": "aws",
"data_dir": "/var/consul",
"log_level": "INFO",
"enable_syslog": true,
"start_join": ["10.0.0.2","10.0.0.3"]
}
I am trying to this via ansible as follows:
- name: Add the ip's of other servers to join cluster
lineinfile:
path: /etc/consul.d/server/config.json
regexp: '^"enable_syslog"'
insertafter: '^"enable_syslog"'
line: '"start_join": ["{{ groups['consul'][1] }}", "{{ groups['consul'][2] }}"]'
when: inventory_hostname == '{{ groups['consul'][0] }}'
Which is not really helping me out saying syntax error at line: , i am not sure what is the best way to achieve something like this via ansible and also what how to tackle the case when i increase the servers in inventory.

You can use the Template module to replace the config file on your servers, instead of changing it in place with the regex. This way you can add a task to generate a new config file with the start_join field containing the elements of your hosts file (or any other and more complex configuration) using regular jinja2 templates.

Related

Ansible register variable from facts output

I'm using Ansible playbook to get information about the server's hardware internals through iDrac controller. It is performed by 3rd party module, which uses API to connect to the device.
I get server's internals info (controllers, disks, CPU information, etc.) by running the task. And I would like to register some variables from such output (the output is just shortened by dots).
I kept the main structure of output, to make it clear:
ok: [rac1] => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"invocation": {
"module_args": {
"ca_path": null,
"idrac_ip": "192.168.168.100",
"idrac_password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"idrac_port": 443,
...
}
},
"msg": "Successfully fetched the system inventory details.",
"system_info": {
"BIOS": [
{
"BIOSReleaseDate": "09/14/2022",
"FQDD": "BIOS.Setup.1-1",
…
}
],
"CPU": [
{
"CPUFamily": "Intel(R) Xeon(TM)",
"Characteristics": "64-bit capable",
"CurrentClockSpeed": "2.1 GHz",
…
},
{
"CPUFamily": "Intel(R) Xeon(TM)",
"Characteristics": "64-bit capable",
…
}
],
"Controller": [
{
"Bus": "67",
"CacheSize": "8192.0 MB",
"DeviceDescription": "RAID Controller in SL 3",
"FQDD": "RAID.SL.3-1",
"Key": "RAID.SL.3-1",
…
},
I need to get only couple values from output (PCI slot num where RAID controller is located):
"DeviceDescription": "RAID Controller in SL 3",
"Key": "RAID.SL.3-1"
But I have no clue, which example from documentation can I use to register value to variable.
Considering this is a third party module. The task execution is very slow, so it is not so easy for me to play with it as much as possible.
Could somebody suggest me please, which direction should I dig? I'm not a big expert in Ansible yet.
My role's tasks are following below.
I tried to get nested values using debug task(just to figure out key which I need to register), like this, but no luck:
### Get inventory key:value pairs and trying to save certain value to variable ###:
- name: Get Inventory
dellemc.openmanage.idrac_system_info:
idrac_ip: "{{ idrac_ip }}"
idrac_user: "{{ idrac_user }}"
idrac_password: "{{ idrac_password }}"
validate_certs: False
register: ansible_facts[system_info][Controller][FQDD].result
### Trying to show my saved variable in this task ###
- name: print registered value
debug:
var: RAID slot is at "{{ result }}"
verbosity: 4
I get this message after launching playbook:
"msg": "Unsupported parameters for (dellemc.openmanage.idrac_system_info) module: register. Supported parameters include: idrac_ip, timeout, idrac_user, ca_path, idrac_port, validate_certs, idrac_password (idrac_pwd)."
Since you are providing already valid output, how do have generated that? How was it "printed"?
A minimal example playbook
---
- hosts: rac1
become: false
gather_facts: false
vars:
result:
system_info: {
"BIOS": [
{
"BIOSReleaseDate": "09/14/2022",
"FQDD": "BIOS.Setup.1-1"
}
],
"CPU": [
{
"CPUFamily": "Intel(R) Xeon(TM)",
"Characteristics": "64-bit capable",
"CurrentClockSpeed": "2.1 GHz"
},
{
"CPUFamily": "Intel(R) Xeon(TM)",
"Characteristics": "64-bit capable"
}
],
"Controller": [
{
"Bus": "67",
"CacheSize": "8192.0 MB",
"DeviceDescription": "RAID Controller in SL 3",
"FQDD": "RAID.SL.3-1",
"Key": "RAID.SL.3-1"
}
]
}
tasks:
- name: Show Facts
debug:
msg: "{{ result.system_info.Controller }}"
will result already into the expected output of
TASK [Show Facts] *****************************
ok: [rac1] =>
msg:
- Bus: '67'
CacheSize: 8192.0 MB
DeviceDescription: RAID Controller in SL 3
FQDD: RAID.SL.3-1
Key: RAID.SL.3-1
Regarding
which example from documentation can I use to register value to variable.
you may read about Registering variables. For registering results, even for 3rd-party or Custom Modules the structure will be
- name: Task
module_name:
module_parameter: values
register: variable_name
That's why you get an syntax error
Unsupported parameters for (dellemc.openmanage.idrac_system_info) module: register.
about the incorrect indention. Therefore try first
- name: Get Inventory
dellemc.openmanage.idrac_system_info:
idrac_ip: "{{ idrac_ip }}"
idrac_user: "{{ idrac_user }}"
idrac_password: "{{ idrac_password }}"
validate_certs: False
register: inventory
- name: Show Inventory
debug:
msg: "{{ inventory }}"
to get familiar with the result set and data structure.
Further documentation which might help are Return Values and idrac_system_info module – Get the PowerEdge Server System Inventory.

Ansible: YAML inventory for staging / production hosts

I can't setup inventory which will be easy and useful in yml format for Ansible Playbook :(
For example:
all:
children:
db:
children:
production:
hosts:
1.1.1.1:
staging:
hosts:
11.11.11.11:
web:
children:
production:
hosts:
2.2.2.2:
staging:
hosts:
22.22.22.22:
So, I have two playbooks with:
playbook-db.yml
...
hosts:
- db
and playbook-web.yml
...
hosts:
- db
And I want to use this inventory like:
andible-playbook -D playbook-db.yml --limit=staging
I am expecting that my playbook will be used only db and staging hosts, but playbook is applying for all staging hosts: 11.11.11.11 and 22.22.22.22 (but I am expecting 11.11.11.11 only) :(
How I can realize it correctly?
It seems you have a misunderstanding about the inventory file, since ansible is doing as you described
ansible-inventory -i your-posted-file.yml --list
emits
{ ...
"all": {
"children": [
"db",
"ungrouped",
"web"
]
},
"db": {
"children": [
"production",
"staging"
]
},
"production": {
"hosts": [
"1.1.1.1",
"2.2.2.2"
]
},
"staging": {
"hosts": [
"11.11.11.11",
"22.22.22.22"
]
}
showing that the db group has all members of production and staging, but staging has hosts "11.11.11.11", "22.22.22.22" just as you described
I think perhaps you were conflating the yaml indentation with membership, but that's not how ansible inventories work.
What is far more likely is that you'd want a db-staging and db-production group, for the case you described where you want only db hosts that are staging, leaving the db group to mean every db member

Ansible DellOS6 Config Backup

EDIT: After some research, I wonder if this may be related to the on_become() function as described in this post? https://github.com/Dell-Networking/ansible-dellos-examples/issues/12
I am trying to backup our current configurations on our Dell 2048p switches, running OS6. No matter what I set the timeout to (using persistent_connection in ansible.cfg), it still errors out. I have checked the logs on the switch and it gets both the show ver and show running-config commands, however its just not making it back. I have looked at the Networking and Troubleshooting guide, but am having trouble getting a proper error. Does anyone have this working, or spot anything I can change?
Version
ansible 2.9.5
config file = /etc/ansible/ansible.cfg
configured module search path = ['/home/me/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/local/lib/python3.6/dist-packages/ansible
executable location = /usr/local/bin/ansible
python version = 3.6.9 (default, Nov 7 2019, 10:44:02) [GCC 8.3.0]
Playbook
-
name: Show ver
hosts: Dell
connection: network_cli
gather_facts: yes
tasks:
-
name: "Get Dell EMC OS6 Show version"
dellos6_command:
commands: ['show version']
register: show_ver
-
name: "Backup config file locally"
dellos6_config:
backup: yes
backup_options:
dir_path: "/mnt/c/Users/me/Documents/Programming Projects/netBackupPlaybooks"
filename: "{{ inventory_hostname }}"
authorize: yes
register: backup_dellso6_location
when: ansible_network_os == 'dellos6'
- debug: var=show_ver
- debug: var=backup_dellos6_location
Inventory
[Dell]
sw1 ansible_host=10.10.10.10 ansible_ssh_extra_args='-o StrictHostKeyChecking=no' ansible_ssh_common_args='-o StrictHostKeyChecking=no' ansible_network_os=dellos6 ansible_connection=network_cli ansible_become_method=enable ansible_become_password=admin ansible_user=admin ansible_password=admin
sw2 ansible_host=10.10.10.11 ansible_ssh_extra_args='-o StrictHostKeyChecking=no' ansible_ssh_common_args='-o StrictHostKeyChecking=no' ansible_network_os=dellos6 ansible_connection=network_cli ansible_become_method=enable ansible_become_password=admin ansible_user=admin ansible_password=admin
Command
sudo ansible-playbook -i inventory.ini DellPB.yaml -vvvv
Error
The full traceback is:
WARNING: The below traceback may *not* be related to the actual failure.
File "/tmp/ansible_dellos6_config_payload_pjEND4/ansible_dellos6_config_payload.zip/ansible/module_utils/network/dellos6/dellos6.py", line 86, in get_config
return _DEVICE_CONFIGS[cmd]
fatal: [sw2]: FAILED! => {
"changed": false,
"invocation": {
"module_args": {
"after": null,
"auth_pass": null,
"authorize": true,
"backup": true,
"backup_options": null,
"before": null,
"config": null,
"host": null,
"lines": null,
"match": "line",
"parents": null,
"password": null,
"port": null,
"provider": null,
"replace": "line",
"save": false,
"src": null,
"ssh_keyfile": null,
"timeout": null,
"update": "merge",
"username": null
}
},
"msg": "unable to retrieve current config",
"stderr": "command timeout triggered, timeout value is 30 secs.\nSee the timeout setting options in the Network Debug and Troubleshooting Guide.",
"stderr_lines": [
"command timeout triggered, timeout value is 30 secs.",
"See the timeout setting options in the Network Debug and Troubleshooting Guide."
]
Just wanted to edit for anyone else experiencing this issue. It looks like it was a bug in the module that will be fixed in the latest release of Ansible.
https://github.com/ansible/ansible/pull/63272

Why is this basic ansible playbook throwing an error?

I am trying to understand how ansible playbooks are structured and I am failing at a basic example:
---
- hosts: all
tasks:
# update dependencies
- name: install apt dependencies
apt: name={{ item }}
with_items:
- python3-arrow
- python3-netifaces
- python3-requests
- python3-docopt
- name: install pip3 dependencies
pip: name=scapy-python3 executable=pip3
# install service
- name: copy source file
copy: src=honeysyn.py dst=/opt/sentinel-honeysyn/honeysyn.py
- name: copy service file
copy: src=honeysyn.service dst=/etc/systemd/system/honeysyn.service mode=0644
- name: install service, restart and enable
systemd:
name: honeysyn
daemon_reload: yes
enabled: yes
started: yes
The error is:
The offending line appears to be:
copy: src=honeysyn.service dst=/etc/systemd/system/honeysyn.service mode=0644
- name: install service, restart and enable
^ here
I checked the consistency of the YAML file and the JSON output makes sense:
[
{
"tasks": [
{
"name": "install apt dependencies",
"apt": "name={{ item }}",
"with_items": [
"python3-arrow",
"python3-netifaces",
"python3-requests",
"python3-docopt"
]
},
{
"pip": "name=scapy-python3 executable=pip3",
"name": "install pip3 dependencies"
},
{
"copy": "src=honeysyn.py dst=/opt/sentinel-honeysyn/honeysyn.py",
"name": "copy source file"
},
{
"copy": "src=honeysyn.service dst=/etc/systemd/system/honeysyn.service mode=0644",
"name": "copy service file"
},
{
"systemd": {
"started": true,
"enabled": true,
"name": "honeysyn",
"daemon_reload": true
},
"name": "install service, restart and enable"
}
],
"hosts": "all"
}
]
I found out that the errors are often very much off the real bug (I had the same case as above, but it was an extra space after a = in a completely different place) - thus the whole playbook.
What is wrong with this playbook?
The systemd module that you are attempting to use is present in Ansible 2.2 (which is not released as far as I know) and hence will not work with any of the currently available Ansible versions.
https://docs.ansible.com/ansible/systemd_module.html
As #Amit pointed out, it's not released yet.
Ansible seems to have a very zealous documentation release schedule, which sometimes outstrips the release of the actual supporting code :-)
Maybe try the service module instead for now, something like this should work:
- name: install service, enable and start
service:
name: honeysyn
enabled: yes
state: started

ansible variables inside variables

I'm trying to build a role which uses some variables from a file.
Though this variables also depend on some common variable which I want to define for all roles only one without copy&paste it to every single variable file.
Though I can't understand how I can do that. I'm talking about vars file only.
E.g. roles/dns/tasks/main.yml includes file for specific location:
- include_vars: ../vars/dns/domains_{{ location }}.yml
location is defined on role level. Inside this I'm trying to define settings for various dns names, e.g.:
domains: [
{
domain: "domain.com",
location: "america",
ip: "xx.xx.xx.xx",
ttl: 1800,
mx: "10 mail",
subdomains: [
{ name: "www", ip: "xx.xx.xx.xx"},
]
},
]
so here I have the same IP defined for each and every entry.
Is there a way to put all IPs into some global var file (e.g. group_vars/all/vars_file.yml ) and use it inside this role specific var file like this:
domains: [
{
domain: "domain.com",
location: "america",
ip: server.america.ip,
ttl: 1800,
mx: "10 mail",
subdomains: [
{ name: "www", ip: server.america.ip },
]
},
]
where server.america.ip is defined somewhere global?
Yes, that's possible. Variable files actually run through jinja as well, so you can have basic expressions and variables in variable files.
domains: [
{
domain: "domain.com",
location: "america",
ip: "{{ server.america.ip }}",
ttl: 1800,
mx: "10 mail",
subdomains: [
{ name: "www", ip: "{{ server.america.ip }}" },
]
},
]
You can include variables from role X, at beginning of tasks/main.yml of your role Y, for example.
If you have a common role, let's put location on this one, for example.
Only potential problem, is that you might need to use 'with_items' to call included variables.

Resources