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.
Related
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.
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
I am trying come up with a way to pass multiple variables to the same field in a role but not having any luck getting it to work using the Role duplication and execution method I've been using. As an example I want an SLB Server to have multiple ports assigned to it using the port_number variable. I'm new to Ansible so making some rookie mistakes like the code below (port_number: "80", port_number: "8080" returns duplicate entry so only uses the first) but I have tried just about every syntax I have found examples for and nothing is working right. The end result is basically having test3 with both of the port_number: entries assigned to it but at this point I'm not even sure it's possible doing it this way or if I have to run a separate module after the fact to add the entries. Any help is greatly appreciated. Thanks.
---
- name: Deploy A10 config
connection: local
hosts: all
roles:
- role: server
vars:
name: "test1"
fqdn_name: "test1.test.domain.net"
health_check: "TCP-8080-HALFOPEN"
port_number: "80"
- { role: server, vars: { name: "test2", fqdn_name: "test2.test.domain.net", port_number: "8080" }}
- { role: server, vars: { name: "test3", fqdn_name: "test3.test.domain.net", port_number: "80", port_number: "8080" }}
---
- name: Test server create
a10_slb_server:
a10_host: "10.1.1.1"
a10_username: "admin"
a10_password: "admin"
a10_port: "443"
a10_protocol: "https"
state: present
name: "{{ name }}"
fqdn_name: "{{ fqdn_name }}"
port_list:
- port_number: "{{ port_number }}"
In your code vars is dictionary. The keys in a dictionary must be unique.
vars:
name: "test1"
fqdn_name: "test1.test.domain.net"
health_check: "TCP-8080-HALFOPEN"
port_number: "80"
YAML resolves the duplication of the keys simply by overriding the value. This expression
vars: { name: "test3", fqdn_name: "test3.test.domain.net", port_number: "80", port_number: "8080" }
would give
"vars": {
"fqdn_name": "test3.test.domain.net",
"name": "test3",
"port_number": "8080"
}
In your code port_list is list. It's a list of dictionaries. This seems to be the proper way to declare multiple port numbers.
port_list:
- port_number: "80"
- port_number: "8080"
In serialized format
port_list: [{port_number: "80"}, {port_number: "8080"}]
But, in your code role: server it's not clear how these variables are used in the role. It is necessary to review the role to learn how to submit the data.
For example:
- role: server
vars:
name: "test1"
fqdn_name: "test1.test.domain.net"
health_check: "TCP-8080-HALFOPEN"
port_number1: "80"
port_number2: "8080"
--
- name: Test server create
a10_slb_server:
a10_host: "10.1.1.1"
a10_username: "admin"
a10_password: "admin"
a10_port: "443"
a10_protocol: "https"
state: present
name: "{{ name }}"
fqdn_name: "{{ fqdn_name }}"
port_list:
- port_number: "{{ port_number1 }}"
- port_number: "{{ port_number2 }}"
I want to push ios_facts to gitlab using ansibles uri module.
- name: get ios facts
ios_facts:
gather_subset: all
register: ios_facts
- name: commit to gitlab
delegate_to: localhost
uri:
url: http://gitlab/api/v4/projects/2/repository/commits
method: POST
body_format: json
status_code: 201
headers:
PRIVATE-TOKEN: "xxxxxxxxxxxxxx"
Content-Type: "application/json"
body: |
{
"branch": "master",
"commit_message": "{{ ansible_net_hostname }} update",
"actions": [
{
"action": "update",
"file_path": "conf/{{ ansible_net_hostname }}",
"content": "{{ ansible_net_config }}"
}
]
}
The Playbook works fine if I am using any other variable than ansible_net_config, or if I am pasting the raw content of ansible_net_config instead of using the jinja2 reference. The ansible_net_config is a large string using \n as new line and contains some special characters. I guess the problem occurs because I don't get valid json when the playbook parses.
I then get the HTTP Error 400: Bad Request
Is there any filter I can apply or any other thing I might be missing out?
I managed to solve the issue:
The API Call failed when the variable contains "\n". I could make it work by replacing "\n" with escaped "\\n":
...
"content": {{ ansible_net_config | replace('\n','\\n') }}
...
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.