My first "role" isn't running

372 views
Skip to first unread message

Gilberto Valentin

unread,
Mar 17, 2016, 8:14:48 PM3/17/16
to Ansible Project
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:

---
# tasks file for app_install

- name: Install required nfs packages
  yum: name={{ item }} state=present
  with_items:
  - nfs-utils
  - nfs-utils-lib

- name: Create a temporary mount point for the installation files
  file: path=/tmp/app_install state=directory owner=root group=root mode=0775

- name: Mount the nfs share from nfsshare.domain.tld
  shell: mount -F -t nfs -o vers=3 -v nfsshare.domain.tld:/share/location /tmp/app_install

- name: Install app on test systems
  command: /tmp/app_install/apptool_install arg1
  when: ({{ test }})

- name: Join test systems to test ou
  shell: /path/to/domainjoin-cli join --notimesync --disable hostname 
          --ou OU=test,OU=UNIX,DC=server,DC=domain,DC=tld server.domain.tld join_account
  when: ({{ test }})

 My app_install_main.yml (task file) looks like this:

---

- name: install app and join systems to domain
  hosts: "{{ test }}"
  become: yes

  roles:
    - app_install

  vars_prompt:
    - name: "ansible_sudo_pass"
      prompt: "Sudo password"
      private: yes

My app_hosts file looks like this:

[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 here is what I have in my vars/main.yml:

---
# vars file for app_install

test: "{{ testservers }}"

Where or how should I define my host? This is my first role. I am sure I am missing a few obvious requirements.

Arthur Reyes

unread,
Mar 17, 2016, 8:26:17 PM3/17/16
to Ansible Project
Just a thought. Did you export ANSIBLE_INVENTORY? And is it equal to the path and name of your inventory file?

Gilberto Valentin

unread,
Mar 17, 2016, 8:33:59 PM3/17/16
to Ansible Project
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 :)

Arthur Reyes

unread,
Mar 17, 2016, 10:37:01 PM3/17/16
to Ansible Project
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.

Gilberto Valentin

unread,
Mar 18, 2016, 8:03:05 AM3/18/16
to Ansible Project
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

Gilberto Valentin

unread,
Mar 18, 2016, 11:06:48 AM3/18/16
to Ansible Project
Ok, if I change my vars main.yml

From

---
# vars file for app_install

test: "{{ testservers }}"

To

---
# vars file for app_install

test: "testservers"

...I get the following:

Sudo password:

PLAY [install app and join appropriate ou] ******************

TASK [setup] *******************************************************************
ok: [testserver1.domain.tld]

PLAY RECAP *********************************************************************
testserver1.domain.tld : ok=1    changed=0    unreachable=0    failed=0

However, it looks like it doesn't run my role at all

Mike Biancaniello

unread,
Mar 18, 2016, 1:38:35 PM3/18/16
to Ansible Project
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

Gilberto Valentin

unread,
Mar 18, 2016, 3:01:58 PM3/18/16
to Ansible Project
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:

---

test: testservers

I even tried it with test: "{{ testservers }}" but get

ERROR! ERROR! 'testservers' is undefined

Dick Davies

unread,
Mar 18, 2016, 3:13:39 PM3/18/16
to ansible list
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.
> --
> You received this message because you are subscribed to the Google Groups
> "Ansible Project" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to ansible-proje...@googlegroups.com.
> To post to this group, send email to ansible...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/ansible-project/f9cac5de-59bd-4d38-b83d-9810aaf38073%40googlegroups.com.
>
> For more options, visit https://groups.google.com/d/optout.

Mike Biancaniello

unread,
Mar 18, 2016, 3:33:26 PM3/18/16
to Ansible Project
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.





Mike Biancaniello

unread,
Mar 18, 2016, 3:34:12 PM3/18/16
to Ansible Project
Or ... your problem could be that you don't have a group defined as "testservers". Only "testsystems".

Gilberto Valentin

unread,
Mar 18, 2016, 3:52:46 PM3/18/16
to Ansible Project, di...@hellooperator.net
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

Uditha Desilva

unread,
Mar 18, 2016, 4:00:14 PM3/18/16
to Ansible Project
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?

Gilberto Valentin

unread,
Mar 18, 2016, 4:01:03 PM3/18/16
to Ansible Project
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

---

test: testservers

Gilberto Valentin

unread,
Mar 18, 2016, 4:03:38 PM3/18/16
to Ansible Project
Mike,

And then in my app_install_main.yml, I have the following:

Mike Biancaniello

