I would like to insert an IP address in to a J2 template which is used by an Ansible playbook. That IP adress is not the address of the host which is being provisioned, but the IP of the host from which the provisioning is done. Everything I have found so far covers using variables/facts related to the hosts being provisioned.
In other words: the IP I’d like to insert is the one in ['ansible_default_ipv4']['address'] when executing ansible -m setup 127.0.0.1.
I think that I could use a local playbook to write a dynamically generated template file containing the IP, but I was hoping that this might be possible “the Ansible way”.
Just use this:
{{ ansible_env["SSH_CLIENT"].split()[0] }}
You can force Ansible to fetch facts about the control host by running the setup module locally by using either a local_action or delegate_to. You can then either register that output and parse it or simply use set_fact to give it a useful name to use later in your template.
An example play might look something like:
tasks:
- name: setup
setup:
delegate_to: 127.0.0.1
- name: set ansible control host IP fact
set_fact:
ansible_control_host_address: "{{ hostvars[inventory_hostname]['ansible_eth0']['ipv4']['address'] }}"
delegate_to: 127.0.0.1
- name: template file with ansible control host IP
template:
src: /path/to/template.j2
dest: /path/to/destination/file
And then use the ansible_control_host_address variable in your template as normal:
...
Ansible control host IP: {{ ansible_control_host_address }}
...
This is how I solved the same problem (Ansible 2.7):
- name: Get local IP address
setup:
delegate_to: 127.0.0.1
delegate_facts: yes
- name: Add to hosts file
become: yes
lineinfile:
line: "{{ hostvars['127.0.0.1']['ansible_default_ipv4']['address'] }} myhost"
path: /etc/hosts
Seems to work like a charm. :-)
Related
I'm trying to access another host IP for usage in the Jinja2 template. So basically - I need to extract the IP address of another host to use it in my role template. Could you please direct me? Thank you
Example of inventory file, here i need web group host IP (web_ip) to use in role for lb group:
web:
hosts:
web_ip
vars:
ansible_user: ...
ansible_ssh_private_key_file: ...
lb:
hosts:
lb_ip
vars:
ansible_user: ..
ansible_ssh_private_key_file: ..
Example of template that will be used for lb host group:
upstream web {
server ${{ web_ip }};
}
Solved it myself. Here is the solution that worked for me:
{%for host in groups['web']%}{{hostvars[host]['ansible_env'].SSH_CONNECTION.split(' ')[2]}}{% endfor %}
I have two DigitalOcean Droplets with public and private IP addresses, created by Vagrant and Ansible playbook.
I need to create was_route53 records for each address (two records per droplet)
How I can get addresses into vars to use it in playbook?
I made a playbook this weekend to do something very similar.
In my case, I create a droplet on digitalocean, save the IP address, and then add a DNS record to AWS.
I hope this helps. Note that the playbook still has some things hardcoded, such as region and size because I have not polished it off yet.
Also, this is the first time I have used ansible with DO and AWS, and it's the first time that I have used the "register" feature to save variables, so this is probably a long way from best practice.
One thing that seems ugly is my hardcoding of my venv python interpreter.
If you are happy to use your system python, then you don't need to worry about that. The problem is that when ansible sees connection: local, it uses the system python, which is a bit odd since the script is running in a venv on the same machine.
You need to pip install boto3
and:
ansible-galaxy collection install community.digitalocean
ansible-galaxy collection install community.aws
example playbook
---
- hosts: all
connection: local
become_user: tim
vars: #local connection defaults to using the system python
ansible_python_interpreter: /home/tim/pycharm_projects/django_api_sync/ansible/venv/bin/python3
vars_files:
- includes/secret_variables.yml
tasks:
- name: create a DigitalOcean Droplet
community.digitalocean.digital_ocean_droplet:
state: present
name: "{{droplet_name}}"
oauth_token: "{{digital_ocean_token}}"
size: "s-2vcpu-2gb"
region: SGP1
monitoring: yes
unique_name: yes
image: ubuntu-20-04-x64
wait_timeout: 500
ssh_keys: [ "{{digital_ocean_ssh_fingerprint}}"]
register: my_droplet
- name: Print IP address
ansible.builtin.debug:
msg: Droplet IP address is {{ my_droplet.data.ip_address }}
- name: Add A record with route53
community.aws.route53:
aws_access_key: "{{aws_access_key}}"
aws_secret_key: "{{aws_secret_key}}"
state: present
zone: growthpath.com.au
record: "{{ ansible_host }}"
type: A
ttl: 7200
value: "{{ my_droplet.data.ip_address }}"
wait: yes
Example inventory file:
all:
hosts:
test-dear1.growthpath.com.au:
droplet_name: test-dear1
ansible_host: test-dear1.growthpath.com.au
ansible-playbook -i inventory_aws_test.yml -v create_new_droplet.yml
How do I get the IP or hostname of Ansible server in a jinja2 template? I'm talking about the IP of Ansible control machine, not the ip of the target servers, e.g. {{ ansible_fqdn }}
Make sure you have gathered facts for localhost. Do this in a seperate play in your playbook if needed. The following should be sufficient:
- name: Simply gather facts for localhost
hosts: localhost
gather_facts: true
Use the var from localhost in your template i.e. {{ hostvars['localhost'].ansible_fqdn }}
I'm setting up an Ansible playbook to set up a couple servers. There are a couple of tasks that I only want to run if the current host is my local dev host, named "local" in my hosts file. How can I do this? I can't find it anywhere in the documentation.
I've tried this when statement, but it fails because ansible_hostname resolves to the host name generated when the machine is created, not the one you define in your hosts file.
- name: Install this only for local dev machine
pip:
name: pyramid
when: ansible_hostname == "local"
The necessary variable is inventory_hostname.
- name: Install this only for local dev machine
pip:
name: pyramid
when: inventory_hostname == "local"
It is somewhat hidden in the documentation at the bottom of this section.
You can limit the scope of a playbook by changing the hosts header in its plays without relying on your special host label ‘local’ in your inventory. Localhost does not need a special line in inventories.
- name: run on all except local
hosts: all:!local
This is an alternative:
- name: Install this only for local dev machine
pip: name=pyramid
delegate_to: localhost
I'm setting up an Ansible playbook to set up a couple servers. There are a couple of tasks that I only want to run if the current host is my local dev host, named "local" in my hosts file. How can I do this? I can't find it anywhere in the documentation.
I've tried this when statement, but it fails because ansible_hostname resolves to the host name generated when the machine is created, not the one you define in your hosts file.
- name: Install this only for local dev machine
pip:
name: pyramid
when: ansible_hostname == "local"
The necessary variable is inventory_hostname.
- name: Install this only for local dev machine
pip:
name: pyramid
when: inventory_hostname == "local"
It is somewhat hidden in the documentation at the bottom of this section.
You can limit the scope of a playbook by changing the hosts header in its plays without relying on your special host label ‘local’ in your inventory. Localhost does not need a special line in inventories.
- name: run on all except local
hosts: all:!local
This is an alternative:
- name: Install this only for local dev machine
pip: name=pyramid
delegate_to: localhost