This question already has answers here:
How to get the first element of a list from the output of setup module in Ansible?
(3 answers)
Closed 4 years ago.
I have the following values in a data structure:
kafka_topic:
topic:
- "DATA.APP_TOPIC"
partitions:
- "1"
replication-factor:
- "1"
I am retrieving the topic value and passing it to the command module:
- name: Topic Name
set_fact:
topic_name: "{{ kafka_topic.topic }}"
- name: Create Topic with Specific Configuration
command: "{{ kafka_bin_dir }}/{{ kafka_config_script }}
--zookeeper {{ prefix }}-kafka-{{ Kafka_node }}.{{ DNSDomain}}:{{ zookeeper_port }}
--entity-type topics
--alter
--entity-name {{ topic_name }}
--add-config
{{ item.topic_property }}={{ item.value }}"
with_items: "{{ app_kafka_topic_properties_dicts }}"
However, the actual value passed to the command module is [uDATA.APP_TOPIC].
How do I make sure just the value DATA.APP_TOPIC is passed to the command module?
The solution was easy. I just returned the first element of the kafka_topic.topic list.
- name: Topic Name
set_fact:
topic_name: "{{ kafka_topic.topic[0] }}"
This returns the element as oppose to the entire list.
Related
---
- name: Register topic
include: registration.yml
topic: "{{ item }}"
with_items: "{{ kafka_topic }}"
When trying to run the playbook, the following error is shown:
ERROR! conflicting action statements: include, topic The error appears
to be in '/xxx/yyy/tasks/main.yml
The offending line appears to be:
- name: Register topic
topic: X is not a valid Ansible statement.
If I understand correctly, you want to pass in a variable named topic to the tasks file.
If so, this is the way to do it:
---
- name: Register topic
include: registration.yml
vars:
topic: "{{ item }}"
with_items: "{{ kafka_topic }}"
Where kafka_topic is a list / map of items.
Also, note that with_items is being deprecated and replaced by the loop.
If you want to access the item with a diff name, try this
- name: Register topic
include: registration.yml
loop: "{{ kafka_topic }}"
loop_control:
loop_var: topic
Then in your registration.yml you can use the looped item as {{ topic }}
I have the output of a command:
---
data:
versions:
- alt-php53
- ea-php56
- ea-php72
metadata:
command: php_get_installed_versions
reason: OK
result: 1
version: 1
And I need to iterate through the values of the versions key.
I have this to assign the output to a variable:
- name: Get PHP versions
shell: "/usr/sbin/whmapi1 php_get_installed_versions"
register: eaphp_versions
But I do not know how exactly to iterate through those values. I tried various methods with dict2items, from_yaml, from_yaml_all using loop, I tried sub_elements but none worked.
The closest I got is the below:
- name: 'Apply stuff'
shell: "echo the item is {{ item }} >> report.txt"
loop: "{{ eaphp_versions.stdout | from_yaml_all | list }}"
But judging from the output it iterates through the whole output as one item:
the item is {udata: {uversions: [ualt-php53, uea-php56, uea-php72]}, umetadata: {ureason: uOK, uversion: 1, ucommand: uphp_get_installed_versions, uresult: 1}}
Please help.
Thanks in advance.
Assume the data structure at top are the contents from eaphp_versions, then you can:
- any-your-module:
any-module-params: use of {{ item }}
with_items: "{{ eaphp_versions.data.versions }}"
The {{ item }} is one of the 3 versions.
I found a solution to this myself. Here it is below how I did it.
- name: Set fact
set_fact:
versions: "{{ versions|default({})|combine(item) }}"
loop: "{{ eaphp_versions.stdout | from_yaml_all|list }}"
- name: 'Set PHP memory_limit to 512M (all PHP versions)'
#40
shell: "/usr/sbin/whmapi1 php_ini_set_directives directive-1=memory_limit%3A512M version={{ item }}"
with_items: "{{ versions.data.versions }}"
I'm trying to append a number to the end of the instance name tag, i have the following code but there's a problem with the second task which i cannot find, and i've not been able to find an example of anyone else trying to solve this problem.
I'm also relatively new to Ansible and cannot find the relevant documentation to do certain things like how to lookup a value in a list like how i'm doing with my until: which is probably invalid syntax
Ansible is 2.9 and runs on the instance itself
The Tasks I have are setup to do the following
Get a list of running EC2 instances that belong to the same launch template
Loop the same amount of times as the instance list until the desired name based on item index is not found in the name tags of the ec2 list
Set the updated tag name
Current Code:
---
- name: "{{ role_name }} | Name Instance: Gather facts about current LT instances"
ec2_instance_info:
tags:
"aws:autoscaling:groupName": "{{ tag_asg }}"
"aws:ec2launchtemplate:id": "{{ tag_lt }}"
Application: "{{ tag_application }}"
filters:
instance-state-name: [ "running" ]
no_log: false
failed_when: false
register: ec2_list
- name: "{{ role_name }} | Name Instance: Generate Name"
with_sequence: count="{{ ec2_list.instances|length }}"
until: not "{{ tag_default_name }} {{ '%02d' % (item + 1) }}" in ec2_list.instances[*].tags['Name']
when: tag_name == tag_default_name
no_log: false
failed_when: false
register: item
- name: "{{ role_name }} | Name Instance: Append Name Tag"
ec2_tag:
region: eu-west-1
resource: "{{ instance_id }}"
state: present
tags:
Name: "{{ tag_default_name }} {{ '%02d' % (item + 1) }}"
when: tag_name == tag_default_name
no_log: false
failed_when: false
As requested here's the error I am getting:
ERROR! no module/action detected in task.
The error appears to be in '/app/deploy/Ansible/roles/Boilerplate/tasks/name_instance.yml': line 14, column 3, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
- name: "{{ role_name }} | Name Instance: Generate Name"
^ here
We could be wrong, but this one looks like it might be an issue with
missing quotes. Always quote template expression brackets when they
start a value. For instance:
with_items:
- {{ foo }}
Should be written as:
with_items:
- "{{ foo }}"
The error is not with the name: as i constantly get that error when there's some other error within the task body
You don't appear to have a module listed in the second task. You might be able to use debug as the module, or use set_fact and skip the register line.
I think it might also be possible to combine the last two tasks with some more advanced looping, but I'd have to play around with it to give you a working example.
Thanks to bnabbs answer i realised the problem with that version was the lack of module, after fixing that i then finished creating and testing it and now have a fully working set of tasks which has resulted in the following code.
---
- name: "{{ role_name }} | Name Instance: Gather facts about current LT instances"
ec2_instance_info:
filters:
"tag:aws:autoscaling:groupName": "{{ tag_asg }}"
"tag:aws:ec2launchtemplate:id": "{{ tag_lt }}"
"tag:Application": "{{ tag_application }}"
instance-state-name: [ "pending", "running" ]
register: ec2_list
- name: "{{ role_name }} | Name Instance: Set Needed Naming Facts"
set_fact:
tag_name_seperator: " "
start_index: "{{ (ec2_list.instances | sort(attribute='instance_id') | sort(attribute='launch_time') | map(attribute='instance_id') | list).index(instance_id) }}"
name_tag_list: "{{ (ec2_list.instances | map(attribute='tags') | list) | map(attribute='Name') | list }}"
# Generate Name from starting index of array and mod to the length of the amount of instances to help prevent conflicts when multiple instances are launched at the same time
- name: "{{ role_name }} | Name Instance: Generate Name"
set_fact:
desired_tag_name: "{{ tag_default_name }}{{ tag_name_seperator }}{{ '%02d' % (((item|int) + (start_index|int) % (name_tag_list|length)) + 1) }}"
loop: "{{ name_tag_list }}"
until: not "{{ tag_default_name }}{{ tag_name_seperator }}{{ '%02d' % (((item|int) + (start_index|int) % (name_tag_list|length)) + 1) }}" in name_tag_list
- name: "{{ role_name }} | Name Instance: Append Name Tag"
ec2_tag:
region: eu-west-1
resource: "{{ instance_id }}"
state: present
tags:
Name: "{{ desired_tag_name }}"
I have an output from yum list module. The thing is I want to display the output without those number (epoch attribute). The problem is I couldn't find any solutions of mapping 2 attributes (name and version). All the solutions I found are connected to only 1 attribute ( envra) in my case.
- name: check packages
become: true
yum:
list: installed
register: output
- name: add lines to files
lineinfile:
dest: "./file.txt"
line: "{{ inventory_hostname }} {{ item }}"
with_items:
- "{{ output.results | map(attribute='envra') |list }}"
delegate_to: localhost
This is the output without any mapping. As you can see there are multiple attributes. I would like to display only name and version of the package.
10.112.65.15 {u'envra': u'0:GeoIP-1.5.0-14.el7.x86_64', u'name': u'GeoIP', u'repo': u'installed', u'epoch': u'0', u'version': u'1.5.0', u'release': u'14.el7', u'yumstate': u'installed', u'arch': u'x86_64'}
The closest to expected values is envra attribute, but still has those epoch number inside...
10.112.65.15 0:GeoIP-1.5.0-14.el7.x86_64
As I mentioned at the begging I would like to get output of something like that
10.112.65.15 GeoIP 1.5.0
or at least without epoch attribute.
I've also change approach and tried this method
- name: add lines to files
lineinfile:
dest: "./file.txt"
line: "{{ inventory_hostname }} {{ item }} "
with_items:
- "{{ output | json_query(my_query) | list }}"
delegate_to: localhost
vars:
my_query: "results[].[name, version]"
but received result was with '[]' and u' which I'd like to delete but don't exactly know how.
10.112.65.15 [u'GeoIP', u'1.5.0']
Why do you extract the attribute or use json query ? Simply use the hash and print out the needed fields. The following should work out of the box.
- name: add lines to files
lineinfile:
dest: "./file.txt"
line: "{{ inventory_hostname }} {{ item.name }} {{ item.version }}"
with_items:
- "{{ output.results }}"
delegate_to: localhost
I am trying to use a register in Ansible playbook to store my output. Below is the code which i am using.
I have tried below code
- name: Check if Service Exists
stat: path=/etc/init.d/{{ item }}
register: {{ item }}_service_status
with_items:
- XXX
- YYY
- ZZZ
I need different outputs to be stored in different register variables based on the items as mentioned in the code. It is failing and not able to proceed. Any help would be appreciated.
Updated answer
I think you need to put quotes around it:
register: "{{ item }}_service_status"
Or you can use set_fact (1, 2, 3, 4)
register all the output to a single static variable output and then use a loop to iteratively build a new variable service_status (a list) by looping over each item in the static variable output
- name: Check if Service Exists
stat: path=/etc/init.d/{{ item }}
register: output
with_items:
- XXX
- YYY
- ZZZ
- name: Setting fact using output of loop
set_fact:
service_status:
- rc: "{{ item.rc }}"
stdout: "{{ item.stdout }}"
id: "{{ item.id }}"
with_items:
- "{{ output }}"
- debug:
msg: "ID and stdout: {{ item.id }} - {{ item.stdout }}"
with_items:
- "{{ service_status }}"
Initial Answer
IIUC, this link from the Ansible docs shows how to use register inside a loop (see another example in this SO post).
A couple of points
it may be more convenient to assign the list (XXX, YYY, ZZZ) to a separate variable (eg. 1, 2)
I don't know if this is part of the problem, but with_items is no longer the recommended approach to loop over a variable: instead use loop - see here for an example
vars:
items:
- XXX
- YYY
- ZZZ
- name: Check if Service Exists
stat: path=/etc/init.d/{{ item }}
register: service_status
loop: "{{ items|flatten(levels=1) }}"
- name: Show the return code and stdout
debug:
msg: "Cmd {{ item.cmd }}, return code {{ item.rc }}, stdout {{ item.stdout }}"
when: item.rc != 0
with_items: "{{ service_status.results }}"