ansible loop list and range - loops

I have a list:
['bob', 'john', 'jack', 'rick']
I have a fixed range: 10,20 step: 2
I want to build this variable:
my_var:
- name: bob
content: '10'
- name: john
content: '12'
- name: jack
content: '14'
- name: rick
content: '16'
It seems I have to use loop but I don't understand how !

Loop the lists with the zip filter. For example, the playbook
- hosts: localhost
vars:
my_users: [bob, john, jack, rick]
tasks:
- set_fact:
my_var: "{{ my_var|default([]) +
[{'name': item.1, 'content': item.0}] }}"
loop: "{{ range(10,20,2)|zip(my_users)|list }}"
- debug:
var: my_var
gives
my_var:
- {content: 10, name: bob}
- {content: 12, name: john}
- {content: 14, name: jack}
- {content: 16, name: rick}
The iteration is not needed if you can use the collection community.general. For example, the playbook below gives the same result
- hosts: localhost
vars:
my_users: [bob, john, jack, rick]
my_var: "{{ range(10,20,2)|
zip(my_users)|
map('zip', ['content', 'name'])|
map('map', 'reverse')|
map('community.general.dict')|
list }}"
tasks:
- debug:
var: my_var
The values of the attribute content are integers in both options above. Convert the integers to strings if you need them. For example, in the loop, change the task
- set_fact:
my_var: "{{ my_var|default([]) +
[{'name': item.1, 'content': item.0|string}] }}"
loop: "{{ range(10,20,2)|zip(my_users)|list }}"
, or change the declaration
my_var: "{{ range(10,20,2)|map('string')|
zip(my_users)|
map('zip', ['content', 'name'])|
map('map', 'reverse')|
map('community.general.dict')|
list }}"
Both options give the same result (note the quoted numbers (strings) instead of the unquoted numbers in the first two options)
my_var:
- {content: '10', name: bob}
- {content: '12', name: john}
- {content: '14', name: jack}
- {content: '16', name: rick}

Related

Ansible loop with additional filters

I have the following list
ids: [id1, id2, id3]
and the following registered result of an iteration
output2:
changed: false
msg: All items completed
results:
- ansible_loop_var: item
changed: false
failed: false
item: id1
msg:
json:
key1: '0'
key2: '6'
key3: '4'
- ansible_loop_var: item
changed: false
failed: false
item: id2
msg:
json:
key1: '2'
key2: '6'
key3: '6'
- ansible_loop_var: item
changed: false
failed: false
item: id3
msg:
json:
key1: '8'
key2: '0'
key3: '9'
skipped: false
How can I create the dictionary below and select the keys?
"id1": {
"key1": "0",
"key3": "4"
}
"id2": {
"key1": "2",
"key3": "6"
}
"id3": {
"key1": "8",
"key3": "9"
}
Declare the below variables in vars
ids: [id1, id2, id3]
_values: "{{ output2.results|
json_query('[].msg.json.{key1: key1, key3: key3}') }}"
result: "{{ dict(ids|zip(_values)) }}"
As a hint, create the task below for testing. Select key1 and key3 from the resulting JSON
- debug:
msg: "{{ stat|from_yaml }}"
register: output2
loop: "{{ ids }}"
vars:
stat: |
json:
key1: "{{ range(10)|random }}"
key2: "{{ range(10)|random }}"
key3: "{{ range(10)|random }}"
gives
_values:
- {key1: '0', key3: '5'}
- {key1: '1', key3: '9'}
- {key1: '3', key3: '6'}
result:
id1: {key1: '0', key3: '5'}
id2: {key1: '1', key3: '9'}
id3: {key1: '3', key3: '6'}
Fit the query according to the content of your output2.
Example of a complete playbook for testing
- hosts: localhost
vars:
ids: [id1, id2, id3]
_values: "{{ output2.results|
json_query('[].msg.json.{key1: key1, key3: key3}') }}"
result: "{{ dict(ids|zip(_values)) }}"
tasks:
- debug:
msg: "{{ stat|from_yaml }}"
register: output2
loop: "{{ ids }}"
vars:
stat: |
json:
key1: "{{ range(10)|random }}"
key2: "{{ range(10)|random }}"
key3: "{{ range(10)|random }}"
- debug:
var: output2
- debug:
var: _values|to_yaml
- debug:
var: result|to_yaml
OK -- given that output2, this task will create foo:
- name: Build list
set_fact:
foo: |-
{
{% for item in output2.results %}
"{{ item.item }}": {
"key1": "{{ item.msg.json.key1 }}",
"key3": "{{ item.msg.json.key3 }}"
},
{% endfor %}
}

