Get a value from a variable key in dictionary - amazon-web-services

I have a variable env: prod and I am trying to get the value from a prod list for a specific zone.
properties are like below
prod:
us-west-2a: xxxxxxxx
us-west-2b: xxxxxxxx
us-east-1a: xxxxxxxx
us-east-1b: xxxxxxxx
- set_fact:
reg: "{{ ansible_ec2_placement_availability_zone }}"
- set_fact:
detach_volumeid: '{{ vars[env].'reg' }}'
I am trying to get the value of prod region volume id where prod is a variable and reg is a variable.

A specific dictionary key can be addressed with the dot (.) notation but can also be addressed with the brackets notation [].
When you want to address a key as a variable, you will use the later form.
So given the playbook:
- hosts: all
gather_facts: no
tasks:
- debug:
msg: '{{ vars[env][reg] }}'
vars:
env: prod
reg: us-east-1a
prod:
us-west-2a: xxxxxxxx-w-2a
us-west-2b: xxxxxxxx-w-2b
us-east-1a: xxxxxxxx-e-1a
us-east-1b: xxxxxxxx-e-1b
This yields the recap:
PLAY [all] ********************************************************************************************************
TASK [debug] ******************************************************************************************************
ok: [localhost] => {
"msg": "xxxxxxxx-e-1a"
}
PLAY RECAP ********************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Related

Ansible regex replace String

I am trying to replace the unnecessary words from the below string using regex_replace but unable to do to so for the last part of it.
String: Test_[u'Net::Route Domain: RD2001']
Regex being used: regex_replace('.*: (.*)$', '\\1')
Output printing: Test_RD2001']
Expected Output: Test_RD2001
Could someone suggest how can I get rid of the last characters after RDXXXX.
Also this RDXXXX number is dynamic.
As dicussed in comments, you should try to fix the data source. However, here is the regex to print the expected result:
---
- name: Sample playbook
connection: local
#gather_facts: false
hosts: localhost
vars:
String: "Test_[u'Net::Route Domain: RD2001']"
tasks:
- debug:
msg: "{{ String| regex_replace('^(\\w+)\\[.*:\\s+([\\w]+).*', '\\1\\2') }}"
Results:
PLAY [Sample playbook] ***************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************
ok: [localhost]
TASK [debug] *************************************************************************************************************************
ok: [localhost] => {
"msg": "Test_RD2001"
}
PLAY RECAP ***************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

ansible: Extract value from the register variables to use it in other plays within same playbook

I'm setting up complete environment using ansible. For some reason, ansible is not picking up variable values.
I'm using ansible 2.1.1.0
Here's a strip example of what I'm trying to do:
I have registered my vpc with register: ec2_vpc.
1. #This didn't works
- name: Add to host vars
add_host:
name: vpc_vars
groups: vpc_subnets
vpc_subnet_id: "{{ ec2_vpc.subnets[0].id }}"
vpcid: "{{ ec2_vpc.vpc_id }}"
- debug: var=vpc_subnet_id
- debug: var=vpcid
2. These works
- name: Record vpc id
debug: var=ec2_vpc.vpc_id
- name: Record subnet id
debug: var=ec2_vpc.subnets[0].id
Resulted json of my above strip:
TASK [debug] *******************************************************************
ok: [localhost] => {
"vpc_subnet_id": "VARIABLE IS NOT DEFINED!"
}
TASK [debug] *******************************************************************
ok: [localhost] => {
"vpcid": "VARIABLE IS NOT DEFINED!"
}
TASK [Record vpc id] ***********************************************************
ok: [localhost] => {
"ec2_vpc.vpc_id": "vpc-4sdh3832f"
}
TASK [Record subnet id] ********************************************************
ok: [localhost] => {
"ec2_vpc.subnets[0].id": "subnet-edfjdh3482"
}
Why is my first syntax not picking the value instead its giving VARIABLE IS NOT DEFINED!
Updated: Here my 2nd syntax describes I am correctly sorting out the value from the JSON result of registered variable. But I want it work for my 1st syntax which means I want to add hosts variables to dynamic inventory. So that I can reuse it in another play
add_host dynamically adds host to your inventory.
I guess you just need set_fact:
- name: Add to host vars
set_fact:
vpc_subnet_id: "{{ ec2_vpc.subnets[0].id }}"
vpcid: "{{ ec2_vpc.vpc_id }}"
- debug: var=vpc_subnet_id
- debug: var=vpcid
As you said that you have register your return value/result in ec2_vpc then how you can get it vpc_subnet_id or vpcid. you want to get it through this then you have to do like this:
- set_fact:
vpc_subnet_id: "{{ ec2_vpc.subnets[0].id }}"
vpcid: "{{ ec2_vpc.vpc_id }}"
Hope that help you.

AWS provision with ansible

I am getting and error when I want to provision an ec2. This is how i set up my environment.
I put my aws credentials in ~/.boto
cat /etc/ansible/hosts
[local]
localhost
cat /etc/ansible/ec2-vars/testserver.yml
ec2_keypair: "ansible"
ec2_security_group: "sg-*******"
ec2_instance_type: "t2.micro"
ec2_image: "ami-********"
ec2_subnet_ids: ['subnet-*******','subnet-REDACTED','subnet-REDACTED']
ec2_region: "us-east-1"
ec2_tag_Name: "testserver"
ec2_tag_Type: "testserver"
ec2_tag_Environment: "development"
ec2_volume_size: 8
cat /etc/ansible/provision-ec2.yml
---
- hosts: localhost
connection: local
gather_facts: false
user: root
pre_tasks:
- include_vars: ec2_vars/{{type}}.yml
roles:
- provision-ec2
cat /etc/ansible/roles/provision-ec2/tasks/main.yml
---
- name: Provision EC2 Box
local_action:
module: ec2
key_name: "{{ ec2_keypair }}"
group_id: "{{ ec2_security_group }}"
instance_type: "{{ ec2_instance_type }}"
image: "{{ ec2_image }}"
vpc_subnet_id: "{{ ec2_subnet_ids|random }}"
region: "{{ ec2_region }}"
instance_tags: '{"Name":"{{ec2_tag_Name}}","Type":" {{ec2_tag_Type}}","Environment":"{{ec2_tag_Environment}}"}'
assign_public_ip: yes
wait: true
count: 1
volumes:
- device_name: /dev/sda1
device_type: gp2
volume_size: "{{ ec2_volume_size }}"
delete_on_termination: true
register: ec2
- debug: var=item
with_items: ec2.instances
- add_host: name={{ item.public_ip }} >
groups=tag_Type_{{ec2_tag_Type}},tag_Environment_{{ec2_tag_Environment}}
ec2_region={{ec2_region}}
ec2_tag_Name={{ec2_tag_Name}}
ec2_tag_Type={{ec2_tag_Type}}
ec2_tag_Environment={{ec2_tag_Environment}}
ec2_ip_address={{item.public_ip}}
with_items: ec2.instances
- name: Wait for the instances to boot by checking the ssh port
wait_for: host={{item.public_ip}} port=22 delay=60 timeout=320 state=started
with_items: ec2.instances
Now I run the following command and this is what i get.
[root#ip-**-**-*** ansible]# ansible-playbook -vv -i localhost, -e "type=testservers" provision-ec2.yml
Using /etc/ansible/ansible.cfg as config file
PLAYBOOK: provision-ec2.yml ****************************************************
1 plays in provision-ec2.yml
PLAY [localhost] ***************************************************************
TASK [include_vars] ************************************************************
task path: /etc/ansible/provision-ec2.yml:7
fatal: [localhost]: FAILED! => {"changed": false, "failed": true, "file": "/etc/ansible/ec2_vars/testservers.yml", "msg": "Source file not found."}
NO MORE HOSTS LEFT *************************************************************
to retry, use: --limit #provision-ec2.retry
PLAY RECAP *********************************************************************
localhost : ok=0 changed=0 unreachable=0 failed=1
please help.
New error:
TASK [provision-ec2 : Provision EC2 Box] ***************************************
task path: /etc/ansible/roles/provision-ec2/tasks/main.yml:2
fatal: [localhost -> localhost]: FAILED! => {"changed": false, "failed": true, "msg": "No handler was ready to authenticate. 1 handlers were checked. ['HmacAuthV4Handler'] Check your credentials"}
NO MORE HOSTS LEFT *************************************************************
to retry, use: --limit #provision-ec2.retry
PLAY RECAP *********************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=1
You are mixing underscore and hyphen.
cat /etc/ansible/ec2-vars/testserver.yml
include_vars: ec2_vars/{{type}}.yml

Creating n new instances in AWS EC2 VPC and then configuring them

I'm having a really hard time doing what seems like a fairly standard task so I'm hoping somebody can help me. I've googled this like crazy and most of the examples are not in VPC or use deprecated structure that makes them wrong or unusable in my use case.
Here are my goals:
I want to launch a whole mess of new instances in my VPC (the same
code below has 3 but it could be a hundred)
I want to wait for thoseinstances to come alive
I then want to configure those instances (ssh into them, change
hostname, enable some services, etc. etc.)
Now I could probably do this in 2 tasks. I could create the instances in 1 playbook. Wait for them to settle down. Then run a 2nd playbook to configure them. That's probably what I'm going to do now because I want to get moving - but there has to be a one shot answer to this.
Here's what I have so far for a playbook
---
- hosts: localhost
connection: local
gather_facts: False
tasks:
- name: Provision Lunch
with_items:
- hostname: eggroll1
- hostname: eggroll2
- hostname: eggroll3
ec2:
region: us-east-1
key_name: eggfooyong
vpc_subnet_id: subnet-8675309
instance_type: t2.micro
image: ami-8675309
wait: true
group_id: sg-8675309
exact_count: 1
count_tag:
Name: "{{ item.hostname }}"
instance_tags:
Name: "{{ item.hostname }}"
role: "supper"
ansibleowned: "True"
register: ec2
- name: Wait for SSH to come up
wait_for: host={{ item.private_ip }} port=22 delay=60 timeout=900 state=started
with_items: '{{ec2.instances}}'
- name: Update hostname on instances
hostname: name={{ item.private_ip }}
with_items: '{{ec2.instances}}'
And that doens't work. What I get is
TASK [Wait for SSH to come up] *************************************************
[DEPRECATION WARNING]: Skipping task due to undefined Error, in the future this will be a fatal error.. This feature will be removed in a future release. Deprecation warnings can be disabled by setting
deprecation_warnings=False in ansible.cfg.
TASK [Update hostname on instances] ********************************************
[DEPRECATION WARNING]: Skipping task due to undefined Error, in the future this will be a fatal error.. This feature will be removed in a future release. Deprecation warnings can be disabled by setting
deprecation_warnings=False in ansible.cfg.
Which makes me sad. Now this is my latest incarnation of that playbook. But I've tried to rewrite it using every example I can find on the internet. Most of them have with_items written in a different way, but ansible tells me that way is depricated, and then fails.
So far ansible has been fun and easy, but this is making me want to toss my laptop across the street.
Any suggestions? Should I be using register and with_items at all? Would I be better off using something like this:
add_host: hostname={{item.public_ip}} groupname=deploy
instead? I'm wide open to a rewrite here. I'm going to go write this up in 2 playbooks and would love to get suggestions.
Thanks!
****EDIT****
Now it's just starting to feel broken or seriously changed. I've googled dozens of examples and they all are written the same way and they all fail with the same error. This is my simple playbook now:
---
- hosts: localhost
connection: local
gather_facts: False
vars:
builderstart: 93
builderend: 94
tasks:
- name: Provision Lunch
ec2:
region: us-east-1
key_name: dakey
vpc_subnet_id: subnet-8675309
instance_type: t2.micro
image: ami-8675309
wait: True
group_id: sg-OU812
exact_count: 1
count_tag:
Name: "{{ item }}"
instance_tags:
Name: "{{ item }}"
role: "dostuff"
extracheese: "True"
register: ec2
with_sequence: start="{{builderstart}}" end="{{builderend}}" format=builder%03d
- name: the newies
debug: msg="{{ item }}"
with_items: "{{ ec2.instances }}"
It really couldn't be more straight forward. No matter how I write it, no matter how I vary it, I get the same basic error:
[DEPRECATION WARNING]: Skipping task due to undefined Error, in the
future this will be a fatal error.: 'dict object' has no attribute
'instances'.
So it looks like it's the with_items: "{{ ec2.instances }}" line that's causing the error.
I've used debug to print out ec2 and that error looks accurate. It looks like the structure changed to me. It looks like ec2 now contains a dictionary with results as a key to another dictionary object and that instances is a key in that dictionary. But I can't find a sane way to access the data.
For what it's worth, I've tried accessing this in 2.0.1, 2.0.2, and 2.2 and I get the same problem in every case.
Are the rest of you using 1.9 or something? I can't find an example anywhere that works. It's very frustrating.
Thanks again for any help.
Don't do it like this:
- name: Provision Lunch
with_items:
- hostname: eggroll1
- hostname: eggroll2
- hostname: eggroll3
ec2:
region: us-east-1
Because by using it you flushing all info from ec2 in your item.
You receiving following output:
TASK [Launch instance] *********************************************************
changed: [localhost] => (item={u'hostname': u'eggroll1'})
changed: [localhost] => (item={u'hostname': u'eggroll2'})
but item should be like this:
changed: [localhost] => (item={u'kernel': None, u'root_device_type': u'ebs', u'private_dns_name': u'ip-172-31-29-85.ec2.internal', u'public_ip': u'54.208.138.217', u'private_ip': u'172.31.29.85', u'id': u'i-003b63636e7ffc27c', u'ebs_optimized': False, u'state': u'running', u'virtualization_type': u'hvm', u'architecture': u'x86_64', u'ramdisk': None, u'block_device_mapping': {u'/dev/sda1': {u'status': u'attached', u'delete_on_termination': True, u'volume_id': u'vol-37581295'}}, u'key_name': u'eggfooyong', u'image_id': u'ami-fce3c696', u'tenancy': u'default', u'groups': {u'sg-aabbcc34': u'ssh'}, u'public_dns_name': u'ec2-54-208-138-217.compute-1.amazonaws.com', u'state_code': 16, u'tags': {u'ansibleowned': u'True', u'role': u'supper'}, u'placement': u'us-east-1d', u'ami_launch_index': u'1', u'dns_name': u'ec2-54-208-138-217.compute-1.amazonaws.com', u'region': u'us-east-1', u'launch_time': u'2016-04-19T08:19:16.000Z', u'instance_type': u't2.micro', u'root_device_name': u'/dev/sda1', u'hypervisor': u'xen'})
Try to use following code
- name: Create a sandbox instance
hosts: localhost
gather_facts: False
vars:
keypair: eggfooyong
instance_type: t2.micro
security_group: ssh
image: ami-8675309
region: us-east-1
subnet: subnet-8675309
instance_names:
- eggroll1
- eggroll2
tasks:
- name: Launch instance
ec2:
key_name: "{{ keypair }}"
group: "{{ security_group }}"
instance_type: "{{ instance_type }}"
image: "{{ image }}"
wait: true
region: "{{ region }}"
vpc_subnet_id: "{{ subnet }}"
assign_public_ip: no
count: "{{ instance_names | length }}"
register: ec2
- name: tag instances
ec2_tag:
resource: '{{ item.0.id }}'
region: '{{ region }}'
tags:
Name: '{{ item.1 }}'
role: "supper"
ansibleowned: "True"
with_together:
- '{{ ec2.instances }}'
- '{{ instance_names }}'
- name: Wait for SSH to come up
wait_for: host={{ private_ip }} port=22 delay=60 timeout=320 state=started
with_items: '{{ ec2.instances }}'
Assumption that your ansible host located inside of VPC
To achieve this goal, I have written a really small filter plugin get_ec2_info.
Create a directory with the named filter_plugins
Create a plugin file get_ec2_info.py with the following content:
from jinja2.utils import soft_unicode
class FilterModule(object):
def filters(self):
return {
'get_ec2_info': get_ec2_info,
}
def get_ec2_info(list, ec2_key):
ec2_info = []
for item in list:
for ec2 in item['instances']:
ec2_info.append(ec2[ec2_key])
return ec2_info
Then you can use this in your playbook:
---
- hosts: localhost
connection: local
gather_facts: False
tasks:
- name: Provision Lunch
ec2:
region: us-east-1
key_name: eggfooyong
vpc_subnet_id: subnet-8675309
instance_type: t2.micro
image: ami-8675309
wait: true
group_id: sg-8675309
exact_count: 1
count_tag:
Name: "{{ item.hostname }}"
instance_tags:
Name: "{{ item.hostname }}"
role: "supper"
ansibleowned: "True"
register: ec2
with_items:
- hostname: eggroll1
- hostname: eggroll2
- hostname: eggroll3
- name: Create SSH Group to login dynamically to EC2 Instance(s)
add_host:
hostname: "{{ item }}"
groupname: my_ec2_servers
with_items: "{{ ec2.results | get_ec2_info('public_ip') }}"
- name: Wait for SSH to come up on EC2 Instance(s)
wait_for:
host: "{{ item }}"
port: 22
state: started
with_items: "{{ ec2.results | get_ec2_info('public_ip') }}"
# CALL THE DYNAMIC GROUP IN THE SAME PLAYBOOK
- hosts: my_ec2_servers
become: yes
remote_user: ubuntu
gather_facts: yes
tasks:
- name: DO YOUR TASKS HERE
EXTRA INFORMAITON:
using ansible 2.0.1.0
assuming you are spinning up ubuntu instances, if not then change the value in remote_user: ubuntu
assuming ssh key is properly configured
Please consult these github repos for more help:
ansible-aws-role-1
ansible-aws-role-2
I thinks this would be helpful for debug.
https://www.middlewareinventory.com/blog/ansible-dict-object-has-no-attribute-stdout-or-stderr-how-to-resolve/
The ec2 register is a dict type. And it has a key results.
results key has many elements including dict and list like below:
{
"msg": {
"results": [
{
"invocation": {
},
"instances": [],
"changed": false,
"tagged_instances": [
{
}
],
"instance_ids": null,
"failed": false,
"item": [
],
"ansible_loop_var": "item"
}
],
"msg": "All items completed",
"changed": false
},
"_ansible_verbose_always": true,
"_ansible_no_log": false,
"changed": false
}
So, you can get the desired data using ., for instance, item.changed which has false boolean value.
- debug:
msg: "{{ item.changed }}"
loop: "{{ ec2.results }}"

'ansible_date_time' is undefined

Trying to register an ec2 instance in AWS with Ansible's ec2_ami module, and using current date/time as version (we'll end up making a lot of AMIs in the future).
This is what I have:
- name: Create new AMI
hosts: localhost
connection: local
gather_facts: false
vars:
tasks:
- include_vars: ami_vars.yml
- debug: var=ansible_date_time
- name: Register ec2 instance as AMI
ec2_ami: aws_access_key={{ ec2_access_key }}
aws_secret_key={{ ec2_secret_key }}
instance_id={{ temp_instance.instance_ids[0] }}
region={{ region }}
wait=yes
name={{ ami_name }}
with_items: temp_instance
register: new_ami
From ami_vars.yml:
ami_version: "{{ ansible_date_time.iso8601 }}"
ami_name: ami_test_{{ ami_version }}
When I run the full playbook, I get this error message:
fatal: [localhost]: FAILED! => {"failed": true, "msg": "ERROR! ERROR! ERROR! 'ansible_date_time' is undefined"}
However, when run the debug command separately, from a separate playbook, it works fine:
- name: Test date-time lookup
hosts: localhost
connection: local
tasks:
- include_vars: ami_vars.yml
- debug: msg="ami version is {{ ami_version }}"
- debug: msg="ami name is {{ ami_name }}"
Result:
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "ami version is 2016-02-05T19:32:24Z"
}
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "ami name is ami_test_2016-02-05T19:32:24Z"
}
Any idea what's going on?
Remove this:
gather_facts: false
ansible_date_time is part of the facts and you are not gathering it.
> cat tasks/test.yml
---
- hosts: node
gather_facts: no
tasks:
- setup:
gather_subset:
- min
- name: q
debug: var=ansible_date_time.epoch
and run
> ansible-playbook -i conf/share_var.conf tasks/test.yml --private-key=/root/.ssh/id_rsa -u ${USER} -b --become-method=sudo
PLAY [node] ********************************************************************************************************************************************************************************************************************************
TASK [setup] *******************************************************************************************************************************************************************************************************************************
ok: [xxxx.94.182]
ok: [xxxx.94.183]
ok: [xxxx.94.181]
TASK [q] ***********************************************************************************************************************************************************************************************************************************
ok: [xxxx.94.181] => {
"ansible_date_time.epoch": "1636712223"
}
ok: [xxxx.94.182] => {
"ansible_date_time.epoch": "1636712223"
}
ok: [xxxx.94.183] => {
"ansible_date_time.epoch": "1636712223"
}
PLAY RECAP *********************************************************************************************************************************************************************************************************************************
xxxx.94.181 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
xxxx.94.182 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
xxxx.94.183 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0