5
votes

I'm trying to set up environment specific variables in ansible (e.g. production, staging, development). For some reason, ansible is not picking up variables in group_vars/[environment].

I'm using ansible 1.9.1

Here's a stripped down example of what I'm trying to do.

Directory structure:

.
├── group_vars
│   └── staging
├── hosts
│   └── staging
└── site.yml

group_vars/staging:

test_var: "this is a test"

site.yml:

---
- hosts: localhost
  tasks:
  - debug: msg="test variable = {{ test_var }}"

hosts/staging is an empty file

Output of running ansible-playbook -i hosts/staging site.yml:

PLAY [localhost] **************************************************************

GATHERING FACTS ***************************************************************
ok: [localhost]

TASK: [debug msg="test variable = {{ test_var }}"] ****************************
fatal: [localhost] => One or more undefined variables: 'test_var' is undefined

FATAL: all hosts have already failed -- aborting

PLAY RECAP ********************************************************************
           to retry, use: --limit @/Users/jcowley/site.retry

localhost                  : ok=1    changed=0    unreachable=1    failed=0

If I move group_vars/staging to group_vars/all, it works as expected and outputs the value of test_var. But I'm trying to understand how I can separate environments per the documentation in Ansible's Best Practices

1

1 Answers

5
votes

EDIT:

To answer your question more specifically, please have a look at this github exemple project. This is, I think, what you tried to do. I might be wrong, but I think the problem comes from your inventory file. You actually named your group_vars files (staging) after your inventory filename (staging too). But, you must name it after the section inside your inventory file, which is, I suppose, localhost looking at your playbook.

Thus, this is what you should have:

hosts/staging:

[staging]
X.X.X.X

Here is, according to me, a more viable solution to organize your project. It is based on roles.

Directory structure:

.
├── group_vars
│   └── all
├── hosts
│   └── local
│   └── staging
│   └── prod
├── roles
│   └── exemple
│       └── tasks
│       └── vars
│           └── local.yml
│           └── staging.yml
│           └── prod.yml
└── site.yml

The group_vars/all could have an env variable:

# The application environment
# Possible values are : prod, staging or local
env: local

# Other global variables
...

Your inventory file:

[local]
X.X.X.X

[staging]
X.X.X.X

[prod]
X.X.X.X

Then, your playbook sites.yml could look like this:

---
- name: Server(s) configuration
  hosts: "{{env}}"
  roles:
    - exemple
  vars_files:
    - "roles/example/vars/{{env}}.yml"

Doing it this way gives you multiple benefits:

  • you can reuse the env variable anywhere in your project, in jinja templates or as a condition in tasks which is very practical;
  • your project is split into separate roles. It’s cleaner this way for big project (you can have an apache role, ssh role, etc.);
  • you can create env-specific variables in separate files in roles/exemple/vars/ directory.