"msg": "'data_list' is undefined". How do I define this variable in my ansible playbook?

I want to extract data from a csv, turn it into a list that would be a variable (data_list in this case) and input the information according to the parameters listed in the task file.
But I am getting this error, "'data_list' is undefined".
Here is the main playbook:
---
- name: Read Users
hosts: localhost
vars:
data_list: []
tasks:
- read_csv:
path: user.csv
key: name
fieldnames: name,firstname,surname,displayName,groups
delimiter: ','
register: userdata
- name: Extract the list
set_fact:
data_list: "{{ data_list + [{ 'name': item.value.name, 'firstname': item.value.firstname, 'surname': item.value.surname, 'displayName': item.value.displayName, 'groups': item.value.groups }] }}"
loop: "{{ userdata.dict|dict2items }}"
when:
- item.key != 'Name'
- debug:
msg: "{{ item.name }}"
with_items: "{{ data_list }}"
- name: Create multiple users
hosts: "{{ hostname }}"
gather_facts: false
any_errors_fatal: false
become: yes
become_method: runas
become_user: admin
roles:
- { role: Create Multiple Users }
Here is my tasks file:
---
- name: Create users
community.windows.win_domain_user:
name: "{{ item.name }}"
firstname: "{{ item.firstname }}"
surname: "{{ item.surname }}"
attributes:
displayName: "{{ item.firstname + ' ' + item.surname }}"
groups:
- "{{ item.groups }}"
loop:
with_items:
- "{{ data_list }}"
After running the playbooks, I received this error:
TASK [Create Multiple Users : Create user] *************************************
fatal: [10.12.201.20]: FAILED! => {"msg": "'data_list' is undefined"}
While keeping everything else default, I've already tried adding vars to:
- name: Create multiple users
hosts: "{{ hostname }}"
gather_facts: false
any_errors_fatal: false
become: yes
become_method: runas
become_user: admin
roles:
- { role: Create Multiple Users }
vars:
- "{{ data_list }}"
---
- name: Create user
vars:
- "{{ data_list }}"
community.windows.win_domain_user:
name: "{{ item.name }}"
firstname: "{{ item.firstname }}"
surname: "{{ item.surname }}"
attributes:
displayName: "{{ item.firstname + ' ' + item.surname }}"
groups:
- "{{ item.groups }}"
loop:
with_items:
- "{{ data_list }}"
And also tried the following syntax:
vars:
- "{{ data_list }}"
vars: "{{ data_list }}"
with_items:
- "{{ data_list }}"
with_items: "{{ data_list }}"
But I am still getting errors.
So in this case, how do I define data_list?
Update
Some of you have suggested me to combine the content in the task file into the first playbook.
But after running the playbook, the portion on "- name: Create multiple Windows AD user accounts" seems to have been entirely skipped by ansible.
Whatever troubleshooting that I have done either results in some error or it gets skipped by ansible. I am not sure which is the right way of writing the playbook so that I don't face anymore errors and I am able to create users.
My playbook looks like this now:
---
- name: Read Users
hosts: localhost
vars:
data_list: []
tasks:
- read_csv:
path: user.csv
key: name
fieldnames: name,firstname,surname,displayName,groups
delimiter: ','
register: userdata
- name: Extract the list
set_fact:
data_list: "{{ data_list + [{ 'name': item.value.name, 'firstname': item.value.firstname, 'surname': item.value.surname, 'displayName': item.value.displayName, 'groups': item.value.groups }] }}"
loop: "{{ userdata.dict|dict2items }}"
when:
- item.key != 'Name'
- debug:
msg: "{{ item.name }}"
with_items: "{{ data_list }}"
- name: Create multiple users
hosts: "{{ hostname }}"
gather_facts: false
any_errors_fatal: false
become: yes
become_method: runas
become_user: admin
vars:
data_list: []
tasks:
- name: Create users
community.windows.win_domain_user:
name: "{{ item.name }}"
firstname: "{{ item.firstname }}"
surname: "{{ item.surname }}"
attributes:
displayName: "{{ item.firstname + ' ' + item.surname }}"
groups:
- "{{ item.groups }}"
loop:
with_items: "{{ data_list }}"

Include variable name with the item value in ansible

I'm trying to get input from CSV file and then add that as a dynamic inventory for a play, below is the ansible playbook:
---
- hosts: localhost
vars:
ansible_user: root
ansible_password: "User#123"
csv_file: "/var/lib/awx/projects/patching/server.csv"
tasks:
- read_csv:
key: servername
path: "{{ csv_file }}"
register: list
- debug:
msg: "{{ item.value.servername }}"
loop: "{{ list.dict|dict2items }}"
- add_host:
name: "{{ item.value.servername }}"
ansible_user: "{{ ansible_user }}"
ansible_password: "{{ ansible_password }}"
groups: patching
loop: "{{ list.dict|dict2items }}"
- name: test
hosts: patching
tasks:
- shell: hostname
register: hostname
- debug: "{{ hostname }}"
This playbook works fine, but I would like make the parameter "key" in the read_csv module as a variable as below and incorporate it with the item value as below, it throws error
"as The error was: 'dict object' has no attribute 'column'"
---
- hosts: localhost
vars:
ansible_user: root
ansible_password: "user#123"
csv_file: "/var/lib/awx/projects/patching/server.csv"
column: servername
tasks:
- read_csv:
key: "{{ column }}"
path: "{{ csv_file }}"
register: list
- debug:
msg: "{{ item.value.column }}"
loop: "{{ list.dict|dict2items }}"
- add_host:
name: "{{ item.value.column }}"
ansible_user: "{{ ansible_user }}"
ansible_password: "{{ ansible_password }}"
groups: patching
loop: "{{ list.dict|dict2items }}"
- name: test
hosts: patching
tasks:
- shell: hostname
register: hostname
- debug: "{{ hostname }}"
Need to understand how to incorporate the variable "column" to the item.value.servername change as item.value.column
Below is the CSV file:
#cat server.csv
servername,ip
172.17.92.60,172.17.92.60
172.17.92.38,172.17.92.38
172.17.92.39,172.17.92.39
172.17.92.70,172.17.92.70
try this playbook:
tasks:
- read_csv:
key: "{{ column }}"
path: "{{ csv_file }}"
register: list
- debug:
msg: "{{ item.value[column] }}"
loop: "{{ list.dict|dict2items }}"
- add_host:
name: "{{ item.value[column] }}"
ansible_user: "{{ ansible_user }}"
ansible_password: "{{ ansible_password }}"
groups: patching
loop: "{{ list.dict|dict2items }}"

iterate though complex values.yaml using range in helm chart

I'm new here to helm world. I want to generate manifest from my values and sample.yaml so
I trying to create a template from my sample.yaml files.
Values.yaml
prodapps:
alpha:
name: alpha
image: alpha.azurecr.io/alpha:latest
imagePullPolicy: IfNotPresent
resources:
requests:
memory: "10000Mi"
cpu: "150m"
limits:
memory: "800Mi"
cpu: 600m"
ingress:
enabled: true
annotations:
zap.ingress.kubernetes.io/rule-type: PathPrefixStrip
nginx.ingress.kubernetes.io/rewrite-target: /
path: /alpha/api
hosts:
- demo.jumboapps.com
beta:
name: beta
disable: true
image: beta.azurecr.io/beta:latest
imagePullPolicy: IfNotPresent
resources:
requests:
memory: "10000Mi"
cpu: "150m"
limits:
memory: "800Mi"
cpu: 600m"
ingress:
enabled: true
annotations:
zap.ingress.kubernetes.io/rule-type: PathPrefixStrip
nginx.ingress.kubernetes.io/rewrite-target: /
path: /beta/api
hosts:
- demo.jumboapps.com
Sample.yaml
apiVersion: v1
kind: Service
metadata:
name: "{{ .Values.prodapps.alpha.name }}-svc"
namespace: "{{ .Release.Namespace }}"
spec:
ports:
- port: 80
name: "http"
selector:
app: "{{ .Values.prodapps.alpha.name }}"
---
apiVersion: v1
kind: Service
metadata:
name: "{{ .Values.prodapps.beta.name }}-svc"
namespace: "{{ .Release.Namespace }}"
spec:
ports:
- port: 80
name: "http"
selector:
app: "{{ .Values.prodapps.beta.name }}"
My main goal is to templatize my sample.yaml.by and produce the valid Manifet file.
following helm documentation.
But I cant find any sensible(my understandable) syntax for looping through complex values files.
Please anyone help me out with this.
You need to learn more about the usage of range and how k8s divides resources with '---' when applying resources.
You can imitate the following
Values.yaml
prodapps:
alpha:
name: alpha
image: alpha.azurecr.io/alpha:latest
imagePullPolicy: IfNotPresent
resources:
requests:
memory: "10000Mi"
cpu: "150m"
limits:
memory: "800Mi"
cpu: 600m"
beta:
name: beta
disable: true
image: beta.azurecr.io/beta:latest
imagePullPolicy: IfNotPresent
resources:
requests:
memory: "10000Mi"
cpu: "150m"
limits:
memory: "800Mi"
cpu: 600m"
service.yaml
{{ if .Values.prodapps }}
{{- range $k, $v := $.Values.prodapps }}
---
apiVersion: v1
kind: Service
metadata:
name: "{{ $v.name }}-svc"
namespace: "{{ .Release.Namespace }}"
spec:
ports:
- port: 80
name: "http"
selector:
app: "{{ $v.name }}"
{{- end }}
{{- end }}
deployment.yaml
{{ if .Values.prodapps }}
{{- range $k, $v := $.Values.prodapps }}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: "{{ $v.name }}-dep"
namespace: "{{ .Release.Namespace }}"
spec:
template:
spec:
containers:
- name: {{ $v.Name }}
image: "{{ $v.image }}"
imagePullPolicy: {{ $v.imagePullPolicy }}
resources:
{{- toYaml $v.resources | nindent 12 }}
{{- end }}
{{- end }}

