How do I use an encrypted variable (ansible_ssh_pass) in an INI file? - ansible

I am reading this page and if I drop the following text in an file in the Inventory folder :
[vyos:vars]
ansible_connection=network_cli
ansible_network_os=vyos
ansible_user=my_vyos_user
ansible_ssh_pass= !vault |
$ANSIBLE_VAULT;1.2;AES256;my_user
66386134653765386232383236303063623663343437643766386435663632343266393064373933
3661666132363339303639353538316662616638356631650a316338316663666439383138353032
63393934343937373637306162366265383461316334383132626462656463363630613832313562
3837646266663835640a313164343535316666653031353763613037656362613535633538386539
65656439626166666363323435613131643066353762333232326232323565376635
I am getting this error message
[WARNING]: * Failed to parse /home/myuser/Ansible/Inventory/pwdtest
with ini plugin: /home/cristi/Ansible/Inventory/pwdtest:9: Expected
key=value, got: $ANSIBLE_VAULT;1.2;AES256;my_user
I think the issue comes down to assigning a multiline string to a variable in an INI file
Does anybody have any idea how I can use this?
I can use the above in a YAML file format but I would like to keep consistency and use YAML everywhere

How do I use an encrypted variable (ansible_ssh_pass) in an INI file?
You can't.
The documentation page you linked to, seems to be blatantly wrong.
For a start, !vault tag and | character in the output of ansible-vault belong to YAML syntax and there is no way they could ever work in an INI-format inventory.
It seems also, that the function AnsibleVaultEncryptedUnicode, which decrypts the value, is called only from the YAML parser, so there is no way to modify the value (like single line, no tag) in the INI-format inventory.
You can either:
write your inventory in YAML, whole or a part of it, if you use a directory and split the inventory into multiple files
create a directory group_vars in the same directory as your inventory file and put a file vyos.yml inside with the following content:
ansible_connection: network_cli
ansible_network_os: vyos
ansible_user: my_vyos_user
ansible_ssh_pass: !vault |
$ANSIBLE_VAULT;1.2;AES256;my_user
66386134653765386232383236303063623663343437643766386435663632343266393064373933
3661666132363339303639353538316662616638356631650a316338316663666439383138353032
63393934343937373637306162366265383461316334383132626462656463363630613832313562
3837646266663835640a313164343535316666653031353763613037656362613535633538386539
65656439626166666363323435613131643066353762333232326232323565376635

Related

How can I parse part of a URL from an variable?

I'm trying to write a playbook that will go and download the version of ombi I supply on the command line as a variable, then parse part of it so I can rename the file and keep a local copy of it. Then gunzip then untar then stop the service overwrite the existing app, then restart the service.
I've written several other playbooks but parsing this part out has me stumped.
So if say this was the URL
https://github.com/Ombi-app/Ombi/releases/download/v4.32.0/linux-x64.tar.gz
I want to extract the 4.32.0 out of that url. So my playbook run line might be something like:
ansible-playbook updateombi.yml --extra-vars "ombi_release=https://github.com/Ombi-app/Ombi/releases/download/v4.32.0/linux-x64.tar.gz"
I'm assuming I would declare a var like:
ombi_version: "{{ ombi_release | urlsplit('path') }}"
but the urlsplit is what's got me stumped. Anyone able to throw me a bone?
I'm trying to write a playbook that will go and download the version of Ombi I supply on the command line as a variable ...
To do so you could simply provide the version number only
ansible-playbook updateombi.yml --extra-vars "ombi_release=4.32.0"
and construct the URL and filename afterwards within your playbook
url: "https://github.com/Ombi-app/Ombi/releases/download/v{{ ombi_release }}/linux-x64.tar.gz"
dest: /tmp/linux-x64-v{{ ombi_release }}.tar.gz
since they don't have a variable part except the version number. By doing this there would be no need for
... then parse part of it so I can rename the file ...

How can I lookup properties in a slurped file?

According to the ansible documentation, I can use slurp to read a remote file.
I have a java properties file on a remote host that I want to slurp so I did:
- name slurp xyz properties
slurp:
src: /some/path/on/the/remote/my.properties
register: myprops
- debug:
msg: "{{ myprops['content'] | b64decode }}"
If I do that I get the content.
Now I want to use that conent in ansible. E.g. through a lookup. Something like this:
{{lookup('somePropertyInPropertiesFile', myprops['content'])}}
But this doesn't work since the lookup module only allows lookup in files.
How can I pass the slurped file to the lookup?
I'm using ansible 2.9.9
Given ansible lookups work on the control host, you can also get a file from remote to local using fetch module. Then use ini lookup to read a specific property from the properties file.
I couldn't test the code but something like below should work.
- name: Fetch my properties
fetch:
src: /some/path/on/the/remote/my.properties
dest: /tmp/
flat: yes
- debug:
msg: "content is {{ lookup('ini', 'content type=properties file=/tmp/my.properties') }}"
flat: yes will copy the file under /tmp without creating a dir with hostname in the given destination dir which is the default behavior. This might be useful if you have a single host or do not care if the file gets overwritten.
The answer of Moon is correct, but I want to add more details about java property files.
It seems that ansible can only hanlde simple java property files like:
user.name=robert
user.pass=somerandompassword
But the java properties file format also allowes values to span serveral lines, e.g.
targetCities=\
Detroit,\
Chicago,\
Los Angeles
When you have entries like this, ansible doesn't parse them correctly. Ansible's result is:
ok: [..............] => {
"msg": "content is \\\nDetroit,\\\nChicago,\\\nLos Angeles"
}
But the java Properties documentation say:
Properties are processed in terms of lines. There are two kinds of line, natural lines and logical lines. A natural line is defined as a line of characters that is terminated either by a set of line terminator characters (\n or \r or \r\n) or by the end of the stream. A natural line may be either a blank line, a comment line, or hold all or some of a key-element pair. A logical line holds all the data of a key-element pair, which may be spread out across several adjacent natural lines by escaping the line terminator sequence with a backslash character .
Thus
targetCities=\
Detroit,\
Chicago,\
Los Angeles
should be equivalent to
targetCities=Detroit,Chicago,Los Angeles
which is not the case as explained above.
EDIT
Sadly some property files, like tomcat's catalina.properties, can not be parsed at all.
fatal: [..............]: FAILED! => {"msg": "An unhandled exception occurred while running
the lookup plugin 'ini'. Error was a <class 'ConfigParser.ParsingError'>, original
message: File contains parsing errors: <???>\n\t[line 35]: u'org.apache.jasper.,org.apache.naming.,org.apache.tomcat.\\r\\n'\n\t[line 110]:
...

Register a list of variables from file in ansible

I have a file /tmp/components_list with a content like this:
ComponentA: '1263'
ComponentB: '989'
ComponentC: '1354'
I want to register variables in ansible (without quotes), according to the content of file and use them in the yml code.
So, as a result I need something like that:
- name: Get variables from file
Some actions with a file /tmp/components_list
- name: Using these variables
shell: docker run --name component artifactory:5100/radware/Component:{{ComponentA}}
So it should be a number in the variable ComponentA.
How can I do it by using ansible? Thanks!
You can use include_vars statement, see also How to include vars file in a vars file with ansible?

Ansible dynamic inventory service concept

I've been reading the ansible documentation on how to create a dynamic inventory. From what I understand I have to provide a json that is capable of outputing host_vars and group_vars.
With that in mind, how would I go about extending the group_vars and host_vars concepts to include the definition of service ?
In essence, my "end goal" would be to have something that allows me to define:
Host A has services A B C that would then turn into the corresponding host and group vars.
What is the best way to approach this?
I have been thinking about maybe a database but I'm not quite sure on how to propperly abstract the service concept.
Thanks in advance for any help
I cannot give you all your answers, I just started using Ansible four weeks ago. However, I have successfully integrated dynamic inventories. Here's what I can share: (extrapolate for your setup, I'm in a RHEL shop, using 6.9 and 7.4)
By default, ansible looks for your inventory in a file found at /etc/ansible/hosts The default format for that file is (I believe) INI format.
[servers]
server-1
server-2
[labhosts]
labhost-1
labhost-2
[localhost]
127.0.0.1
/etc/ansible/ansible.cfg will allow you relocate your inventory file/directory if needed. For now, my comments will assume no changes from the default
The example above is static inventory. You can move your /etc/ansible/hosts file aside, then do: mkdir /etc/ansible/hosts/
mv your hosts file, into /etc/ansible/hosts/hosts It's OK, to have static inventory files inside your dynamic directory (for now) So the beauty is, you can still use static inventory, it just now lives in /etc/ansible/etc/ <-- directory There is nothing special about the static filename. It can be any name, however some chars are not valid as part of the static file names.
To use dynamic inventory, you now only need to put into the /etc/ansible/hosts/ directory, executable scripts that pull your hostnames from some external database. AND, this is the KEY part, the output (the stdout) of that script MUST output in JSON format.
When ansible looks for your inventory files, it will "see" that /etc/ansible/hosts/ is a dir and then look in there for scripts. When you run a play or playbook, it will execute the script, and use the JSON output as your host targets of your play.
Now, I'm no JSON expert, but here's what works for me. The syntax of the JSON is like this: {"GROUPNAME":["HOST1","HOST2","HOST3",]}
So the entire string is bounded by left and right curly braces. The first field is the quoted groupname, separated by a colon, then the comma delimited list of quoted hosts, bounded by left and right square brackets.
In my environment, we have a perl script, and based on switch parameters, pulls lists of hostnames. We recently modified the perl script, using print statements to generate the JSON output. There is a JSON: perl module, but we didn't find it necessary to use, as formatting the output using print was sufficient. As for the groupname, we also "built" that groupname from the switch settings on the perl script.
So using my INI inventory example above, the JSON output would be something like this: {"servers":["server-1","server-2",]}
Note1: One quirk that I've learned, if you only have ONE host, it must be terminated with a comma. There's a reason, I'm not sure I can explain it. When we are generating our JSON output, we add a comma, regardless of the number of hosts, and it just works.
Note2: I realize this is not real JSON output, but it's working for our needs.
In your playbooks, you would put - hosts: all or - hosts: your_group_name
I usually just put - hosts: all, then limit using -i option and/or "--limit=hostname"
"-i", narrows your inventory to just the static or dynamic generated list
--limit=hostname where "hostname" is one of the subset of -i output.
Consider this command: ansible all -m ping
This will ping all hosts in your entire inventory. Both static and dynamic
ansible all -m ping -i servers
This will ping all hosts in your servers group
ansible all -m ping -i server --limit=server-1
This will ping just the one host, "server-1"
Using --limit= is great for testing plays or playbooks
When moving on to playbooks, you specify the hostlist, in the playbook.
Then you only need to add limits as needed, on the command line.
Good luck!

Can 'extra_vars' receive multiple files?

According the Ansible documentation defining variables at runtime, it says I can load variables from a file.
ansible-playbook release.yml --extra-vars "#some_file"
However, in my case I have two files containing extra variables for my playbook invocation.
Concatenating them together is not an option because one is a secret file created and keyed using Vault. The other file is generated from an upstream process.
I have tried:
ansible-playbook release.yml --extra-vars "#some_file #some_other_file"
... but it didn't work. Upon invocation I get
ERROR: file could not read: some_file #some_other_file
so my guess is it takes everything after the first # symbols as the path of the file.
My questions is, can extra-vars accept multiple files?
It turns out I can use:
ansible-playbook release.yml --extra-vars=#some_file --extra-vars=#some_other_file
This does work for me. Please let me know if there is a better answer. Thanks.

Resources