I have a variable declared, and I am trying to get its value to show up in the key, when attempting to use the ec2_instance_info ansible module. I want the value to show up under tags. Please view the dummy code below.
vars:
tag_key: Key
tag_value: Value
tasks:
- name:
ec2_instance_info:
filters:
"tag: {{ tag_key }}": "{{ tag_value }}"
I want the above to output as:
tag:Key:Value
But instead it comes out as:
tag:{{ tag_key }}:Value
As a result, when I run the commands, it doesn't call any instances, since they're searching for the wrong thing. The code works fine when I swap the variables out for regular strings. (I'm aware the syntax is probably wrong in the dummy code, I've tried a bunch of things now.)
I attempted the following: Ansible variable in key/value key And while it works in displaying the variables, it now registers as a dict and I get the error:
Invalid type for parameter Filters[0].Values, value: {'Key': 'Value'}, type: <type 'dict'>, valid types: <type 'list'>, <type 'tuple'>"
So I guess I'm looking for either a way to use variables in key names without it turning to a dict, and if that's not available, to transform that into a list. Thanks in advance.
The filters of ec2_instance_info module requires a "dict". So one way to supply that "dict" is to create one in vars:.
Something like:
vars:
ec2_filters:
"tag:Name": "my-instance-1"
tasks:
- ec2_instance_info:
filter: "{{ ec2_filters }}"
register: ec2_out
- debug:
var: ec2_out
Or call the nested variables as a dict inside filters:
vars:
tag_key: Key
tag_value: Value
tasks:
- ec2_instance_info:
filter:
'{ "tag:{{ tag_key }}": "{{ tag_value }}" }'
register: ec2_out
Related
I am using Ansible version 2.9. I want to do a GET, which returns a block of info, regex an ID from that info that corresponds to whatever host I am iterating through at the moment, and then later do things with that ID.
I have the regex working ( https://regex101.com/r/UL7V6r/2 ). And I confirmed this regex does work in the playbook when I input it exactly like in the sample. But, I need the host name at the end of that regex to be a variable matching the host I am iterating through, not a static host name. Here is the playbook, focused on just getting the regex to work:
gather_facts: no
vars:
the_name: "{{ inventory_hostname_short }}"
tasks:
- uri:
url: http://controller-sample-a1p.someplace.com/restapi/nodes
method: GET
return_content: yes
register: nodeId
delegate_to: 127.0.0.1
- debug: msg="{{ nodeId.content | regex_findall("(\w+-\w+-\w+-\w+-\w+)..<address>\d+\.\d+\.\d+\.\d+:?\d+?<\/address><name>{{ the_name }}") }}"
delegate_to: 127.0.0.1
- debug:
var: the_name
The focus is on the end of that regex, with the variable of "the_name". As you can see I am trying curly brackets here. I've tried lots of variations insulting no brackets, single quotes, double quotes, etc.
The results of this play is:
ok: [sampleFQDN2.place.com -> 127.0.0.1] => {
"msg": []
}
TASK [debug] *************************************************************************************************************************
ok: [sampleFQDN2.place.com] => {
"the_name": "sampleFQDN2"
}
Expected result would be for debug msg one to show "FJLEEJ24-3190-49F1-965D-823F63904136" (per the link).
So this suggests to me that the variable is correct (second debug). And the regex is correct because if I take the variable output of "sampleFQDN2" and plug it in directly, that first debug spits out the right response. Which leads me to believe I just have not found the right syntax to stick a variable in a regex_findall.
Does anyone know the syntax for this? Or even if it is possible?
You never nest Jinja {{...}} template markers. Within a Jinja template, if you want to combine a literal string and a variable, you can use the ~ string concatenation operator, like this:
- debug: msg="{{ nodeId.content | regex_findall("(\w+-\w+-\w+-\w+-\w+)..<address>\d+\.\d+\.\d+\.\d+:?\d+?<\/address><name>" ~ the_name) }}"
The ~ operator is like +, except it will convert arguments into
strings so that you can concatenate numeric values to a string
(writing "this " + 1 would fail, but "this " ~ 1 would work).
Or you can use Python string formatting syntax, like this:
- debug: msg="{{ nodeId.content | regex_findall("(\w+-\w+-\w+-\w+-\w+)..<address>\d+\.\d+\.\d+\.\d+:?\d+?<\/address><name>%s" % (the_name)) }}"
This syntax uses printf-style formatting tokens (%s for strings,
%d for integers, etc). Or like this:
- debug: msg="{{ nodeId.content | regex_findall("(\w+-\w+-\w+-\w+-\w+)..<address>\d+\.\d+\.\d+\.\d+:?\d+?<\/address><name>{}".format(the_name)) }}"
Here is one site that documents Python
string formatting in some detail.
I am running a playbook in ansible that takes the stdout_lines of a shell module output and gives me this format:
StackNames.stdout_lines:
- "["
- ' "SHSD-CZWV-ami-automation-WIN2012R2-NONPROD-ramirja-119",'
- ' "SHSD-CZWV-ami-automation-WIN2012R2-NONPROD-ramirja-118",'
- ' "SHSD-CZWV-ami-automation-WIN2012R2-NONPROD-ramirja-117"'
- "]"
I am trying get get a list of these values that can be used in a loop so the stacks can be deleted, but first I need to get rid of all the quotes, dbl quotes and white spaces so is formatted properly for the cloudformation ansible module to take in the stack_name parameter value.
I have tried setting a new variable with proper formatting such as:
- set_fact:
stack_list: "{{ StackNames.stdout_lines | replace('"','') |trim }}"
but I have no luck so far.
Any help is greatly appreciated
From your example, your shell command is returning a json parsable result. Simply parse the global output (stdout) inside a variable with the from_json filter and you're done:
- set_fact:
stack_list: "{{ StackNames.stdout | from_json }}"
- name: Make sure the above is working with your specific output
debug:
var: item
loop: "{{ stack_list }}"
I am trying add some keys to my root authorized_keys on the instance, but looks like it is overwriting the list and only stick the last key,
Any one know how to sort this ?
- name: Set authorized key
authorized_key:
user: root
state: present
key: "{{item}}"
loop: "{{keys}}"
the vars file is
keys:
- "https://gitlab.com/user1.keys"
- "https://github.com/user2.keys"
Q: "Looks like it is overwriting the list and only stick the last key, Anyone know how to sort this ?"
A: By default authorized_key does not remove non-specified keys from the authorized_keys file. See parameter exclusive. Make sure what data you feed key with.
From the documentation, under the exclusive option:
Whether to remove all other non-specified keys from the
authorized_keys file. Multiple keys can be specified in a single key
string value by separating them by newlines. This option is not loop
aware, so if you use with_ , it will be exclusive per iteration of the
loop. If you want multiple keys in the file you need to pass them all
to key in a single batch as mentioned above.
This means that you can achieve what you want by using a Jinja join filter on your array:
- name: Set authorized key
authorized_key:
user: root
state: present
key: "{{ keys | join('\n') }}"
Is that even possible to refer to a group variable while running a play for other group?
I have a specific case like that:
/etc/ansible/hosts
[group1]
server1.test.org
[group2]
server2.test.com
[group2:vars]
foo=bar
Running a play for group1
- name: test variables...
hosts: group1
gather_facts: no
tasks:
- debug: msg="foo={{ groups[group2].foo }}"
It is not working, I have tried other syntax variants without success.
The groups don't actually have variables defined for them when the inventory gets initialized. The hosts get a copy of what's defined for group variables. So to do what you want, you need to read from a host. Try this:
- name: test variables...
hosts: group1
gather_facts: no
tasks:
- debug: msg="foo={{ hostvars[groups['group2'][0]].foo }}"
I need something like (ansible inventory file):
[example]
127.0.0.1 timezone="Europe/Amsterdam" locales="en_US","nl_NL"
However, ansible does not recognize 'locales' as a list.
You can pass a list or object like this:
[example]
127.0.0.1 timezone="Europe/Amsterdam" locales='["en_US", "nl_NL"]'
With complex variables, it's best to define them in a host_vars file rather than in the inventory file, since host_vars files support YAML syntax.
Try creating a host_vars/127.0.0.1 file with the following content:
---
timezone: Europe/Amsterdam
locales:
- en_US
- nl_NL
Ryler's answer is good in this specific case but I ran into problems using other variations with the template module.
[example]
127.0.0.1 timezone="Europe/Amsterdam" locales='["en_US", "nl_NL"]'
Is his original example and works fine.
The following variations work with template. Basically if it's a string you must remember to use the internal double quotes or the entire structure is parsed as a single string. If it's only numbers or "True" or "False" (not "yes") then you're fine. In this variation I couldn't make it work with template if it had external quotes.
I haven't done an exhaustive check of which internal use cases they do and do not break other than the template module.
I am using Ansible 2.2.1.
[example:vars]
# these work
myvar1=["foo", "bar"]
myvar2=[1,2]
myvar3=[True,False]
# These fail, they get interpreted as a single string.
myvar4=[yes, no]
myvar5=[foo,bar]
myvar6='["foo", "bar"]'
you can try split
#inventory file
[example]
127.0.0.1 timezone="Europe/Amsterdam" locales="en_US","nl_NL"
#role file
---
- debug: msg="{{ item }}"
with_items: locales.split(',')
I believe the case is where you define your variable.
if it is under a
[host:vars]
var=["a", "b"]
otherwise:
[hosts]
host1 var='["a", "b"]'
INI file with variables looks like this
$ cat ./vars/vars.yml
lvol_names=['2g-1','2g-2','2g-3']
the variable represents the list type
lvol_names:
- 2g-1
- 2g-2
- 2g-3
the variable can be read from a playbook via lookup:
$ cat ./play.yml
- name: play1
hosts: kub2_data_nodes
become: yes
vars:
- lvol_names: "{{ lookup('ini', 'lvol_names type=properties file=./vars/vars.yml') }}"
You can custom a filter, to split string to list
Github ansible example show how to create custom filter.