2

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:

- hosts: mhost2
  tasks:
    - name: ping mhost2 in staging
      ping:

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:

- hosts: mhost2 
  tasks:
    - name: ping mhost2 in production
      ping:

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?

1 Answer 1

2

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.

1
  • Thank you @vladimir-botka, I was expecting a solution that just involves passing the correct inventory in the ad-hoc command somehow, but this works.
    – Tanuki
    Jun 15, 2022 at 9:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.