Ansible: How to run ad-hoc command with multiple environnements?
-
Given the following architecture:
├── ansible.cfg ├── hosts │ ├── production │ └── staging ├── production │ ├── group_vars │ │ ├── all.yml │ │ ├── mygroup.yml │ │ └── mygroup2.yml │ ├── host_vars │ │ ├── mhost1.yml │ │ └── mhost2.yml │ └── production_playbook.yml └── staging ├── group_vars │ ├── all.yml │ ├── mygroup.yml │ └── mygroup2.yml ├── host_vars │ ├── mhost1.yml │ └── mhost2.yml └── staging_playbook.yml
The content of ansible.cfg is:
[defaults]
inventory=hosts
The content of the hosts/production and hosts/staging file is the same:
[all] [mygroup] mhost1
[mygroup2]
mhost2
staging/group_vars/all.yml, mygroup.yml, mygroup2.yml contains all:
ansible_user: root
staging/host_vars/mhost1.yml and mhost2.yml contains both (with their respective ip):
ansible_host: xxx.xxx.xxx.xx
staging_playbook.yml contains:
--- - hosts: all tasks: - name: ping all in staging ping:
-
hosts: mhost1
tasks:- name: ping mhost1 in staging
ping:
- name: ping mhost1 in staging
-
hosts: mhost2
tasks:- name: ping mhost2 in staging
ping:
- name: ping mhost2 in staging
In the production environment, the production_playbook.yml is similar:
--- - hosts: all tasks: - name: ping all in production ping:
-
hosts: mhost1
tasks:- name: ping mhost1 in production
ping:
- name: ping mhost1 in production
-
hosts: mhost2
tasks:- name: ping mhost2 in production
ping:
- name: ping mhost2 in production
The only differences are in production/host_vars where I have different IP addresses.
If I run:
ansible-playbook staging/staging_playbook.yml
or
ansible-playbook production/production_playbook.yml
it all works fine so I guess the architecture is correct.
Now, my question is: how can I target a specific host in a specific environment with an Ansible ad-hoc command?
for example:
ansible mhost1 -i hosts/staging -m ping
which is not working and gives the output:
mhost1 | UNREACHABLE! => { "changed": false, "msg": "Failed to connect to the host via ssh: ssh: Could not resolve hostname mhost1: nodename nor servname provided, or not known", "unreachable": true }
EDIT:
I found out that if I move my inventory to their respective environments like:
├── ansible.cfg ├── production │ ├── group_vars │ │ ├── all.yml │ │ ├── mygroup.yml │ │ └── mygroup2.yml │ ├── host_vars │ │ ├── mhost1.yml │ │ └── mhost2.yml │ ├── hosts │ └── production_playbook.yml └── staging ├── group_vars │ ├── all.yml │ ├── mygroup.yml │ └── mygroup2.yml ├── host_vars │ ├── mhost1.yml │ └── mhost2.yml ├── hosts └── staging_playbook.yml
and remove from ansible.cfg:
inventory=hosts
I can execute my ad-hocs command however to run the playbook I have to specify the inventory like:
ansible-playbook staging/staging_playbook.yml -i staging/hosts
The architecture I found allowing me to execute my playbooks per environment without having to specify an inventory while executing the command and allowing me to execute ad-hoc commands on a specific host in a specific environnement is this one:
├── ansible.cfg ├── hosts │ ├── production │ └── staging ├── production │ ├── group_vars │ │ ├── all.yml │ │ ├── mygroup.yml │ │ └── mygroup2.yml │ ├── host_vars │ │ ├── mhost1.yml │ │ └── mhost2.yml │ ├── hosts │ └── production_playbook.yml └── staging ├── group_vars │ ├── all.yml │ ├── mygroup.yml │ └── mygroup2.yml ├── host_vars │ ├── mhost1.yml │ └── mhost2.yml ├── hosts └── staging_playbook.yml
This seems weird since I have an inventory per environment and an inventory outside containing the same code. What is the proper way to achieve the same thing?
-
-
One of the options would be to change the current directory. This simplifies the structure and lets you keep common configuration and inventory for production and staging. For example, to run the commands,
- either change the working directory for all commands
shell> cd staging shell> ansible-playbook playbook.yml shell> ansible mhost1 -m ping
- , or change the working directory for each command
shell> (cd staging; ansible-playbook playbook.yml) shell> (cd staging; ansible mhost1 -m ping)
Make the changes below
- Use inventory file from the current directory. Put into the ansible.cfg
inventory=$PWD/hosts
Link ansible.cfg to both production/ansible.cfg and staging/ansible.cfg
Link hosts to both production/hosts and staging/hosts
You can rename both production_playbook.yml and staging_playbook.yml to playbook.yml
├── ansible.cfg ├── hosts ├── production │ ├── group_vars │ │ ├── all.yml │ │ ├── mygroup.yml │ │ └── mygroup2.yml │ ├── host_vars │ │ ├── mhost1.yml │ │ └── mhost2.yml | ├── ansible.cfg -> ../ansible.cfg │ ├── hosts -> ../hosts │ └── playbook.yml └── staging ├── group_vars │ ├── all.yml │ ├── mygroup.yml │ └── mygroup2.yml ├── host_vars │ ├── mhost1.yml │ └── mhost2.yml ├── ansible.cfg -> ../ansible.cfg ├── hosts -> ../hosts └── playbook.yml
WARNING
In a critical environment separate production and staging physically.