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 ...
I am using Ansible and have a directory structure like the example below:
configs
something
files
1.conf
2.conf
// and so on
Those files are templates and I am using Ansible to parse these templates and create them automatically in the destination server.
My problem is that with_fileglob is working only of first level directory and cannot seem to enable some recursive mode.
I have
- name: "Apply templates"
template:
src: "{{ item }}"
dest: "{{ item | replace('.j2', '') }}"
with_fileglob:
- "{{ user_configs_path }}/*"
by the way user_configs_path=configs exists and all good here.
The above does nothing.
If I add something under configs, example configs/blabla.j2 and re-run the playbook it is parsed and copied fine.
So seems somehow that the directories are not searched recursively.
I am not limited to only use the fileglob solution so feel free to suggest anything I can learn to reach my goal.
Basically I want to recursively iterate all directories for files only, and in a loop apply the template module to them and create them in remote server
Thank you
Regarding
My problem is that with_fileglob is working only of first level directory and cannot seem to enable some recursive mode.
and according the documentation fileglob
Matches all files in a single directory, non-recursively, that match a pattern. It calls Python’s “glob” library.
for
How to make Ansible with_fileglob work recursively for all subdirectories
one would need to enhance the module code.
Regarding
Basically I want to recursively iterate all directories for files only, and in a loop apply the template module to them and create them in remote server
as solution and depending on your requirements and what you try to achieve, you could use just
find module – Return a list of files based on specific criteria, in example .conf files. It works with parameter recursive: true and will you provide with a list of full path(s) over which you can loop after.
shell module – Execute shell commands on targets like find and register: result
Similar Q&A
Ansible playbook to find out specific files in sub directories
Ansible: How to find latest files from a directory recursively?
How to search for files containing a particular text with Ansible?
I need to add a text before the end of a parameter in file. I need to insert my text just before </abc>. I am using lineinfile and it enters the text before <abc> and not </abc>.
My current text file :
<domain-log-broadcast-filter>MultiDataSourceLogFilter</domain-log-broadcast-filter>
<abc>Info is already here. i just need to append the text at end of this parameter. new values to be inserted here</abc>
My Playbook :
- lineinfile:
path: /tmp/tochange.xml
insertbefore: '\<\/abc\>'
line: "Tisisthelinetobeinsertedbyme"
state: present
My Output for this is :
<domain-log-broadcast-filter>MultiDataSourceLogFilter</domain-log-broadcast-filter>
Thisisthelinetobeinsertedbyme
<abc>Info is already here. i just need to append the text at end of this parameter. new values to be inserted here</abc>
Now i have 2 requirements :
I want to insert my text just before </abc>
I have 4 </abc> parameters in my file. I want to ignore the first </abc> and the line is to be inserted before other 3 </abc> parameters.
Please sugest me a best way to do it, all i need is this work to be done, with any modules any script in the playbook. Thanks in advance.
Q: "... with any modules any script in the playbook."
A: Ansible file modules are not able to do it. You'll need the module command or shell to run file editing tools like sed or awk.
Module lineinfile is not able not to fulfill the requirements. This module modifies single lines in a file. It's not possible to change 3 out of 4 lines that match regexp. Neither replace nor blockinfile modules will help you either, I'm afraid. The module template modifies whole files. The next option might be the module patch.
Quoting from lineinfile:
"... For other cases, see the copy or template modules."
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!
I have what I think is a fairly common task of taking a local archive file, transferring it to a server, and extracting it there. I'm using the unarchive module for this but struggling with an elegant way to deal with the local filename always being different because the filename includes the software version. For example, here's a excerpt from a playbook:
- name: Upload code
unarchive: src={{payload_file}} dest={{install_dir}}
I can run this and use -e to set the variable:
ansible-playbook -e payload_file=/tmp/payload-4.2.1.zip -i production deploy.yml
My question is is this the best way to handle this situation? All the docs have hardcoded example file names and paths and I haven't seen any evidence in the docs that makes a variable that will be different each deployment straightforward to set.
While passing extra args on the command line will work, I generally don't like having to type to run the job -- this is to say that I don't think your solution is inelegant or bad in any way.
However, if you're willing to change your process a little, you can avoid having to add options when calling your playbook.
Option 1: Put the payload-version.zip file in a directory and target that directory with a glob. Any file in that directory will get unarchived (if there's only one file, this achieves the same behavior):
- name: Upload code
unarchive: src={{item}} dest={{install_dir}}
with_fileglob:
- /tmp/payloads/*
Option 2: Symlink the versioned file to a simple, general name of payload-latest.zip and target it with your play (using the modified date or setting a fact for metadata). I assume you have a build process or script to generate the zip, so add a step to symlink the build version to payload-latest.zip and target that in your play.