unread,
Mar 18, 2016, 4:33:25 PM3/18/16
to Ansible Project
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

Gilberto Valentin

unread,
Mar 18, 2016, 4:34:08 PM3/18/16
to Ansible Project
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:

---
# tasks file for app_install

- name: Install required nfs packages
 yum: name={{ item }} state=present
 with_items:
 - nfs-utils
 - nfs-utils-lib

- name: Create a temporary mount point for the installation files
 file: path=/tmp/app_install state=directory owner=root group=root mode=0775

- name: Mount the nfs share from nfsshare.domain.tld
 shell: mount -F -t nfs -o vers=3 -v nfsshare.domain.tld:/share/location /tmp/app_install

- name: Install app on test systems
 command: /tmp/app_install/apptool_install arg1
 when: ({{ testserver }})

- name: Join test systems to test ou
 shell: /path/to/domainjoin-cli join --notimesync --disable hostname
          --ou OU=test,OU=UNIX,DC=server,DC=domain,DC=tld server.domain.tld join_account
 when: ({{ testserver }})

However, it fails with the following error:

Sudo password:

PLAY [install app and join systems to appropriate ou] ******************

TASK [setup] *******************************************************************
ok: [testserver1.domain.tld]

TASK [app_install : Install required nfs packages] *********************
changed: [testserver1.domain.tld] => (item=[u'nfs-utils', u'nfs-utils-lib'])

TASK [app_install : Create a temporary mount point for the installation files] ***
changed: [testserver1.domain.tld]

TASK [app_install : Mount the nfs share] *********************
skipping: [testserver1.domain.tld]

TASK [app_install : Install app on test systems] ***************
fatal: [testserver1.domain.tld]: FAILED! => {"failed": true, "msg": "ERROR! The conditional check '{{ testserver }}' failed. The error was: ERROR! error while evaluating conditional ({{ testserver }}): ERROR! 'testserver' is undefined\n\nThe error appears to have been in '/git/ansible/projects/app/roles/app_install/tasks/main.yml': line 16, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: Install app on testserver systems\n  ^ here\n"}

PLAY RECAP *********************************************************************
testserver1.domain.tld : ok=3    changed=2    unreachable=0    failed=1

So on my when: "{{ testserver }}" for my tasks/main.yml, how do I have it apply the task only when it matches that host group?

Mike Biancaniello

unread,
Mar 18, 2016, 4:50:08 PM3/18/16
to Ansible Project

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:
  1. 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.
  2. Make your 'when' statement be: when: "'testservers' in group_names"

Also, what do you mean by "moved it up one level"?



Uditha Desilva

unread,
Mar 18, 2016, 6:17:21 PM3/18/16
to Ansible Project
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.

Gilberto Valentin

unread,
Mar 18, 2016, 7:59:20 PM3/18/16
to Ansible Project
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:

---

- name: install app and join systems to domain
 hosts: testservers
 become: yes

  roles:
  - app_install

  vars_prompt:
  - name: "ansible_sudo_pass"
    prompt: "Sudo password"
    private: yes

It is here where I am calling my hosts: testservers. Then in my task/main.yml, I have:

---
# tasks file for app_install

- name: Install required nfs packages
yum: name={{ item }} state=present
with_items:
- nfs-utils
- nfs-utils-lib

- name: Create a temporary mount point for the installation files
file: path=/tmp/app_install state=directory owner=root group=root mode=0775

- name: Mount the nfs share from nfsshare.domain.tld
shell: mount -F -t nfs -o vers=3 -v nfsshare.domain.tld:/share/location /tmp/app_install

- name: Install app on test systems
command: /tmp/app_install/apptool_install arg1
when: "'testserver'in group_names"

- name: Join test systems to test ou
shell: /path/to/domainjoin-cli join --notimesync --disable hostname
         --ou OU=test,OU=UNIX,DC=server,DC=domain,DC=tld server.domain.tld join_account
when: "'testserver' in group_names"

As you can see, I am adding your suggestion here too. I am not sure I grasp what you mean by "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". I am still trying to wrap my head around that.

Uditha Desilva

unread,
Mar 18, 2016, 8:05:12 PM3/18/16
to Ansible Project

That "when" should be checking for "testservers" (plural).


--
You received this message because you are subscribed to a topic in the Google Groups "Ansible Project" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/ansible-project/GsGIlwrqU_0/unsubscribe.
To unsubscribe from this group and all its topics, send an email to ansible-proje...@googlegroups.com.

To post to this group, send email to ansible...@googlegroups.com.

Mike Biancaniello

unread,
Mar 21, 2016, 10:48:00 AM3/21/16
to Ansible Project
1. what Uditha said about 'testservers'.
2. By "use multiple plays", I meant to create one play that specifies hosts: testservers, another play that specifies hosts: dev-servers, and a third that specifies hosts: prod-servers.
Then, have specific tasks for those servers.

Now, re-looking at your playbook, I realize that I had forgotten that you were using a role for this, so separating this into multiple plays would be more complicated because you want the role to act differently depending on the group. In general, this makes the role less portable because it requires that these groups be defined.

So, if you wanted to go down this road, you could either split your role into multiple roles or split your tasks/main.yml into multiple files (this might be overkill for what you want to do, but I'm including it here for completeness):

e.g.
tasks/prod.yml: tasks to run on all prod-servers
tasks/dev.yml: tasks to run on all dev-servers
tasks/test.yml: task to run on all testservers

tasks/main.yml:
---
- name: Run on prod
  include
: prod.yml
 
when: run_prod|default(false)

- name: Run on dev
  include
: prod.yml
 
when: run_dev|default(false)

- name: Run on test
  include
: test.yml
 
when: run_test|default(false)



and in your playbook:
---
- name: Play for test servers
  hosts
: testservers

  roles
:
 
- { role: app_install, run_test: true, tags: test }


- name: Play for dev servers
  hosts
: dev-servers

  roles
:
 
- { role: app_install, run_dev: true, tags: dev }

- name: Play for prod servers
  hosts
: prod-servers

  roles
:
 
- { role: app_install, run_prod: true, tags: prod }



Gilberto Valentin

unread,
Mar 22, 2016, 4:01:55 PM3/22/16
to Ansible Project
Hi Mike,

Thanks for the suggestions. I tried to implement what you mentioned and I ended up breaking everything. I am completely lost with this. I am just going to have to start over at this point. Between sanitizing the data to post here and then trying to translate your suggestions back to what it really is on my end keeps getting more and more complicated. Somewhere along the line, I've lost the translation of what you are suggestion vs how I am actually writing it.

Mike Biancaniello

unread,
Mar 22, 2016, 4:37:26 PM3/22/16
to Ansible Project
like I said, since you've put this into a role, "separating this into multiple plays would be more complicated", so you're better off not splitting it up and instead, doing what you were doing

copied from your earlier post (with the typo pointed out by Uditha corrected:
  when: "'testservers'in group_names"

- name: Join test systems to test ou
  shell: /path/to/domainjoin-cli join --notimesync --disable hostname
         --ou OU=test,OU=UNIX,DC=server,DC=domain,DC=tld server.domain.tld join_account
  when: "'testservers' in group_names"

Gilberto Valentin

unread,
Mar 22, 2016, 7:30:45 PM3/22/16
to Ansible Project
Mike,

Thanks for your patience and assistance. I wanted to do it the way you suggested so that I get in the habit of crafting my roles that can be useful in other ways later. With that said, I think I am getting the hang of what you are saying. I started completely over and separated my roles. I also changed my naming convention on everything so that things don't get lost in translation here. So, this is what I have so far:

This is what my directory structure now looks like. If you notice, I created a directory called powerbroker, which is essentially my project. Then, I created a sub-dir in there called powerbroker_install because I'll eventually create another called powerbroker_uninstall later. Within powerbroker_install I created three roles with ansible-galaxy init role_name for dev|prod|test. Then, I have my host file, called powerbroker_hosts and my site.yml right under the parent directory powerbroker_install

Here is a view:

roles
└── powerbroker
    ├── powerbroker_install
    │   ├── pb_install_dev
    │   │   ├── README.md
    │   │   ├── defaults
    │   │   │   └── main.yml
    │   │   ├── files
    │   │   ├── handlers
    │   │   │   └── main.yml
    │   │   ├── meta
    │   │   │   └── main.yml
    │   │   ├── tasks
    │   │   │   └── main.yml
    │   │   ├── templates
    │   │   ├── tests
    │   │   │   ├── inventory
    │   │   │   └── test.yml
    │   │   └── vars
    │   │       └── main.yml
    │   ├── pb_install_prod
    │   │   ├── README.md
    │   │   ├── defaults
    │   │   │   └── main.yml
    │   │   ├── files
    │   │   ├── handlers
    │   │   │   └── main.yml
    │   │   ├── meta
    │   │   │   └── main.yml
    │   │   ├── tasks
    │   │   │   └── main.yml
    │   │   ├── templates
    │   │   ├── tests
    │   │   │   ├── inventory
    │   │   │   └── test.yml
    │   │   └── vars
    │   │       └── main.yml
    │   ├── pb_install_test
    │   │   ├── README.md
    │   │   ├── defaults
    │   │   │   └── main.yml
    │   │   ├── files
    │   │   ├── handlers
    │   │   │   └── main.yml
    │   │   ├── meta
    │   │   │   └── main.yml
    │   │   ├── tasks
    │   │   │   └── main.yml
    │   │   ├── templates
    │   │   ├── tests
    │   │   │   ├── inventory
    │   │   │   └── test.yml
    │   │   └── vars
    │   │       └── main.yml
    │   ├── powerbroker_hosts
    │   └── site.yml

Legend: 
blue are the project and subdir of the project
green are the roles
yellow are the files I touched

So far, I have only worked in pb_install_test. The only file I touched here is the following:
  • pb_install_test/tasks/main.yml
Here is the content of the file:

---
# tasks file for pb_install_test

- name: install required nfs packages
  yum: name={{ item }} state=present
  with_items:
    - nfs-utils
    - nfs-utils-lib

- name: mount nfs share
  mount: name=/tmp/pb_install src="hostname.server.com:/src/path" fstype=nfs opts="vers=3" state=mounted

- name: install pbis and pbul
  shell: /tmp/pb_install/pbis_install e1

- name: join systems to domain and correct ou
  shell: /opt/pbis/bin/domainjoin-cli join --notimesync --disable hostname --ou OU=UNIX,OU=Servers,DC=sub,DC=domain,DC=com subdomain.server.com

Then, I worked on powerbroker_install/site.yml. This is the content of the file:

---
########################## Test Servers ###########################
- name: install powerbroker (pbis and pbul) to all test servers
  hosts
: e1servers
  become
: yes


  roles
:
 
- pb_install_test


########################## Dev Servers ###########################
#- name: install powerbroker (pbis and pbul) to all dev servers
#  hosts: e2servers
#  become: yes


#  roles:
#  - pb_install_dev


########################## Prod Servers ###########################
#- name: install powerbroker (pbis and pbul) to all prod servers
#  hosts: e3servers
#  become: yes


#  roles:
#  - pb_install_prod


########################## Variables Prompt ########################
  vars_prompt
:
   
- name: "ansible_sudo_pass"
      prompt
: "SUDO password"
     
private: yes

I turned off (commented out) the others because I am not ready to push to those yet ;)

Looks like this is going to work well. However, I am running into a snag. My last task needs me to provide a password. The task I am referring to is from this file 
  • pb_install_test/tasks/main.yml
This is the actual task I am referring to:

- name: join systems to domain and correct ou
  shell
: /opt/pbis/bin/domainjoin-cli join --notimesync --disable hostname --ou OU=UNIX,OU=Servers,DC=sub,DC=domain,DC=com subdomain.server.com

Not long ago while starting out, I was doing something like this to pass a password to a command but not sure if this is the best approach for this:

- name: join systems to domain and correct ou
      expect:
        command: /bin/bash -c "/opt/pbis/bin/domainjoin-cli join --notimesync --disable hostname --ou OU=UNIX,OU=Servers,DC=sub,DC=domain,DC=com subdomain.server.com"
        responses:
          Password for Administrator: "password123"

While that worked before (I haven't tried it again), I feel like maybe there is a better and more secure way to do this. Thoughts?

Mike Biancaniello

unread,
Mar 23, 2016, 9:44:21 AM3/23/16
to Ansible Project
I'm actually surprised that this tree worked; I would have expected 'roles' to need to be under powerbroker_install (i.e. powerbroker/powerbroker_install/roles/pb_install_dev, etc), but glad that things are working for you.

For passwords, are you familiar with prompts or vaults? That might be what you need.

Gilberto Valentin

unread,
Mar 23, 2016, 10:12:42 AM3/23/16
to Ansible Project
Mike,

So the roles directory is something I created manually. I saw this on a video tutorial directly made from Ansible and the instructor was creating these manually and then initiating the roles from within the roles directly. I applied the same concept and it worked :). I'll def. check out prompts and vaults. As you can see, I am already using vars_prompt in my site.yml.

Again, thanks a bunch for your help. I finally got what I needed from this thread. Thanks to Uditha for assisting as well. :)
Reply all
Reply to author
Forward
0 new messages