Reputation: 11
I have a yml file which installs ODBC Connections on a windows nodes using powershell. For Each DB type we have different yml files and each yml has install scripts for different Databases.
So, everytime we want to change or add a new connection, we comment out all but the one that is only required to be executed and this requires a lot of manual work as and when a connection is changed or added.
This is how i defined the win_command:
- name: Run xxxx Oracle
win_command: powershell -executionpolicy unrestricted folder:\xxx.ps1 -Server {{ XXXX_DB_SERVER }} -UID {{ XXXX_Username }} -PWD {{ XXXXX }} -Database {{ XXX_DB_NAME }} -DSN {{ XXXX_DSN }}
register: cmdXXXXX
- debug: var=cmdXXXX
I have commands like this for almost 9 DBs in this yml. I want to create a variable which will be provided at runtime and only those commands should be executed to install the DB connections.
Upvotes: 1
Views: 1527
Reputation: 44615
If you really have created variables prefixed with some identifier name for all your db parameters, this is really not ideal. You would typically deal with such info in ansible using a list or a dict (you still have a solution below if you really cannot change that)
This is an example variable declaration
# Example with a list
my_odbc_connection_list:
- name: XXXX
db_server: some.server.local
db_name: acooldb
username: someuser
password: sosecret
dsn: some dsn
- name: YYYY
db_server: other.server.local
db_name: ahypedb
username: otheruser
password: verysecret
dsn: other dsn
# Example with a dict
my_odbc_connection_dict:
XXXX:
db_server: some.server.local
db_name: acooldb
username: someuser
password: sosecret
dsn: some dsn
YYYY:
db_server: other.server.local
db_name: ahypedb
username: otheruser
password: verysecret
dsn: other dsn
Using those structures, it become easy to go through all the connections to set with one single task and a loop. Again, here are two examples for each data structure above with the command used in your question
- name: Run odbc declaration commands from list
win_command: powershell -executionpolicy unrestricted folder:\{{ item.name }}.ps1 -Server {{ item.db_server }} -UID {{ item.username }} -PWD {{ item.password }} -Database {{ item.db_name }} -DSN {{ item.dsn }}
register: odbc_cmd
loop: "{{ my_odbc_connection_list }}"
- name: show commands results
debug:
msg: "{{ odbc_cmd.results }}"
- name: Run odbc declaration commands from dict
win_command: powershell -executionpolicy unrestricted folder:\{{ item.key }}.ps1 -Server {{ item.value.db_server }} -UID {{ item.value.username }} -PWD {{ item.value.password }} -Database {{ item.value.db_name }} -DSN {{ item.value.dsn }}
register: odbc_cmd
loop: "{{ my_odbc_connection_dict | dict2items }}"
- name: show commands results
debug:
msg: "{{ odbc_cmd.results }}"
From there, it is fairly easy to play only the relevant connection commands by passing a list of names. To provide it at runtime, the easiest way is to pass an --extra-var
to the ansible-playbook
command as a comma separated list of strings e.g.
ansible-playbook -i inventory odbc_play.yml --extra_var names_to_declare=XXXX,YYYY
You can provide a single element in the var. It will result in a single element list below.
You then only need to filter out all the elements which are not in that name list. This is basically equivalent to changing the loops with the following expressions:
# if using the data as list
loop: "{{ my_odbc_connection_list | selectattr('name', 'in', names_to_declare.split(',')) }}"
# if using the data as dict
loop: "{{ my_odbc_connection_dict | dict2items | selectattr('key', 'in', names_to_declare.split(',')) }}"
Note that this will take care of filtering out typos in names as well if user entered one that does not exist.
There are other ways than "harcoding" that filter directly in the loop
(declaring an other var, using set_fact
, coping with defaults for names_to_declare
if not provided - i.e. use all connections) but this is a bit beyond the question.
Now if you cannot cannot change your data structure it is still possible to cope with that. Meanwhile you will need a list containing all the known connection names (and you will have to update it if you add more connections) e.g.
known_odbc_connection_list:
- XXXX
- YYYY
This will enable you to loop over your existing vars being slightly more verbose:
- name: Run ocbc declaration commands
vars:
name: "{{ item }}"
db_server: "{{ lookup('vars', item + '_DB_SERVER') }}"
username: "{{ lookup('vars', item + '_Username') }}"
password: "{{ lookup('vars', item + '_Password') }}"
db_name: "{{ lookup('vars', item + '_DB_NAME') }}"
dsn: "{{ lookup('vars', item + '_DSN') }}"
win_command: powershell -executionpolicy unrestricted folder:\{{ name }}.ps1 -Server {{ db_server }} -UID {{ username }} -PWD {{ password }} -Database {{ db_name }} -DSN {{ dsn }}
loop: "{{ known_odbc_connection_list }}"
register: odbc_cmd
And using the same var as above at run time, you can modify your loop to filter connections as:
loop: "{{ known_odbc_connection_list | intersect(names_to_declare.split(',')) }}"
As with the 2 other solutions above, this latest expression will take care of filtering out non-existent names in case of a typo from the user.
Upvotes: 2