How to use variable values in salt formula? - salt-stack

Consider my SLS file,
state1:
cmd.run:
- order: 1
- name: |
USER_NAME='username'
USERPWD='password'
DB_NAME='test'
USER_TOBE_CREATED='new_user'
PASSWORD='newpass'
mysql_user.present:
- order: 2
- host: localhost
- username: USER_TOBE_CREATED
- password: PASSWORD
- connection_user: USER_NAME
- connection_pass: USERPWD
- connection_charset: utf8
- saltenv:
- LC_ALL: "en_US.utf8"
mysql_grants.present:
- order: 3
- grant: all privileges
- database: DB_NAME.*
- user: USER_TOBE_CREATED
In the states mysql_user.present and mysql_grants.present I am using the variables USER_TOBE_CREATED,USER_NAME,USERPWD etc whose values are assigned in state cmd.run. How will I make these two following states to use the actual values of those variables?. Here it's taking variable name itself as the value.

You may want to declare the variables in the state file itself, i.e.:
{% set user_name = "name" %}
and:
state1:
cmd.run:
- order: 1
- name: |
USER_NAME='{{ user_name }}'
You can re-use the variable as many times as you want inside the state file.
Let me know if this helped.

Related

Ansible Nested Loop for Cisco ACL

I'm creating a playbook for an ACL update, where the existing ACL needs to be updated, but before adding the new set of IP addresses to that ACL, I need to make sure that the ACL is present and that the IP hasn't already been configured.
Process:
Need to add the below IP addresses
ACL NAME: 11, 13, DATA_TEST, dummy
Check if the list of ACL are present
commands: "show access-lists {{item}}"
Check if ACL Exist
Q: Can't figure out how to access each item in the result of the first action to see if ACL has been configured. Ex. We can see from the output that dummy has no output, how can I exclude that and process if exist. (refer code below)
Check if IP addresses already added
Q: What is the best approach here? I'm thinking using when then comparing the ACL output from stdout vs the given variables content (ex. parents/lines)?
Add the set of IP addresses on target ACL
Q: What is the best approach here? Need to match the ACL name and configure using the variable.
If somebody is knowledgeable about Ansible, perhaps you could assist me in creating this project? I'm still doing some research, so any assistance you can give would be greatly appreciated. Thanks
My Code:
---
- name: Switch SVU
hosts: Switches
gather_facts: False
vars:
my_acl_list:
- 11
- 13
- DATA_TEST
- dummy
fail: "No such access-list {{item}}"
UP_ACL11:
parents:
- access-list 11 permit 192.168.1.4
- access-list 11 permit 192.168.1.5
UP_ACL13:
parents: access-list 13 permit 10.22.1.64 0.0.0.63
UP_ACLDATA:
lines:
- permit 172.11.1.64 0.0.0.63
- permit 172.12.2.64 0.0.0.63
parents: ip access-list standard DATA_TEST
tasks:
- name: Check if the ACL Name already exists.
ios_command:
commands: "show access-lists {{item}}"
register: acl_result
loop: "{{my_acl_list}}"
- debug: msg="{{acl_result}}"
- name: Check if ACL Exist
debug:
msg: "{{item.stdout}}"
when: item.stdout.exists
with_items: "{{acl_result.results}}"
loop_control:
label: "{{item.item}}"
# Pending - Need to know how to match if ACL name exist on stdout.
- name: Check if IP addresses already added
set_fact:
when:
# pending - ansible lookup?
# when var: UP_ACL11, UP_ACL13, UP_ACLDATA IPs are not in ACL then TRUE
- name: Add the set of IP addresses on target ACL
ios_config:
# pending - if doest exist on particular ACL name then configure using the var: UP_ACL11, UP_ACL13, UP_ACLDATA
Given the simplified data for testing
acl_result:
results:
- item: DATA_TEST
stdout:
- "Standard ... 10 permit ... 20 permit ..."
stdout_lines:
- - "Standard ..."
- "10 permit ..."
- "20 permit ..."
- item: dummy
stdout:
- ""
stdout_lines:
- - ""
Q: "Check if ACL Exists"
A: If ACL doesn't exist the attribute stdout is a list of empty strings. Test it
- name: Check if ACL Exists
debug:
msg: "{{ item.item }} exists: {{ item.stdout|map('length')|select()|length > 0 }}"
loop: "{{ acl_result.results }}"
loop_control:
label: "{{item.item}}"
gives
TASK [Check if ACL Exists] ********************************************
ok: [localhost] => (item=DATA_TEST) =>
msg: 'DATA_TEST exists: True'
ok: [localhost] => (item=dummy) =>
msg: 'dummy exists: False'
Notes:
In the filter select, "If no test is specified, each object will be evaluated as a boolean". The number 0 evaluates to false.
Example of a complete playbook for testing
- hosts: localhost
vars:
acl_result:
results:
- item: DATA_TEST
stdout:
- "Standard ... 10 permit ... 20 permit ..."
stdout_lines:
- - "Standard ..."
- "10 permit ..."
- "20 permit ..."
- item: dummy
stdout:
- ""
stdout_lines:
- - ""
tasks:
- name: Check if ACL Exists
debug:
msg: "{{ item.item }} exists: {{ item.stdout|map('length')|select()|length > 0 }}"
loop: "{{ acl_result.results }}"
loop_control:
label: "{{item.item}}"
The test can be simplified if you're sure stdout is a list with a single line only
msg: "{{ item.item }} exists: {{ item.stdout|first|length > 0 }}"

