diff --git a/lib/ansible/module_utils/network/aci/msc.py b/lib/ansible/module_utils/network/aci/msc.py index 0ec9f9f7bbc..a13bea86708 100644 --- a/lib/ansible/module_utils/network/aci/msc.py +++ b/lib/ansible/module_utils/network/aci/msc.py @@ -31,11 +31,17 @@ from copy import deepcopy from ansible.module_utils.basic import AnsibleModule, json +from ansible.module_utils.six import PY3 from ansible.module_utils.six.moves.urllib.parse import urlencode, urljoin from ansible.module_utils.urls import fetch_url from ansible.module_utils._text import to_native, to_bytes +if PY3: + def cmp(a, b): + return (a > b) - (a < b) + + def issubset(subset, superset): ''' Recurse through nested dictionary and compare entries ''' @@ -52,6 +58,10 @@ def issubset(subset, superset): return False for key, value in subset.items(): + # Ignore empty values + if value is None: + return True + # Item from subset is missing from superset if key not in superset: return False @@ -65,8 +75,14 @@ def issubset(subset, superset): if not issubset(superset[key], value): return False elif isinstance(value, list): - if not set(value) <= set(superset[key]): - return False + try: + # NOTE: Fails for lists of dicts + if not set(value) <= set(superset[key]): + return False + except TypeError: + # Fall back to exact comparison for lists of dicts + if not cmp(value, superset[key]): + return False elif isinstance(value, set): if not value <= superset[key]: return False @@ -268,6 +284,36 @@ class MSCModule(object): ids.append(dict(roleId=r['id'])) return ids + def lookup_sites(self, sites): + ''' Look up sites and return their ids ''' + if sites is None: + return sites + + ids = [] + for site in sites: + s = self.get_obj('sites', name=site) + if not s: + self.module.fail_json(msg="Site '%s' is not valid." % site) + if 'id' not in s: + self.module.fail_json(msg="Site lookup failed for '%s': %s" % (site, s)) + ids.append(dict(siteId=s['id'], securityDomains=[])) + return ids + + def lookup_users(self, users): + ''' Look up users and return their ids ''' + if users is None: + return users + + ids = [] + for user in users: + u = self.get_obj('users', username=user) + if not u: + self.module.fail_json(msg="User '%s' is not valid." % user) + if 'id' not in u: + self.module.fail_json(msg="User lookup failed for '%s': %s" % (user, u)) + ids.append(dict(userId=u['id'])) + return ids + def create_label(self, label, label_type): ''' Create a new label ''' return self.request('labels', method='POST', data=dict(displayName=label, type=label_type)) diff --git a/lib/ansible/modules/network/aci/msc_tenant.py b/lib/ansible/modules/network/aci/msc_tenant.py index 975183c41f1..64b9bae83f9 100644 --- a/lib/ansible/modules/network/aci/msc_tenant.py +++ b/lib/ansible/modules/network/aci/msc_tenant.py @@ -40,6 +40,16 @@ options: description: - The description for this tenant. type: str + users: + description: + - A list of allowed users for this tenant. + - Using this property will replace any existing allowed users. + type: list + sites: + description: + - A list of allowed sites for this tenant. + - Using this property will replace any existing allowed sites. + type: list state: description: - Use C(present) or C(absent) for adding or removing. @@ -106,6 +116,8 @@ def main(): display_name=dict(type='str'), tenant=dict(type='str', required=False, aliases=['name', 'tenant_name']), tenant_id=dict(type='str', required=False), + users=dict(type='list'), + sites=dict(type='list'), state=dict(type='str', default='present', choices=['absent', 'present', 'query']), ) @@ -126,6 +138,10 @@ def main(): msc = MSCModule(module) + # Convert sites and users + sites = msc.lookup_sites(module.params['sites']) + users = msc.lookup_users(module.params['users']) + path = 'tenants' # Query for existing object(s) @@ -166,8 +182,8 @@ def main(): id=tenant_id, name=tenant, displayName=display_name, - siteAssociations=[], - userAssociations=[dict(userId="0000ffff0000000000000020")], + siteAssociations=sites, + userAssociations=users, ) msc.sanitize(payload, collate=True) @@ -176,6 +192,10 @@ def main(): if msc.sent.get('displayName') is None: msc.sent['displayName'] = tenant + # Ensure tenant has at least admin user + if msc.sent.get('userAssociations') is None: + msc.sent['userAssociations'] = [dict(userId="0000ffff0000000000000020")] + if msc.existing: if not issubset(msc.sent, msc.existing): if module.check_mode: