I am creating a role to install some packages and then join a system to a domain controller. However, when I run my playbook, it comes back saying ERROR! ERROR! ‘test’ is undefined. Here is how I am running my playbook:
ansible-playbook -i server_hosts app_install_main.yml
I don’t see where I need to define my host properly. My role consist of the following files:
`
├── server_hosts
├── app_install
│ ├── README.md
│ ├── defaults
│ │ └── main.yml
│ ├── files
│ ├── handlers
│ │ └── main.yml
│ ├── meta
│ │ └── main.yml
│ ├── tasks
│ │ └── app_install_task.yml
│ ├── templates
│ ├── tests
│ │ ├── inventory
│ │ └── test.yml
│ └── vars
│ └── main.yml
├── app_install_main.yml
`
My app_install_task.yml contains the following:
`
Just a thought. Did you export ANSIBLE_INVENTORY? And is it equal to the path and name of your inventory file?
Hi Arthur, can you elaborate on exporting ANSIBLE_INVENTORY? All I did was call my inventory file like this: ansible-playbook -i server_hosts app_install_main.yml
Thanks for the quick response
It looks like your directory structure isn't quite right. app_install should be a sub directory under roles, which might explain why your playbook never finds vars/main.yml.
Hi Arthur,
Actually, I do have my app_install as a sub directory under roles. It’s just that initially I only pasted everything within roles and only showing you that. Here’s a better view:
`
~/git/ansible/roles$ tree
.
└── project1
├── server_hosts
├── app_install
│ ├── README.md
│ ├── defaults
│ │ └── main.yml
│ ├── files
│ ├── handlers
│ │ └── main.yml
│ ├── meta
│ │ └── main.yml
│ ├── tasks
│ │ └── app_install_task.yml
│ ├── templates
│ ├── tests
│ │ ├── inventory
│ │ └── test.yml
│ └── vars
│ └── main.yml
├── app_install_main.yml
`
Unless I’ve missed something, I can’t see where your top-level “app_install_main.yml” play is expecting to get “test” from – it needs to know the list of hosts to work with before it starts opening up the roles, and it doesn’t import those variables from anywhere itself?
As far as I know, a role should not define values like the host list – that is provided to it by the play itself – so perhaps you meant to write “- hosts: testservers” in that app_install_main.yml instead?
Ok, if I change my vars main.yml
From
`
I think your tree should look more like this. Also notice the change of tasks/app_install_task.yml to tasks/main.yml
`
~/git/ansible$ tree
.
└── project1
├── server_hosts
├── roles
│
└
── app_install
│` `├── README.md
│
├── defaults
│` `│ └── main.yml
│
├── files
│` `├── handlers
│
│ └── main.yml
│` `├── meta
│
│ └── main.yml
│` `├── tasks
│
│ └── main.yml
│` `├── templates
│
├── tests
│` `│ ├── inventory
│
│ └── test.yml
│` `└── vars
│
└── main.yml
├── app_install_main.yml
`
Mike,
I got a bit further with your suggestion. I changed my tree to look like the one you have and now it looks like it’s trying to kick. However, now it’s not finding the value of my hosts: “{{ test }}”
When I run the command, I see this now:
`
[WARNING]: provided hosts list is empty, only localhost is available
Sudo password:
PLAY [install app and join appropriate ou] ******************
skipping: no hosts matched
PLAY RECAP *********************************************************************
`
My vars/main.yml contains the following:
`
Is there any way to put this up as e.g. a github repo?
I'm pretty sure your layout is wrong but it's hard to keep track of
what's where without having it to hand.
I believe that the hosts is loaded before the role (or its vars).
Try changing app_install_main.yml to
`
- name: install app and join systems to domain
hosts: testservers
become: yes
`
Or, passing -e ‘{“test”:“testservers”}’ when you run ansible.
Or … your problem could be that you don’t have a group defined as “testservers”. Only “testsystems”.
I can’t put this up on github. I had to sanitize it a lot just to get it here too :/.
If the structure is wrong, then I am not sure what should be changed. I got that structure initially by running ansible-galaxy init role_name and have modified the structure here and there based on suggestions on this thread
Mike,
So before I make that change, let me show you what I have in my hosts file:
`
[testsystems]
testserver1.domain.tld
[developmentsystems]
devserver1.domain.tld
devserver2.domain.tld
[productionsystems]
prodserver1.domain.tld
prodserver2.domain.tld
[testservers:children]
testsystems
[dev-servers:children]
developmentsystems
[prod-servers:children]
productionsystems
`
And then I call the following from vars/main.yml
`
Mike,
And then in my app_install_main.yml, I have the following:
`
Ok, I missed the ‘testservers’ group.
I just tested on my local machine and the only way I can find to reference a var in the ‘hosts:’ setting is if you pass it in with --extra-vars.
So, I refer to my previous suggestion:
Try changing app_install_main.yml to
`
- name: install app and join systems to domain
hosts: testservers
become: yes
`
Or, passing -e ‘{“test”:“testservers”}’ when you run ansible.
Mike and Uditha,
Ok, I see what you guys are saying about the hosts. I moved it one level up and now we are getting somewhere. Now, the issue is that it can’t run my task because it doesn’t see the value of my conditional. For example, I want my task to run when: “{{ testserver }}”. In other words, I want that task to run only on the servers in my testserver group.
Here is the task/main.yml again:
`
Overall, you are better off customizing your plays for each group (maybe in separate playbooks) instead of trying to make a one-size-fits-all playbook. Tasks can be reused by either importing them or putting them in roles.
The other nice thing about this model is that when you run ansible-playbook --list-roles, you get a nice documented output (assuming you named all of your tasks) of what will happen.
However, since we’re already here…
‘testserver’ is a value, not a variable name.
There are a few ways you can do this:
- Use multiple plays. Have one play run with ‘hosts: testservers’ and another play run on some other set of hosts. Group the tasks in the appropriate plays.
- Make your ‘when’ statement be: when: “‘testservers’ in group_names”
Also, what do you mean by “moved it up one level”?
I agree with Mike’s suggestion regarding changing that conditional to when: “‘testservers’ in group_names” – that’s exactly how I handle special cases like DMZ hosts.
Hi Mike,
When I say “moved it up one level”, I meant I took my hosts file out of the roles directory and moved it up one level out of there.
Now, back to your suggestions. For your first point, I am not sure I follow. For example, you said to run my play (I understand this as task) with ‘hosts: testservers’. How would I do that? I thought your hosts: were defined in the main.yml outside of tasks folder. For example, here is what I have:
In app_install_main.yml:
`