How to set a variable using dynamic inventory using Ansible - amazon-web-services

I am looking for method to set a variable in ansible playbook using inventory information received from dynamic inventory.
For example if we have a sample playbook like
---
- hosts: localhost
connection: local
tasks:
- set_fact: rds_hostname="{{ rds_mysql }}" #set rds endpoint from ec2.py
- debug: var=rds_hostname
I am able to get the endpoint when I run the plain ec2.py script as
"rds_mysql":{
"rds_mysql.shdahfiahfa.us-easy-1.rds.amazon.com"
}
However I wish to set rds_hostname as the endpoint recieved from dynamic_inventory.
Can any one point out my mistake. Thank you

I was able to solve my above problem by using something like this
set_fact: rds_hostname="{{ groups.rds_mysql[0] }}"
Also during my research I found a nice ansible galaxy code which allows you to dump all variables accessible to ansible-playbooks
https://galaxy.ansible.com/list#/roles/646
Hope this helps someone :)

Related

Ansible + AWS EC2 Plugin + username + ssh key on the dynamic inventory file

I'm using the aws_ec2 plugin to get my inventory on AWS but I need some help.
I want to set the 'ansible_user' and 'ansible_ssh_private_key_file' on the dynamic inventory file but I cant get it work. ¿Is this possible? So I don't need to set the '--private-key' and '-u' options on the command line.
This is my current aws_ec2.yaml:
---
plugin: aws_ec2
aws_access_key: 123
aws_secret_key: 345
filters:
tag:Cliente: CustName
instance-state-name : running
Any Idea?
Thanks!
You can create and load dynamic variables for each Ansible host group. You need to create appropriate files on your inventory directory. For example: Say you have configured your ansible.cfg file with the inventory key pointing to the relative path ./inventory. This tells Ansible that it should look inside a file called ./inventory or a series of files inside the ./inventory folder for the host group's information.
You tell Ansible to load different variables for each group just by following the appropriate convention for the folder structure:
./inventory/group_vars: will hold group variables.
./inventory/host_vars: will hold host variables.
Ansible will use the file's name inside each of these folders to reference the appropriate group or host. You can also use sub-directories with the group's name if you want to use multiple files to hold all the variables.
It's important that your aws_ec2.yml file be located inside the ./inventory directory.
For example: if you wanted to store the appropriate user and key configuration to access EC2 instances tagged with the Project tag set to stackoverflow, you would need to create a directory at ./inventory/group_vars/tag_Project_stackoverflow with a variables file like the following:
ansible_user: ec2-user
ansible_ssh_private_key_file: ~/.ssh/id_rsa
The EC2 dynamic inventory module can create dynamic groups from the configuration of your EC2 instances. Check its documentation to see how to configure it.
You can even create these files dynamically using tasks. Here I create a new ec2 key, store it locally, and create the necessary folder structure to hold the connection information:
- name: Create a new EC2 key
amazon.aws.ec2_key:
name: "{{ ec2_key_name }}"
register: ec2_key_output
- name: Save private key
ansible.builtin.copy:
content: "{{ ec2_key_output.key.private_key }}"
dest: "{{ ec2_key_path }}"
mode: 0600
when: ec2_key_output.changed == True
- name: Create the group_vars folder
ansible.builtin.file:
path: ./inventory/group_vars
state: directory
mode: '0755'
- name: Create the group_vars configuration file
ansible.builtin.copy:
content: |
ansible_user: "{{ ec2_user }}"
ansible_ssh_private_key_file: "{{ ec2_key_path }}"
dest: ./inventory/group_vars/tag_Project_stackoverflow
Please check out Ansible's documentation regarding inventory management for more information.

Ansible Keepass integration via python script

i am very new to ansible and would like to test a few things.
I have a couple of Amazon EC2 instances and would like to install different software components on them. I don't want to have the (plaintext) credentials of the technical users inside of ansible scripts or config files. I know that it is possible to encrypt those files, but I want to try keepass for a central password management tool. So my installation scripts should read the credentials from a .kdbx (Keepass 2) database file before starting the actual installation.
Till now i wrote a basic python script for reading the .kdbx file. The script outputs a json object via:
print json.dumps(inventory, sort_keys=False)
The ouput looks like the following:
{"cdc":
{"cdc_test_server":
{"cdc_test_user":
{"username": "cdc_test_user",
"password": "password"}
}
}
}
Now I want to achieve, that the python script is executed by ansible and the key value pairs of the output are included/registered as ansible variables. So far my playbook looks as follows:
- hosts: 127.0.0.1
connection: local
tasks:
- name: "Test Playboook Functionality"
command: python /usr/local/test.py
register: pass
- debug: var=pass.stdout
- name: "Include json user output"
set_fact: passwords="{{pass.stdout | from_json}}"
- debug: " {{passwords.cdc.cdc_test_server.cdc_test_user.password}} "
The first debug generates the correct json output, but i am not able to include the variables in ansible, so that I can use them via jinja2 notation. set_fact doesn't throw an exception, but the last debug just returns a "Hello world" - message? So my question is: How do I properly include the json key value pairs as ansible variables via task?
See Ansible KeePass Lookup Plugin
ansible_user : "{{ lookup('keepass', 'path/to/entry', 'username') }}"
ansible_become_pass: "{{ lookup('keepass', 'path/to/entry', 'password') }}"
You may want to use facts.d and place your python script there to be available as a fact.
Or write a simple action plugin that returns json object to eliminate the need in stdout->from_json conversion.
Late to the party, but it seems your use case is primarily covered by keepass-inventory. And it doesn't require any playbook "magic". Disclaimer: I contribute to this non-profit.
export KDB_PATH=example.kdbx
export KDB_PASS=example
ansible all --list-hosts -i keepass-inventory.py

Ansible - On error, exit role and run cleanup

I'm trying to spin up an AWS deployment environment in Ansible, and I want to make it so that if something fails along the way, Ansible tears down everything on AWS that has been spun up so far. I can't figure out how to get Ansible to throw an error within the role
For example:
<main.yml>
- hosts: localhost
connection: local
roles:
- make_ec2_role
- make_rds_role
- make_s3_role
2. Then I want it to run some code based on that error here.
<make_rds_role>
- name: "Make it"
- rds:
params: etc <-- 1. Let's say it fails in the middle here
I've tried:
- name: this command prints FAILED when it fails
command: /usr/bin/example-command -x -y -z
register: command_result
failed_when: "'FAILED' in command_result.stderr"
As well as other things on within the documentation, but what I really want is just a way to use something like the "block" and "rescue" commands , but as far as I can tell that only works within the same book and on plays, not roles. Does anyone have a good way to do this?
Wrap tasks inside your roles into block/rescue thing.
Make sure that rescue block has at least one task – this way Ansible will not mark the host as failed.
Like this:
- block:
- name: task 1
... # something bad may happen here
- name: task N
rescue:
- assert: # we need a dummy task here to prevent our host from being failed
that: ansible_failed_task is defined
Recent versions of Ansible register ansible_failed_task and ansible_failed_result when hit rescue block.
So you can do some post_tasks in your main.yml playbook like this:
post_tasks:
- debug:
msg: "Failed task: {{ ansible_failed_task }}, failed result: {{ ansible_failed_result }}"
when: ansible_failed_task is defined
But be warned that this trick will NOT prevent other roles from executing.
So in your example if make_rds_role fails ansible will apply make_s3_role and run your post_tasks afterwards.
If you need to prevent it, add some checking for ansible_failed_task fact in the beginning of each role or something.

ansible ec2.py / boto EC2 validation

I'm writing a playbook to validate our Cloud Formation stacks (port 80 open, httpd.conf has correct settings, instance type is correct, etc). The one thing that is tripping me up is how to validate EC2 tags.
key=Name, value=testec2
I've tried the below and changed the when condition multiple different ways.
- name: Check Name Tag
action: debug msg="Name Tag Exists."
when: "ec2_tag_Name"
[Examples tried]
when: "tag_Name_testec2"
when: " ec2_tag_Name_testec2"
when: "ec2_tag_Name"
I've actually tried quite a few more varieties but those are the ones I can easily remember off the top of my head.
when i run "ec2.py --list" it outputs multiple formats of the tag
"ec2_tag_Name": "testec2",
"tag_Name_testec2": [
Any suggestions would be greatly appreciated.
I use tag_Name_testec2 but this is a group in hostsvars. Is not a common variable. To avoid troubles, first change in your ec2.ini, the cache max age, from 20 to 1:
cache_max_age = 1
and see if you have some filter like region or public or private ip.
You could debug you hostvars with this way:
[batman#myhost myproject]$ ansible -i ec2.py tag_Name_webserver -u ec2-user -m debug -a msg="{{ hostvars[inventory_hostname]['ec2_id'] }}" -vvv
Using /etc/ansible/ansible.cfg as config file
10.78.17.117 | SUCCESS => {
"msg": "i-b34cb736"
}
In case anyone is interested, I finally figured it out. Feel free to point and laugh for not noticing "is defined" missing.
name: Check Name Tag Types
action: debug msg="Name tag exists."
when: "ec2_tag_Name is defined"

Ansible - How to launch(purchase) a reserved EC2 instance

How can I launch(purchase) a reserved EC2 instance using Ansible with EC2 module? I've googled using words something like 'ec2 reserved instance ansible' but no joy.
Or should I use AWS CLI instead?
Or you can create Ansible module.
Also there are already created modules that you can use as examples ansible-modules-extras/cloud/amazon.
PS:
Modules can be written in any language and are found in the path
specified by ANSIBLE_LIBRARY or the --module-path command line option.
By default, everything that ships with ansible is pulled from its
source tree, but additional paths can be added.
The directory ”./library”, alongside your top level playbooks, is also
automatically added as a search directory.
I just made a PR which might help you.
You could use it as follows:
- name: Purchase reserved instances
boto3:
name: ec2
region: us-east-1
operation: purchase_reserved_instances_offering
parameters:
ReservedInstancesOfferingId: 9a06095a-bdc6-47fe-a94a-2a382f016040
InstanceCount: 3
LimitPrice:
Amount: 123.0
CurrencyCode: USD
register: result
- debug: var=result
If you're interrested by this feature, feel free to vote up on the PR. :)
I looked into the Cloud module list and found there isn't any modules out of the box that supports reserved instance - I think you try building a wrapper over the AWS CLI or Python Boto SDK [ or any SDK ].
This is the pseudo code for the playbook :
---
- hosts: localhost
connection: local
gather_facts: false
tasks:
- name: 'Calling Python Code to reserve instance'
raw: python reserve-ec2-instance.py args