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:
    • 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?



  • 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.




Suggested Topics

  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2