From cf81958f66747cb3e2510ecf467acaafbf174277 Mon Sep 17 00:00:00 2001
From: Paul Bourke <paul.bourke@oracle.com>
Date: Tue, 15 Nov 2016 17:14:35 +0000
Subject: [PATCH] Fix fact gathering when using --limit

If an operator wants to deploy a single node (e.g. add an additional
compute), they may want to use the --limit feature of Ansible to avoid
waiting for every play across every node.

The problem with this is that --limit will gather facts for that node
only, causing template errors such as the infamous ('dict object' has no
attribute u'ansible_eth0'").

Ansible has catered to this problem to an extent with it's
"delegate_facts" mechanism. The only problem is that in the default 'all
nodes' case, we end up with a storm of SSHs as each node SSHs to every
other. I'm solving this with a separate task to only use this mechanism
when a subset of nodes has been specified (see ansible_play_batch).

Useful links on this subject:
- https://medium.com/@george.shuklin/perfecting-forced-fact-gathering-in-ansible-1611f9c8d0d5#.tr5zs3e7x
- http://docs.ansible.com/ansible/playbooks_delegation.html#delegated-facts

Change-Id: Ibb691eae15cacd9e5129ae9280fd296f5ba95940
Closes-Bug: 1642004
---
 ansible/site.yml | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/ansible/site.yml b/ansible/site.yml
index 49f6f89d18..6878a1f77d 100644
--- a/ansible/site.yml
+++ b/ansible/site.yml
@@ -5,14 +5,32 @@
 # set to 'false' is a bit confusing but this is to avoid
 # Ansible gathering facts twice.
 - name: Gather facts for all hosts
-  hosts:
-    - all
+  hosts: all
   serial: '{{ serial|default("0") }}'
   gather_facts: false
   tasks:
     - setup:
   tags: always
 
+# NOTE(pbourke): This case covers deploying subsets of hosts using --limit. The
+# limit arg will cause the first play to gather facts only about that node,
+# meaning facts such as IP addresses for rabbitmq nodes etc. will be undefined
+# in the case of adding a single compute node.
+# We don't want to add the delegate parameters to the above play as it will
+# result in ((num_nodes-1)^2) number of SSHs when running for all nodes
+# which can be very inefficient.
+- name: Gather facts for all hosts (if using --limit)
+  hosts: all
+  serial: '{{ serial|default("0") }}'
+  gather_facts: false
+  tasks:
+    - setup:
+      delegate_facts: True
+      delegate_to: "{{ item }}"
+      with_items: "{{ groups['all'] }}"
+      when:
+        - (play_hosts | length) != (groups['all'] | length)
+
 - hosts:
     - all
   roles: