I have an Ansible play-book for working with EC2 instances. I'm using dynamic inventory (ec2.py) to get the group of instances that I want to work with (hosts: tag_Service_Foo). When I run it, it produces output like:
GATHERING FACTS ***************************************************************
ok: [54.149.9.198]
ok: [52.11.22.29]
ok: [52.11.0.3]
However, I can fetch the "Name" tag for a particular instance from Amazon (I do this and store it in a variable for use in a couple parts of the playbook).
Is there a way to get Ansible to use this string for the hostname when displaying progress? I'd like to see something more descriptive (since I don't have the IPs memorized):
GATHERING FACTS ***************************************************************
ok: [main-server]
ok: [extra-server]
ok: [my-cool-server]
The output of the ec2.py inventory script looks like this (truncated; it's very long).
{
"_meta": {
"hostvars": {
"54.149.9.198": {
"ec2__in_monitoring_element": false,
"ec2_ami_launch_index": "0",
"ec2_architecture": "x86_64",
"ec2_client_token": "xxx",
"ec2_dns_name": "xxx",
"ec2_ebs_optimized": false,
"ec2_eventsSet": "",
"ec2_group_name": "",
"ec2_hypervisor": "xen",
"ec2_id": "i-xxx",
"ec2_image_id": "ami-xxx",
"ec2_instance_type": "xxx",
"ec2_ip_address": "xxx",
"ec2_item": "",
"ec2_kernel": "",
"ec2_key_name": "xxx",
"ec2_launch_time": "xxx",
"ec2_monitored": xxx,
"ec2_monitoring": "",
"ec2_monitoring_state": "xxx",
"ec2_persistent": false,
"ec2_placement": "xxx",
"ec2_platform": "",
"ec2_previous_state": "",
"ec2_previous_state_code": 0,
"ec2_private_dns_name": "xxx",
"ec2_private_ip_address": "xxx",
"ec2_public_dns_name": "xxx",
"ec2_ramdisk": "",
"ec2_reason": "",
"ec2_region": "xxx",
"ec2_requester_id": "",
"ec2_root_device_name": "/dev/xvda",
"ec2_root_device_type": "ebs",
"ec2_security_group_ids": "xxx",
"ec2_security_group_names": "xxx",
"ec2_sourceDestCheck": "true",
"ec2_spot_instance_request_id": "",
"ec2_state": "running",
"ec2_state_code": 16,
"ec2_state_reason": "",
"ec2_subnet_id": "subnet-xxx",
"ec2_tag_Name": "main-server",
"ec2_tag_aws_autoscaling_groupName": "xxx",
"ec2_virtualization_type": "hvm",
"ec2_vpc_id": "vpc-xxx"
}
}
}
"tag_Service_Foo": [
"54.149.9.198",
"52.11.22.29",
"52.11.0.3"
],
}
What you need to do is create your own wrapper (say my_ec2.py) over the ec2.py that would post process the output. Idea is to use the behavioral hostvar ansible_ssh_host. You can use any language not only python. As long as it prints valid json on stdout you're good to go. Reference if needed.
It'll be a tiny bit of work. But hope the sudo code would help:
output_json_map = new map
for each group in <ec2_output>: # e.g. tag_Service_Foo, I think there would be another
# key in the output that contains list of group names.
for each ip_address in group:
hname = ec2_output._meta.hostvars.find(ip_address).find(ec2_tag_Name)
# Add new host to the group member list
output_json_map.add(key=group, value=hname)
copy all vars from ec2_output._meta.hostvars.<ip_address>
to output_json_map._meta.hostvars.<hname>
# Assign the IP address of this host to the ansible_ssh_host
# in hostvars for this host
output_json_map.add(key=_meta.hostvars.<hname>.ansible_ssh_host,
value=ip_address)
output_json_map.add(key=_meta.hostvars.find(ip_address).ansible_ssh_host,
value=ip_address)
print output_json_map to stdout
E.g. for your example the output of my_ec2.py should be:
{
"_meta": {
"hostvars": {
"main-server": {
"ansible_ssh_host": "54.149.9.198"
--- snip ---
"ec2_tag_Name": "main-server",
--- snip ---
},
"extra-server": {
"ansible_ssh_host": "52.11.22.29"
--- snip ---
"ec2_tag_Name": "extra-server",
--- snip ---
},
<other hosts from all groups>
}
}
"tag_Service_Foo": [
"main-server",
"extra-server",
<other hosts in this group>
],
"some other group": [
<hosts in this group>,
...
],
}
and obviously, use this my_ec2.py instead of ec2.py as the inventory file. :-)
-- edit --
1) In the groups, can I only refer to things by one name? 2) There's no notion of an alias? 3) I'm wondering if I could use the IP addr in the groups and just modify the _meta part or if I need to do it all?
Yes*, No and no.
* Technically first yes should be no. Let me explain.
What we are doing here can be done with static inventory file like this:
Original ec2.py was returning json equivalent of following inventory file:
[tag_Service_Foo]
54.149.9.198 ec2_tag_Name="main-server" ec2_previous_state_code="0" ...
52.11.22.29 ec2_tag_Name="extra-server" ec2_previous_state_code="0" ...
our new my_ec2.py returns this:
[tag_Service_Foo]
main-server ansible_ssh_host="54.149.9.198" ec2_tag_Name="main-server" ec2_previous_state_code="0" ...
extra-server ansible_ssh_host="52.11.22.29" ec2_tag_Name="extra-server" ec2_previous_state_code="0" ...
# Technically it's possible to create "an alias" for main-server like this:
main-server-alias ansible_ssh_host="54.149.9.198" ec2_tag_Name="main-server" ec2_previous_state_code="0" ...
Now you would be able to run a play with main-server-alias in the host list and ansible would execute it on 54.149.9.198.
BUT, and this is a big BUT, when you run a play with 'all' as the host pattern ansible would run the task on main-server-alias as well as main-server. So what you created is an alias in one context and a new host in another. I've not tested this BUT part so do come back and correct me if you find out otherwise.
HTH
If you put
vpc_destination_variable = Name
in your ec2.ini file, that should work too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With