Dirk R
Dirk R

Reputation: 387

How to get a list of all hosts specified by ansible-playbook --limit

The situation

I have a playbook whose execution I sometimes want to limit to specific hosts: web servers and application servers, e.g., --limit mywebserver, appserver1, appserver2. I have two groups:

The playbook calls a play that I call for each of my webservers:

- name: Install and prepare Webservers
  hosts: webservers
  roles:
    - role: webserver_setup

In that play, I execute tasks, e.g., setting up a website for each application server that is stored in a group variable:

- name: Configure website for all application servers
  notify: Reload webserver
  loop: "{{ groups['webserver_' + inventory_hostname] }}"
  ansible.builtin.template:
    src: ./templates/website.y2
    dest: "/etc/nginx/sites-available/{{ hostvars[item]['app_server'] }}.conf"
    mode: '0640'
    owner: webserver
    group: webserver

That works fine if I run the script without --limit. However, if I specify a host for --limit, then the loop in the play is still executed for all application servers, because it doesn't take the limit option into account. (No surprise here.)

My question

My problem is that I have a lot of application servers, and that I would like to limit the play's loop to only the hosts specified by --limit. How'd I do that?

Thoughts on solutions

Upvotes: 4

Views: 2150

Answers (1)

flowerysong
flowerysong

Reputation: 2939

ansible_limit provides the limit that was passed on the command line, and can be expanded into a list of hostnames using the inventory_hostnames lookup. You could just use this in a condition; it's not entirely clear from the question what your actual structure is, but one of the following is probably right:

  when: item in query('inventory_hostnames', ansible_limit | default('all'))
# OR
  when: hostvars[item]['app_server'] in query('inventory_hostnames', ansible_limit | default('all'))

You might also be able to eliminate items from the loop entirely, though that makes the code a bit more complex and it's helpful to use intermediate variables to make it more readable:

- name: Configure website for all application servers
  ansible.builtin.template:
    src: website.y2  # Relative paths in template actions use `templates/` automatically, so you shouldn't specify it.
    dest: /etc/nginx/sites-available/{{ hostvars[item]['app_server'] }}.conf
    mode: "0640"
    owner: webserver
    group: webserver
  notify: Reload webserver
  loop: "{{ webserver_group | intersect(limit_hosts) }}"
  vars:
    webserver_group: "{{ groups['webserver_' ~ inventory_hostname] }}"
    limit_hosts: "{{ query('inventory_hostnames', ansible_limit | default('all')) }}"

Upvotes: 5

Related Questions