Ansible - how to retrieve value from dict passing in the list in extra vars

So this is my dilemma... I am requiring a user to enter the name of a database (i.e. dbx) and the location (canada or america) through extra-vars (-e "dc=canada" -e "dbname=dbx". From that, I am going read the vars
vars:
dbx:
canada:
dbu: db1
home: /u01/app/oracle
america:
dbu: db2
home: /u01/app/oracle
to get the dbu. The dbu will then be compared to databases running on the host
- name: see if db is running on this host
command: echo database is running here
when: dbu == item.database_name
with_items:
- "{{custom python module}}"
I can get the value if I put
- name: output
register: x
debug:
msg: "{{ dbx[dc].dbu }}"
However if I change dbx to the value of dbname, it errors out.
Hope that makes sense.
Thanks Zeitounator and lxop.
By adding another nested loop info:
I was able to get the result by your suggestion:
{{ info[g_db][dc].dbu }}

Ansible loop on var prompt

I would like to create several node on my bigip. For that I want to do a loop on my var prompt and register each value in my variable {{node_list}}.
This is what I've tried
- name: node creation
hosts: F5
gather_facts: no
connection: local
vars_prompt:
## ASK NUMBER OF NODES
- name: node_nb
prompt: "number of nodes"
private: no
## ASK THE NAME AND IP WITH FORMAT NAME;IP
- name: node_list
prompt: "name and Ip of the node like that toto;1.1.1.1"
private: no
with_sequence: count={{ node_nb | int }}
- name: Create node
bigip_node:
user: '{{ ansible_user }}'
password: '{{ ansible_password }}'
server: 'xxxxx'
host: '{{ (item).split(";")[1] }}'
name: '{{ (item).split(";")[0] }}'
partition: 'Common'
state: present
validate_certs: false
with_items: '{{ node_list }}'
First :
My var prompt don't loop if for example I specify "4" in {{ node_nb }}. The question is prompt one time but I want 4 times.
Second:
I would register all informations of the value in input each time in a list. If I want 4 nodes I need to have 4 items in my list
Just have them enter the list separated by spaces, since you are already using ; to separate node names from IPs, and it additionally saves you the trouble of having to prompt for the count because the count will be however many items there are in the list
with_sequence only works with tasks.
so just keep one variable node_list in to the vars_prompt and pass ',' separated list ['asd;1.1.1.1','sdf;2.2.2.2'] as a value.

How to find in an ansible (yaml) dictionary a key from his value?

I have this dictionary:
MyClouds:
Devwatt:
ExternalNetwork: PublicRSC
Flavors:
- Flavor_1cpu_1gb: Devwatt_1cpu_1gb
- Flavor_1cpu_2gb: Devwatt_1cpu_2gb
- Flavor_1cpu_4gb: Devwatt_1cpu_4gb
Fuga:
ExternalNetwork: Internet
Flavors:
- Flavor_1cpu_1gb: Fuga_1cpu_1gb
- Flavor_1cpu_2gb: Fuga_1cpu_2gb
- Flavor_1cpu_4gb: Fuga_1cpu_4gb
- Flavor_1cpu_8gb: Fuga_1cpu_8gb
I have to migrate from one Openstack cloud to another, and one of my problem is to find correspondances between flavors.
I want to find which flavor (key) has the value "Devwatt_1cpu_2gb" in "Devwatt", and after get the value of the same key in "Fuga"
I tried a lot of solution (with-dict, when, jija filters, json_query) but I can't find a way to do that.
Please, may you help me ?
Inspired by Eric's answer and this usefull resource, I, finally, used this solution:
I changed a little bit my data structure and put it in a file matrice.yml:
MyClouds:
Devwatt:
ExternalNetwork: PublicRSC
Flavors:
- name: Flavor_1cpu_1gb
FlavorName: Devwatt_1cpu_1gb
- name: Flavor_2cpu_1gb
FlavorName: Devwatt_2cpu_1gb
- name: Flavor_1cpu_2gb
FlavorName: Devwatt_1cpu_2gb
Fuga:
ExternalNetwork: Internet
Flavors:
- name: Flavor_1cpu_1gb
FlavorName: Fuga_1cpu_1gb
- name: Flavor_2cpu_1gb
FlavorName: Fuga_2cpu_1gb
- name: Flavor_1cpu_2gb
FlavorName: Fuga_1cpu_2gb
then I used these filters in my playbook:
---
- hosts: localhost
connection: local
gather_facts: false
vars:
SourceFlavorName: "Devwatt_2cpu_1gb"
tasks:
- name: get flavors matrice
include_vars:
file: matrice.yml
- name: Get generic name from flavor name of source cloud
debug:
msg: "{{ MyClouds.Devwatt.Flavors | selectattr('FlavorName','search','^'+ SourceFlavorName +'$') |map (attribute='name') | list }}"
register: result
- name: Get flavor name for target cloud from generic name
debug:
msg: "{{ MyClouds.Fuga.Flavors | selectattr('name','search','^'+ result.msg[0] +'$') |map (attribute='FlavorName') | list }}"
With this solution I can have any number of clouds and find easily correspondances between flavor from one source cloud to target cloud.
Why not using a simple mapping using a dict where keys are "Devwatt" flavors and values are "Fuga" flavors, like this :
---
- hosts: localhost
vars:
FlavorsMapping:
Devwatt_1cpu_1gb: Fuga_1cpu_1gb
Devwatt_1cpu_2gb: Fuga_1cpu_2gb
Devwatt_1cpu_4gb: Fuga_1cpu_4gb
tasks:
- debug:
var: FlavorsMapping['Devwatt_1cpu_2gb']

Salt: text file to variable and use the same variable in state file to find&replace

I've run into an issue I havent been able to solve:
I have a file(/etc/osci) that I use on all of my servers as an name for our monitoring(zabbix)
I've created a state file that pushes a template configuration file to the server and and reads the content of /etc/osci to a variable. The next step would be to use that same variable with 'file.replace' function to search for a string and replace it with the variable.
uusnimi=$(cat /etc/osci):
cmd.run
/etc/zabbix_agentd.conf:
file.managed:
- source: salt://base/streamingconf/zabbix/zabbix_agentd.conf
- mode: 644
change_hostname_zabbix:
file.replace:
- name: /etc/zabbix_agentd.conf
- pattern: 'Hostname='
- repl: 'Hostname=$uusnimi'
Now when executing the state file echoing the variable in the target server it provides me the right output:
echo $uusnimi
Server1
but for the life of me I can't figure out how to escape the last line of the above code so it would insert the value not the '$uusnimi' string
Use uusnimi as a jinja variable.
{% set uusnimi = salt['cmd.shell']('cat /etc/osci') %}
/etc/zabbix_agentd.conf:
file.managed:
- source: salt://base/streamingconf/zabbix/zabbix_agentd.conf
- mode: 644
change_hostname_zabbix:
file.replace:
- name: /etc/zabbix_agentd.conf
- pattern: 'Hostname='
- repl: 'Hostname={{ uusnimi }}'

Resources