Repository: ansible/ansible

Issue:
Updated version of my original PR #7292 to incorporate nested group changes
My previous PR for the expanding of CSV values in ec2 tags did not merge cleanly with the current devel HEAD, so have updated the patches to resolve this.



Discussion:
Context from previous PR:

In my current environment, I rely heavily on AWS tags to describe the purpose of boxes, and roles are applied specifically to them via tag values. In instances where a machine is filling more than one role, I needed the flexibility to target specific instances by tag grouping. This commit aims to prevent a significant amount of tags being required by expanding a CSV value for a tag into a list of values.

The hostvars ec2_tag_foo value becomes a list of tag values from splitting the field by comma, and an additional group tag_foo_value is added to the inventory for each of the CSV values.

An example of one of the machine tags is: 
Name: role, Value: webserver,dns,ssh,logger

Without this commit, the value is interpreted as: ec2_tag_role = 'webserver_dns_ssh_logger' and in the inventory there is a key [tag_role_webserver_dns_ssh_logger]

With this commit, the value is interpreted as: ec2_tag_role = [
'webserver', 'dns', 'ssh', 'logger'
]

and in the inventory there are groups: [tag_role_webserver], [tag_role_dns], [tag_role_ssh], [tag_role_logger]

Therefore buying the flexibility of being able to target instances by specific role, and avoiding having to create a tonne of additional tags/hostgroup handlers

Linking with ticket #7292

@nickpack any chance you could rebase again to apply to current devel? I'd find this functionality useful myself.


Resolving patch:
diff --git a/contrib/inventory/ec2.py b/contrib/inventory/ec2.py
--- a/contrib/inventory/ec2.py
+++ b/contrib/inventory/ec2.py
@@ -141,6 +141,7 @@
 
 
 class Ec2Inventory(object):
+
     def _empty_inventory(self):
         return {"_meta" : {"hostvars" : {}}}
 
@@ -321,6 +322,11 @@ def read_settings(self):
         self.cache_path_index = cache_dir + "/ansible-ec2.index"
         self.cache_max_age = config.getint('ec2', 'cache_max_age')
 
+        if config.has_option('ec2', 'expand_csv_tags'):
+            self.expand_csv_tags = config.getboolean('ec2', 'expand_csv_tags')
+        else:
+            self.expand_csv_tags = False
+
         # Configure nested groups instead of flat namespace.
         if config.has_option('ec2', 'nested_groups'):
             self.nested_groups = config.getboolean('ec2', 'nested_groups')
@@ -696,15 +702,21 @@ def add_instance(self, instance, region):
         # Inventory: Group by tag keys
         if self.group_by_tag_keys:
             for k, v in instance.tags.items():
-                if v:
-                    key = self.to_safe("tag_" + k + "=" + v)
+                if self.expand_csv_tags and v and ',' in v:
+                    values = map(lambda x: x.strip(), v.split(','))
                 else:
-                    key = self.to_safe("tag_" + k)
-                self.push(self.inventory, key, dest)
-                if self.nested_groups:
-                    self.push_group(self.inventory, 'tags', self.to_safe("tag_" + k))
+                    values = [v]
+
+                for v in values:
                     if v:
-                        self.push_group(self.inventory, self.to_safe("tag_" + k), key)
+                        key = self.to_safe("tag_" + k + "=" + v)
+                    else:
+                        key = self.to_safe("tag_" + k)
+                    self.push(self.inventory, key, dest)
+                    if self.nested_groups:
+                        self.push_group(self.inventory, 'tags', self.to_safe("tag_" + k))
+                        if v:
+                            self.push_group(self.inventory, self.to_safe("tag_" + k), key)
 
         # Inventory: Group by Route53 domain names if enabled
         if self.route53_enabled and self.group_by_route53_names:
@@ -1120,6 +1132,8 @@ def get_host_info_dict_from_instance(self, instance):
                 instance_vars['ec2_placement'] = value.zone
             elif key == 'ec2_tags':
                 for k, v in value.items():
+                    if self.expand_csv_tags and ',' in v:
+                        v = map(lambda x: x.strip(), v.split(','))
                     key = self.to_safe('ec2_tag_' + k)
                     instance_vars[key] = v
             elif key == 'ec2_groups':


Test patch: