how to get the non-repetitive element from two variables in ansible - ansible

I am running the Ansible task for creating terraform resources, code is below:
- name: "Run terraform project: {{ tf_project }}"
terraform:
state: present
force_init: true
backend_config:
bucket: "{{ tf_bucket_name }}"
region: "{{ bootstrap_region }}"
kms_key_id: "{{ tf_bucket_kms_id }}"
encrypt: "true"
workspace_key_prefix: "{{ target_infra }}"
key: "{{ tf_project }}.tfstate"
project_path: "../terraform_12/{{ tf_project }}"
variables:
target_region: XXXXXXX
workspace: "Test"
below are the values of the variables:
hostvars[inventory_hostname]['Active_Regions']: ['eu-west-1','ap-southeast-2']
hostvars[inventory_hostname]['Region']: 'eu-west-1'
expected value:
target_region: ['ap-southeast-2']
have tried below:
target_region: "{{ hostvars[inventory_hostname]['Active_Regions'] | difference(hostvars[inventory_hostname]['Region'] | list) }}"
but it's not working.
note: hostvars[inventory_hostname]['Active_Regions'] and hostvars[inventory_hostname]['Regions'] are dynamic.

The second parameter is not a list. You have to enclose it in brackets [], e.g.
- set_fact:
target_region: "{{ hostvars[inventory_hostname]['Active_Regions']|
difference([hostvars[inventory_hostname]['Region']]) }}"

Related

Conditional task based on template parameter fails

I'm trying to use Ansible to deploy to two regions in AWS, I have it working with one region at the moment. The issue is I want to only execute my primary_region or my secondary_region depending on the parameter from the template it's using.
My main.yaml:
- hosts: primary_region
name: Create ECR
tasks:
- name: "Create ECR Repository"
cloudformation:
state: "{{ state }}"
stack_name: "{{ stack_create_ecr.name }}"
profile: "{{ aws_profile }}"
region: "{{ inventory_hostname }}"
template_url: "{{ stack_create_ecr.template_url }}"
template_parameters:
"ansibleFile"
tags:
"{{ stack_create_ecr.tags }}"
tags:
- stack_create_ecr
when: stack_create_ecr.region == "primary_region" <-- This
- hosts: secondary_region
name: Create ECR
tasks:
- name: "Create ECR Repository"
cloudformation:
state: "{{ state }}"
stack_name: "{{ stack_create_ecr.name }}"
profile: "{{ aws_profile }}"
region: "{{ inventory_hostname }}"
template_url: "{{ stack_create_ecr.template_url }}"
template_parameters:
"ansibleFile"
tags:
"{{ stack_create_ecr.tags }}"
tags:
- stack_create_ecr
when: stack_create_ecr.region == "secondary_region" <-- This
The template that I am using
stack_create_ecr.yaml:
stack_create_ecr:
name: cloudFormationTemplateNameOmitted
template_url: S3BucketUrl
parameters:
RepoName: EcrRepoName
DevName: cloud-dev
tags:
ansible_playbook: "{{ ansible_playbook_tag }}"
region: primary_region <-- This is what I'm trying to use
Everytime I try to run my playbook I just get msg: 'argument template_parameters is of type <class ''str''> and we were unable to convert to dict: dictionary requested, could not parse JSON or key=value'
I have tried all sorts of things from putting quotes around the string in the when condition. Nothing seems to work, what am I doing wrong?
It seems you massed up with template_parameters prop. It should be a map but you provided a string:
template_parameters:
PropName: "ansibleFile"

Loop through variables in task that has another list embedded in the variables

I am looking to loop through a list of variables. I have it looping through the of variables using with_items, however the catch is there is a list within that variables list that needs to have a different subset / number of variables that i need to iterate through as well.
I have tried different filters to include with_nested, with_subelements, and with_items. I know that they are moving towards loops as the primary driver moving forward so any solution ideally would leverage the ansible path moving forward. I am looking at having an "inner" loop or an external task that will iterate through the vlans_list and input that data as its to that point.
group Variables
vnic_templates:
- name: vNIC-A
fabric: A
mac_pool: testmac1
mtu: 1500
org_dn: org-root
redundancy_type: none
state: present
template_type: initial-template
vlans_list: ### THE PROBLEM CHILD
- name: vlan2
native: 'no'
state: present
- name: vlan3
native: 'no'
state: present
The actual task - i have issues when i have to input multiple vlans. The vnic template will have a 1 to one relationship however the vlans_list could be 1 vnic_template to many vlans.
ucs_vnic_template:
hostname: "{{ ucs_manager_hostname }}"
username: "{{ ucs_manager_username }}"
password: "{{ ucs_manager_password }}"
name: "{{ item.name }}"
fabric: "{{ item.fabric }}"
mac_pool: "{{ item.mac_pool }}"
mtu: "{{ item.mtu }}"
org_dn: "{{ item.org_dn }}"
redundancy_type: "{{ item.redundancy_type }}"
state: "{{ item.state }}"
template_type: "{{ item.template_type }}"
vlans_list:
- name: "{{ item.1.name }}"
native: "{{ item.1.native }}"
state: "{{ item.1.present }}"
# loop: "{{ vnic_templates | subelements('vlans_list') }}"
with_items:
- "{{ vnic_templates }}"
I am starting down the road of adding an include vlan_list.yml outside of this task but no familiar with out to do that.
Actual results are
The task includes an option with an undefined variable. The error was: 'item' is undefined\n\n
I need the create a single vnic template with multiple vlans defined in that list.
Another engineer i work with was able to solve the question. By the way the variables are laid out we were able to easily just change the code
Change this:
vlans_list:
- name: "{{ item.1.name }}"
native: "{{ item.1.native }}"
state: "{{ item.1.present }}"
To this:
vlans_list: "{{ item.vlans_list }}"
Full Code listed below.
- name: Add vNIC Templates
ucs_vnic_template:
hostname: "{{ ucs_manager_hostname }}"
username: "{{ ucs_manager_username }}"
password: "{{ ucs_manager_password }}"
name: "{{ item.name }}"
fabric: "{{ item.fabric }}"
mac_pool: "{{ item.mac_pool }}"
mtu: "{{ item.mtu }}"
org_dn: "{{ item.org_dn }}"
redundancy_type: "{{ item.redundancy_type }}"
state: "{{ item.state }}"
template_type: "{{ item.template_type }}"
vlans_list: "{{ item.vlans_list }}"
with_items:
- "{{ vnic_templates }}"

Setting up correctly gateway_ip in Ansible function

I am using the following function to deploy an Openstack subnet using Ansible and variable file:
- name: Create the subnets
os_subnet:
cloud: "{{ item.cloud }}"
state: present
validate_certs: no
gateway_ip: "{{ item.gateway_ip | default(None) }}"
dns_nameservers: "{{ item.dns if item.dns is defined else omit }}"
enable_dhcp: yes
name: "{{ item.subnet }}"
network_name: "{{ item.network }}"
cidr: "{{ item.cidr }}"
allocation_pool_start: "{{ item.allocation_pool_start }}"
allocation_pool_end: "{{ item.allocation_pool_end }}"
host_routes: "{{ item.host_routes | default(omit) }}"
with_items:
- "{{ subnets }}"
tags: subnets
In my environment, I will have some subnets that will have gateway configured, some not. I would like to create a workaround to make it possible configuring gateway ip for some servers and for some of them not.
I have tried yet to configure it like this, but it will assign also for the ones that do not have the gateway_ip configured in the variable file a gateway. I have tried also the no_gateway_ip option, but for this one I didn't find the proper filter to get a gateway_ip when it is defined in the variable file.
Any way to trick this?
Found the way: no_gateway_ip should be involved, not gateway_ip.
- name: Create the subnets
os_subnet:
cloud: "{{ item.cloud }}"
state: present
validate_certs: no
no_gateway_ip: "{{ not (item.gateway_ip is defined) }}"
dns_nameservers: "{{ item.dns if item.dns is defined else omit }}"
enable_dhcp: yes
name: "{{ item.subnet }}"
network_name: "{{ item.network }}"
cidr: "{{ item.cidr }}"
allocation_pool_start: "{{ item.allocation_pool_start }}"
allocation_pool_end: "{{ item.allocation_pool_end }}"
host_routes: "{{ item.host_routes | default(omit) }}"
with_items:
- "{{ subnets }}"
tags: subnets

How to use variables in with_items in anisble playbook

I have create ansible role to create multiple lambda function, where I am passing some parameters from variable file. My variable file looks like
Variable file
S3BucketName: "test_bucket"
S3Key1: "test.zip"
runtime: "python3.6"
handler1: "test.lambda_handler"
role1: "test_role_arn"
memory_size: "128"
timeout: "180"
s3_key2: "temp.zip"
role2: "temp_role_Arn"
handler2: "temp.lambda_handler"
In my playbook, I am using ansible loop to create multiple aws lambda functions at the same time. when I am using variable in with_items.
Playbook file
- hosts: localhost
roles:
- ansible-lambda
vars_files:
- "ansible-lambda/vars/cf_vars.yaml"
lambda:
name: '{{ item.name }}'
region: "{{ aws_region }}"
state: "{{state}}"
runtime: "{{ runtime }}"
timeout: "{{timeout}}"
memory_size : "{{memory_size}}"
s3_bucket: "{{ S3BucketName}}"
s3_key: '{{ item.s3_key }}'
role: '{{ item.role }}'
handler: '{{ item.handler }}'
with_items:
- name: test
s3_key: "{{ S3Key1 }}" #refering to variable 1
- name: temp
s3_key: "{{ S3Key2 }}" #refering to variable 2
- debug:
msg: "Lambda creation Complete!!"
Following is the error:
fatal: [localhost]: FAILED! => {"msg": "'S3Key1' is undefined"}
This playbook works, when I pass the absolute values instead of variables. I mean s3_key: test.zip
how to use variables in with item?
-------------- var file ---------------
aws_region: austin
lambda_list:
- name: lambda1
state: "UR STATE HERE"
S3BucketName: "test_bucket"
S3Key: "test.zip"
runtime: "python3.6"
handler: "test.lambda_handler"
role_desc: "test_role_arn"
memory_size: "128"
timeout: "180"
- name: lambda2
state: "UR STATE HERE"
S3BucketName: "test_bucket"
S3Key: "test2.zip"
runtime: "python2.7"
handler: "test.lambda_handler"
role_desc: "test_role_ARN"
memory_size: "256"
timeout: "150"
---------------playbook------------------------
- hosts: localhost
vars_files: "ansible-lambda/vars/cf_vars.yaml"
tasks:
lambda:
name: '{{ item.name }}'
region: "{{ aws_region }}"
state: "{{ item.state }}"
runtime: "{{ item.runtime }}"
timeout: "{{ item.timeout }}"
memory_size : "{{ item.memory_size }}"
s3_bucket: "{{ item.S3BucketName }}"
s3_key: "{{ item.s3_key }}"
role: "{{ item.role_desc }}"
handler: "{{ item.handler }}"
with_items:
- "{{ lambda_list }}"
Here's a snippet of the correct way IMHO how to achieve what you're trying to do, sure there are few other ways but to be both efficient and easy config in example above you can see that there's a dict which holds every lambda's info as a key dict, when u use with_items it iterates each key to the task while using the item's data as {{ item.name }}.
You could even put a dict/list in a dict. for exmaple:
lambda_list:
- name: lambda1 # <--- each dash('-') is a key with a value, that value is a dict
S3: #
S3BucketName: "test_bucket"
S3Key: "test.zip"
- name: lambda2
S3: # <-- without the dash its indicated as a list inside the dict.
S3BucketName: "test_bucket"
S3Key: "test2.zip"
in this case to access your nested list you would use {{ item.S3.S3BucketName }} or {{ item['S3']['S3BucketName'] }}
if it was a dict in a dict you would get the key/value of each key without a proper way to access a specific key(with loops you can iterate the dict and use 'when' to get the desired key.)
Here's few references worth reading about loops, dicts and how to access them.
http://ansible-docs.readthedocs.io/zh/stable-2.0/rst/playbooks_loops.html#nested-loops

How can i assign a varaible in a variable

Here's my task.
- name: Add A record for "{{ ec2_hostname }}.{{ internal_domain }}"
route53:
command: create
zone: "{{ internal_domain }}"
private_zone: "{{ private_type }}"
record: "{{ ec2_hostname }}.{{ internal_domain }}"
type: A
ttl: 300
value: "{{ ansible_ec2_[ec2_r53_type]_ipv4 }}"
Specifically having trouble with this line:
value: "{{ ansible_ec2_[ec2_r53_type]_ipv4 }}"
I need to insert ec2_r53_type inside a string to create another variable. This should be either "public" or "local".
So the expected result should be
value: "{{ ansible_ec2_local_ipv4 }}"
or
value: "{{ ansible_ec2_public_ipv4 }}"
Whats the logic here, tried all i knew no luck
This should work
value: "{{ vars['ansible_ec2_' + ec2_r53_type + '_ipv4'] }}"
- find: ^CODEDEPLOY_USER=""
replace: CODEDEPLOY_USER=""{{ app_install_user }}""
"/"{{ app_install_user }}/"" something as such, This is on the vars folder of a play
I would require to add the variable in qoutes on the vars of roles.
roles/xxxx/vars/main.yml
app_install_user is added on group_vars of ansible

Resources