From: Best way to launch aws ec2 instances with ansible
- name: Add the newly created EC2 instance(s) to the local host group (located inside the directory)
local_action: lineinfile
dest="/etc/ansibles/aws/hosts"
regexp={{ item.private_ip }}
insertafter="[webserver]" line={{ item.private_ip }}
with_items: "{{ ec2.instances }}"
creates this error:
fatal: [localhost]: FAILED! => {
"failed": true,
"msg": "the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: 'ansible.vars.unsafe_proxy.AnsibleUnsafeText object' has no attribute 'private_ip'\n\n
I have defined variable private_ip: under vars , with a value
I think that the private_ip property in the code above references to the property of the ec2 variable that's used to catch the returned values from the ec2 module (from the last step), no the one that you defined elsewhere.
- name: Launch the new EC2 Instance
local_action: ec2
group={{ security_group }}
instance_type={{ instance_type}}
image={{ image }}
wait=true
region={{ region }}
keypair={{ keypair }}
count={{count}}
register: ec2 (this is where the variable is defined!!!)
Essentially Ansible is complaining that the ec2 variable hasen't got the
attribute 'private_ip'
, so check the preceding code and see how that variable gets defined.
In the example above you're trying to get the private_ip address from aws. Is that really what you want? Most of the time you want the public ip address since that's what you will use to connect to the ec2 machine, provision it, deploy your app etc...
Related
I'm currently trying to further automate VM automation by not having to include the IP address in the variables file. I found nslookup module with dig, but feel I'm going about this the wrong way, for example here is variables file which is read upon creation for details:
# VMware Launch Variables
# If this is a test deployment you must ensure the vm is terminated after use.
vmname: agent5
esxi_datacenter: Datacenter
esxi_cluster: Cluster
esxi_datastore: ds1 # Do not change value.
esxi_template: template-v2
esxi_folder: agents # Folder must be pre-created
# Static IP Addresses
esxi_static_ip: "{{ lookup('dig', '{{ vmname }}.example.com.') }}"
esxi_netmask: 255.255.252.0
esxi_gateway: 10.0.0.1
What I was hoping to do with these was just to have the "esxi_static_ip" but pulled on the fly from a lookup with dig. This, however, in its current state does not work.
What is happening is either the VM launches without an ipv4 address or more often it fails with the following error:
fatal: [localhost -> localhost]: FAILED! => {"changed": false, "msg": "Failed to create a virtual machine : A specified parameter was not correct: spec.nicSettingMap.adapter.ip.ipAddress"}
I get the IP and pass it along, which works when I hard code the esxi_static_ip: in my vmware-lanch-vars.yml file. However, if I use (including the examples) it fails.
The newvm is registered when I run my vmware_guest playbook.
- name: Make virtual machine IP persistant
set_fact:
newvm_ip_address: '{{ newvm.instance.ipv4 }}'
- name: Add host to in memory inventory
add_host:
hostname: "{{ newvm_ip_address }}"
groups: just_created
newvm_ip_address: "{{ newvm.instance.ipv4 }}"
When I run with -vvvv I can see no IP is being attached:
"networks": [
{
"device_type": "vmxnet3",
"gateway": "0.0.0.01",
"ip": "",
"name": "Network",
"netmask": "255.255.252.0",
"type": "static"
}
],
UPDATE 3
When I created a simple playbook it works, just not when I put it into my regular flow, this below works:
---
- hosts: localhost
vars:
vmname: "apim-sb-ng1-agent2"
vm_dig_fqdn: "{{ vmname }}.example.com."
esxi_static_ip: "{{ lookup('dig', vm_dig_fqdn) }}"
tasks:
- debug: msg="{{ esxi_static_ip }}"
I am not sure this is the first problem your are facing (see my comment above), but your jinja2 template expression is wrong.
You cannot use jinja2 expression expansion while already inside a jinja2 expression expansion.
In this case, you have to concatenate your variable and string with the + operator:
esxi_static_ip: "{{ lookup('dig', vmname + '.example.com.') }}"
If your prefer to use jinja2 expansion everywhere, you can separate this in different variables, e.g.:
vm_dig_fqdn: "{{ vmname }}.example.com."
esxi_static_ip: "{{ lookup('dig', vm_dig_fqdn) }}"
How is it possible to add tags with ansible to an allocated elastic ip. There are no Information in the official documentation:
https://docs.ansible.com/ansible/latest/modules/ec2_eip_module.html
The example code would be the following:
- name: provision new instances with ec2
ec2:
keypair: mykey
instance_type: c1.medium
image: ami-40603AD1
wait: yes
group: webserver
count: 3
register: ec2
- name: associate new elastic IPs with each of the instances
ec2_eip:
device_id: "{{ item }}"
loop: "{{ ec2.instance_ids }}"
If I add a tags field then the following error is thrown:
failed: [localhost] (item=i-08d2c1fee9eef9001) => {"ansible_loop_var":
"item", "changed": false, "item": "i-08d2c1fee9eef9001", "msg":
"Unsupported parameters for (ec2_eip) module: tags Supported
parameters include: allow_reassociation, aws_access_key,
aws_secret_key, debug_botocore_endpoint_logs, device_id, ec2_url,
in_vpc, private_ip_address, profile, public_ip, region,
release_on_disassociation, reuse_existing_ip_allowed, security_token,
state, validate_certs, wait_timeout"}
You can use the ec2_tag module to tag EC2 resources.
https://docs.ansible.com/ansible/latest/modules/ec2_tag_module.html#ec2-tag-module
- name: associate new elastic IP with instance
ec2_eip:
device_id: "{{ l_ec2_instance_id }}"
register: l_eip_register
- name: tag the elastic IP
ec2_tag:
resource: "{{ l_eip_register.allocation_id }}"
tags:
Name: webserver
Based on https://github.com/ansible/ansible/pull/55190 I don't think it's currently possible to tag EIPs using ansible modules.
Why does this task (from Best way to launch aws ec2 instances with ansible):
- name: Add the newly created EC2 instance(s) to the local host group (located inside the directory)
local_action: lineinfile
dest="./hosts"
regexp={{ item.public_ip }}
insertafter="[webserver]" line={{ item.public_ip }}
with_items: ec2.instances
create this error?
TASK [Add the newly created EC2 instance(s) to the local host group (located inside the directory)] ********************************************************************
fatal: [localhost]: FAILED! => {"failed": true, "msg": "the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: 'ansible.vars.unsafe_proxy.AnsibleUnsafeText object' has no attribute 'public_ip'\n\nThe error appears to have been in '/Users/snowcrash/ansible-ec2/ec2_launch.yml': line 55, column 9, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - name: Add the newly created EC2 instance(s) to the local host group (located inside the directory)\n ^ here\n"}
the issue is here
with_items: ec2.instances
It should be:
with_items: '{{ ec2.instances }}'
ec2 is variable referencing a dictionary so you will need to reference it with the proper syntax
Put:
- debug: msg="{{ ec2.instances }}"
before that code and inspect what are the contents of that variable. It should be a list of dictionaries that each have a member public_ip, otherwise you'd get the message that you're getting.
The objective is to spin up multiple instances which can be achieved using count but I have been give specific range of private IP addresses, and want to assign them to the instances.
Below is my present playbook,
---
- name: Provision an EC2 Instance
hosts: local
connection: local
gather_facts: False
tags: provisioning
# Necessary Variables for creating/provisioning the EC2 Instance
vars:
instance_type: t2.micro
security_group: default # Change the security group name here
image: ami-a9d276c9 # Change the AMI, from which you want to launch the server
region: us-west-2 # Change the Region
keypair: ansible # Change the keypair name
ip_addresses:
- 172.31.1.117/32
- 172.31.1.118/32
count: 2
tasks:
- name: Launch the new EC2 Instance
local_action: ec2
group={{ security_group }}
instance_type={{ instance_type}}
image={{ image }}
wait=true
region={{ region }}
keypair={{ keypair }}
count={{count}}
vpc_subnet_id=subnet-xxxxxxx
# private_ip={{private_ip}}
with_items: ip_addresses
register: ec2
- name: Wait for SSH to come up
local_action: wait_for
host={{ item.public_ip }}
port=22
state=started
with_items: ec2.instances
- name: Add tag to Instance(s)
local_action: ec2_tag resource={{ item.id }} region={{ region }} state=present
with_items: ec2.instances
args:
tags:
Name: ansible
- name: Update system
apt: update_cache=yes
- name: Install Git
apt:
name: git
state: present
- name: Install Python2.7
apt:
name: python=2.7
state: present
- name: Install Java
apt:
name: openjdk-8-jdk
state: present
Which is although bringing up the instances but not assigning the IP addresses intended to be assigned. and I'm getting following warning
PLAY [Provision an EC2 Instance] ***********************************************
TASK [Launch the new EC2 Instance] *********************************************
changed: [localhost -> localhost] => (item=172.31.1.117/32)
changed: [localhost -> localhost] => (item=172.31.1.118/32)
[DEPRECATION WARNING]: Skipping task due to undefined attribute, 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.
Please suggest me the best possible way to achieve this.
You are giving count=2, so 2 instances will be launched
Your IP addresses are wrong, you are giving a CIDR instead of IP
You are not using the IP address anywhere in your code when launching the instances
How to fix?
ip_addresses:
- 172.31.1.117
- 172.31.1.118
Don't specify count in ec2 module
Loop through the list of ipaddresses (there are 2 of them)
Make sure you use the IP by referencing {item}
Like this:
private_ip={{item}}
I am trying to use Ansible to create an EC2 instance, configure a web server and then register it to a load balancer. I have no problem creating the EC2 instance, nor configuring the web server but all attempts to register it against an existing load balancer fail with varying errors depending on the code I use.
Has anyone had success in doing this?
Here are the links to the Ansible documentation for the ec2 and ec2_elb modules:
http://docs.ansible.com/ec2_module.html
http://docs.ansible.com/ec2_elb_module.html
Alternatively, if it is not possible to register the EC2 instance against the ELB post creation, I would settle for another 'play' that collects all EC2 instances with a certain name and loops through them, adding them to the ELB.
Here's what I do that works:
- name: Add machine to elb
local_action:
module: ec2_elb
aws_access_key: "{{lookup('env', 'AWS_ACCESS_KEY')}}"
aws_secret_key: "{{lookup('env', 'AWS_SECRET_KEY')}}"
region: "{{ansible_ec2_placement_region}}"
instance_id: "{{ ansible_ec2_instance_id }}"
ec2_elbs: "{{elb_name}}"
state: present
The biggest issue was the access and secret keys. The ec2_elb module doesn't seem to use the environment variables or read ~/.boto, so I had to pass them manually.
The ansible_ec2_* variables are available if you use the ec2_facts module. You can fill these parameters by yourself of course.
The below playbook should work for ec2 server creation and registering it to the elb. Make sure you have the variables set properly or you can also hard-code the variable values in playbook.
- name: Creating webserver
local_action:
module: ec2
region: "{{ region }}"
key_name: "{{ key }}"
instance_type: t1.micro
image: "{{ ami_id }}"
wait: yes
assign_public_ip: yes
group_id: ["{{ sg_webserver }}"]
vpc_subnet_id: "{{ PublicSubnet }}"
instance_tags: '{"Name": "webserver", "Environment": "Dev"}
register: webserver
- name: Adding Webserver to ELB
local_action:
module: ec2_elb
ec2_elbs: "{{ elb_name }}"
instance_id: "{{ item.id }}"
state: 'present'
region: "{{ region }}"
with_items: nat.instances