Ansible create EC2 instances with subsequent numbers in the name in different subnets

I am able to create ec2 instances with subsequent numbers in the same subnet.
However, I have 2 internal subnets and I am trying to create web3 and web5 in internal_subnet_ids[0] and web4 in internal_subnet_ids[1]. How do I do this?
---
- hosts: localhost
gather_facts: no
vars:
region: us-east-1
state: present
aws_ec2_specs:
- image: "{{ ami_id }}"
key_name: "{{ default_key_name }}"
server_category: web
vpc_subnet_id: "{{ internal_subnet_ids[0] }}"
instance_type: t2.small
server_numbers:
- '3'
- '4'
- '5'
exact_count: 1
tasks:
- name: Create EC2 Instances
ec2:
count: "{{ item.0.count | default(omit) }}"
count_tag:
Name: "{{ item.0.server_category + item.1 }}"
exact_count: "{{ item.0.exact_count | default(omit) }}"
image: "{{ item.0.image | mandatory }}"
instance_tags: "{{ {'Name': item.0.server_category + item.1 }|combine(item.0.instance_tags) }}"
instance_type: "{{ item.0.instance_type | mandatory }}"
key_name: "{{ item.0.key_name | mandatory }}"
region: "{{ region | mandatory }}"
vpc_subnet_id: "{{ item.0.vpc_subnet_id | default(omit) }}"
state: "{{ item.0.state | default(omit) }}"
with_subelements:
- "{{ aws_ec2_specs }}"
- server_numbers
when: state == "present"
register: ec2lauched
I figured out a solution, not the very 'pretty' but it would do for now.
---
- hosts: localhost
gather_facts: no
vars:
region: us-east-1
state: present
aws_ec2_specs:
- image: "{{ ami_id }}"
key_name: "{{ default_key_name }}"
server_category: web
instance_type: t2.small
server_numbers_subnet:
- server_numbers: '3'
vpc_subnet_id: "{{ internal_subnet_ids[0] }}"
- server_numbers: '4'
vpc_subnet_id: "{{ internal_subnet_ids[1] }}"
- server_numbers: '5'
vpc_subnet_id: "{{ internal_subnet_ids[0] }}"
exact_count: 1
tasks:
- name: Create EC2 Instances
ec2:
count: "{{ item.0.count | default(omit) }}"
count_tag:
Name: "{{ item.0.server_category + item.1.server_numbers }}"
exact_count: "{{ item.0.exact_count | default(omit) }}"
image: "{{ item.0.image | mandatory }}"
instance_tags: "{{ {'Name': item.0.server_category + item.1.server_numbers }|combine(item.0.instance_tags) }}"
instance_type: "{{ item.0.instance_type | mandatory }}"
key_name: "{{ item.0.key_name | mandatory }}"
region: "{{ region | mandatory }}"
vpc_subnet_id: "{{ item.1.vpc_subnet_id | default(omit) }}"
state: "{{ item.0.state | default(omit) }}"
with_subelements:
- "{{ aws_ec2_specs }}"
- server_numbers_subnet
when: state == "present"
register: ec2lauched

Resources