From 14b03ac15faa31359e6d56beb3b955dc2e012549 Mon Sep 17 00:00:00 2001 From: Dag Wieers Date: Thu, 20 Dec 2018 18:18:46 +0100 Subject: [PATCH] MSC: Various bugfixes and features enhancements (#50200) * MSC: Various bugfixes and features enhancements This PR includes: - Lookups of roles, labels and domains - Auto-create new labels - Improvements to comparing complex datastructures - Force removal of sites - Support non top-level queries - Document internal functions - Add parameter types to modules - Fix documentation examples - Improvements to idempotency wrt. returning changed - Support site locations - Update permission list - Various improvements to integration tests * Fix Ci issues --- lib/ansible/module_utils/network/aci/msc.py | 99 ++++++++++++++++--- lib/ansible/modules/network/aci/msc_label.py | 21 ++-- lib/ansible/modules/network/aci/msc_role.py | 44 +++++++-- lib/ansible/modules/network/aci/msc_site.py | 65 ++++++++++-- lib/ansible/modules/network/aci/msc_tenant.py | 12 ++- lib/ansible/modules/network/aci/msc_user.py | 77 ++++++++++----- .../utils/module_docs_fragments/msc.py | 6 +- .../targets/msc_site/tasks/main.yml | 59 ++++++----- .../targets/msc_user/tasks/main.yml | 3 +- 9 files changed, 295 insertions(+), 91 deletions(-) diff --git a/lib/ansible/module_utils/network/aci/msc.py b/lib/ansible/module_utils/network/aci/msc.py index 6c8ede9586..f40eb46685 100644 --- a/lib/ansible/module_utils/network/aci/msc.py +++ b/lib/ansible/module_utils/network/aci/msc.py @@ -38,19 +38,30 @@ from ansible.module_utils._text import to_native, to_bytes def issubset(subset, superset): ''' Recurse through nested dictionary and compare entries ''' + + # Both objects are the same object if subset is superset: return True + # Both objects are identical if subset == superset: return True + # Both objects have a different type + if type(subset) != type(superset): + return False + for key, value in subset.items(): + # Item from subset is missing from superset if key not in superset: return False - elif isinstance(value, str): - if value != superset[key]: - return False - elif isinstance(value, dict): + + # Item has different types in subset and superset + if type(superset[key]) != type(value): + return False + + # Compare if item values are subset + if isinstance(value, dict): if not issubset(superset[key], value): return False elif isinstance(value, list): @@ -62,9 +73,16 @@ def issubset(subset, superset): else: if not value == superset[key]: return False + return True +def update_qs(params): + ''' Append key-value pairs to self.filter_string ''' + accepted_params = dict((k, v) for (k, v) in params.items() if v) + return '?' + '&'.join(['%s=%s' % (k, v) for (k, v) in accepted_params.items()]) + + def msc_argument_spec(): return dict( host=dict(type='str', required=True, aliases=['hostname']), @@ -146,7 +164,7 @@ class MSCModule(object): self.headers['Authorization'] = 'Bearer {token}'.format(**payload) - def request(self, path, method=None, data=None): + def request(self, path, method=None, data=None, qs=None): ''' Generic HTTP method for MSC requests. ''' self.path = path @@ -154,6 +172,10 @@ class MSCModule(object): self.method = method self.url = urljoin(self.baseuri, path) + + if qs is not None: + self.url = self.url + update_qs(qs) + resp, info = fetch_url(self.module, self.url, headers=self.headers, @@ -168,8 +190,8 @@ class MSCModule(object): # 200: OK, 201: Created, 202: Accepted, 204: No Content if self.status in (200, 201, 202, 204): output = resp.read() - if self.method in ('DELETE', 'PATCH', 'POST', 'PUT') and self.status in (200, 201, 204): - self.result['changed'] = True +# if self.method in ('DELETE', 'PATCH', 'POST', 'PUT') and self.status in (200, 201, 204): +# self.result['changed'] = True if output: return json.loads(output) @@ -192,20 +214,26 @@ class MSCModule(object): return {} - def query_objs(self, path, **kwargs): + def query_objs(self, path, key=None, **kwargs): + ''' Query the MSC REST API for objects in a path ''' found = [] objs = self.request(path, method='GET') - for obj in objs[path]: - for key in kwargs.keys(): - if kwargs[key] is None: + + if key is None: + key = path + + for obj in objs[key]: + for kw_key, kw_value in kwargs.items(): + if kw_value is None: continue - if obj[key] != kwargs[key]: + if obj[kw_key] != kw_value: break else: found.append(obj) return found def get_obj(self, path, **kwargs): + ''' Get a specific object from a set of MSC REST objects ''' objs = self.query_objs(path, **kwargs) if len(objs) == 0: return {} @@ -213,7 +241,54 @@ class MSCModule(object): self.fail_json(msg='More than one object matches unique filter: {0}'.format(kwargs)) return objs[0] + def lookup_domain(self, domain): + ''' Look up a domain and return its id ''' + if domain is None: + return domain + + d = self.get_obj('auth/domains', key='domains', name=domain) + if not d: + self.module.fail_json(msg="Domain '%s' is not valid." % domain) + if 'id' not in d: + self.module.fail_json(msg="Domain lookup failed for '%s': %s" % (domain, d)) + return d['id'] + + def lookup_roles(self, roles): + ''' Look up roles and return their ids ''' + if roles is None: + return roles + + ids = [] + for role in roles: + r = self.get_obj('roles', name=role) + if not r: + self.module.fail_json(msg="Role '%s' is not valid." % role) + if 'id' not in r: + self.module.fail_json(msg="Role lookup failed for '%s': %s" % (role, r)) + ids.append(dict(roleId=r['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)) + + def lookup_labels(self, labels, label_type): + ''' Look up labels and return their ids (create if necessary) ''' + if labels is None: + return None + + ids = [] + for label in labels: + l = self.get_obj('labels', displayName=label) + if not l: + l = self.create_label(label, label_type) + if 'id' not in l: + self.module.fail_json(msg="Label lookup failed for '%s': %s" % (label, l)) + ids.append(l['id']) + return ids + def sanitize(self, updates, collate=False, required_keys=None): + ''' Clean up unset keys from a request payload ''' if required_keys is None: required_keys = [] self.proposed = deepcopy(self.existing) diff --git a/lib/ansible/modules/network/aci/msc_label.py b/lib/ansible/modules/network/aci/msc_label.py index 32c427bfe4..6d6280347b 100644 --- a/lib/ansible/modules/network/aci/msc_label.py +++ b/lib/ansible/modules/network/aci/msc_label.py @@ -23,21 +23,25 @@ options: label_id: description: - The ID of the label. - required: yes + type: str label: description: - The name of the label. + - Alternative to the name, you can use C(label_id). + type: str required: yes aliases: [ label_name, name ] type: description: - The type of the label. + type: str choices: [ site ] default: site state: description: - Use C(present) or C(absent) for adding or removing. - Use C(query) for listing an object or multiple objects. + type: str choices: [ absent, present, query ] default: present extends_documentation_fragment: msc @@ -49,9 +53,8 @@ EXAMPLES = r''' host: msc_host username: admin password: SomeSecretPassword - name: north_europe - label_id: 101 - description: North European Datacenter + label: Belgium + type: site state: present delegate_to: localhost @@ -60,7 +63,7 @@ EXAMPLES = r''' host: msc_host username: admin password: SomeSecretPassword - name: north_europe + label: Belgium state: absent delegate_to: localhost @@ -69,7 +72,7 @@ EXAMPLES = r''' host: msc_host username: admin password: SomeSecretPassword - name: north_europe + label: Belgium state: query delegate_to: localhost register: query_result @@ -151,11 +154,13 @@ def main(): elif state == 'present': msc.previous = msc.existing - msc.sanitize(dict( + payload = dict( id=label_id, displayName=label, type=label_type, - ), collate=True) + ) + + msc.sanitize(payload, collate=True) if msc.existing: if not issubset(msc.sent, msc.existing): diff --git a/lib/ansible/modules/network/aci/msc_role.py b/lib/ansible/modules/network/aci/msc_role.py index 400137a820..61cb667a2f 100644 --- a/lib/ansible/modules/network/aci/msc_role.py +++ b/lib/ansible/modules/network/aci/msc_role.py @@ -23,28 +23,39 @@ options: role_id: description: - The ID of the role. - required: yes + type: str role: description: - The name of the role. + - Alternative to the name, you can use C(role_id). + type: str required: yes aliases: [ name, role_name ] display_name: description: - The name of the role to be displayed in the web UI. + type: str description: description: - The description of the role. + type: str permissions: description: - A list of permissions tied to this role. type: list choices: + - backup-db + - manage-audit-records + - manage-labels - manage-roles - manage-schemas - manage-sites - manage-tenants + - manage-tenant-schemas - manage-users + - platform-logs + - view-all-audit-records + - view-labels - view-roles - view-schemas - view-sites @@ -55,6 +66,7 @@ options: description: - Use C(present) or C(absent) for adding or removing. - Use C(query) for listing an object or multiple objects. + type: str choices: [ absent, present, query ] default: present extends_documentation_fragment: msc @@ -66,9 +78,16 @@ EXAMPLES = r''' host: msc_host username: admin password: SomeSecretPassword - name: north_europe - role_id: 101 - description: North European Datacenter + role: readOnly + display_name: Read Only + description: Read-only access for troubleshooting + permissions: + - view-roles + - view-schemas + - view-sites + - view-tenants + - view-tenant-schemas + - view-users state: present delegate_to: localhost @@ -77,7 +96,7 @@ EXAMPLES = r''' host: msc_host username: admin password: SomeSecretPassword - name: north_europe + role: readOnly state: absent delegate_to: localhost @@ -86,7 +105,7 @@ EXAMPLES = r''' host: msc_host username: admin password: SomeSecretPassword - name: north_europe + role: readOnly state: query delegate_to: localhost register: query_result @@ -116,11 +135,18 @@ def main(): display_name=dict(type='str'), description=dict(type='str'), permissions=dict(type='list', choices=[ + 'backup-db', + 'manage-audit-records', + 'manage-labels', 'manage-roles', 'manage-schemas', 'manage-sites', 'manage-tenants', + 'manage-tenant-schemas', 'manage-users', + 'platform-logs', + 'view-all-audit-records', + 'view-labels', 'view-roles', 'view-schemas', 'view-sites', @@ -183,13 +209,15 @@ def main(): elif state == 'present': msc.previous = msc.existing - msc.sanitize(dict( + payload = dict( id=role_id, name=role, displayName=role, description=description, permissions=permissions, - ), collate=True) + ) + + msc.sanitize(payload, collate=True) if msc.existing: if not issubset(msc.sent, msc.existing): diff --git a/lib/ansible/modules/network/aci/msc_site.py b/lib/ansible/modules/network/aci/msc_site.py index a453282577..d090b4735a 100644 --- a/lib/ansible/modules/network/aci/msc_site.py +++ b/lib/ansible/modules/network/aci/msc_site.py @@ -40,17 +40,30 @@ options: description: - The ID of the site. type: str - required: yes site: description: - The name of the site. + - Alternative to the name, you can use C(site_id). type: str required: yes aliases: [ name, site_name ] labels: description: - The labels for this site. + - Labels that do not already exist will be automatically created. type: list + location: + description: + - Location of the site. + suboptions: + latitude: + description: + - The latitude of the location of the site. + type: float + longitude: + description: + - The longititude of the location of the site. + type: float urls: description: - A list of URLs to reference the APICs. @@ -72,8 +85,21 @@ EXAMPLES = r''' username: admin password: SomeSecretPassword site: north_europe - site_id: 101 description: North European Datacenter + apic_username: msc_admin + apic_password: AnotherSecretPassword + apic_site_id: 12 + urls: + - 10.2.3.4 + - 10.2.4.5 + - 10.3.5.6 + labels: + - NEDC + - Europe + - Diegem + location: + latitude: 50.887318 + longitude: 4.447084 state: present delegate_to: localhost @@ -114,12 +140,18 @@ from ansible.module_utils.network.aci.msc import MSCModule, msc_argument_spec, i def main(): + location_arg_spec = dict( + latitude=dict(type='float'), + longitude=dict(type='float'), + ) + argument_spec = msc_argument_spec() argument_spec.update( apic_password=dict(type='str', no_log=True), apic_site_id=dict(type='str'), apic_username=dict(type='str', default='admin'), labels=dict(type='list'), + location=dict(type='dict', options=location_arg_spec), site=dict(type='str', required=False, aliases=['name', 'site_name']), site_id=dict(type='str', required=False), state=dict(type='str', default='present', choices=['absent', 'present', 'query']), @@ -140,6 +172,10 @@ def main(): apic_site_id = module.params['apic_site_id'] site = module.params['site'] site_id = module.params['site_id'] + location = module.params['location'] + if location is not None: + latitude = module.params['location']['latitude'] + longitude = module.params['location']['longitude'] state = module.params['state'] urls = module.params['urls'] @@ -147,6 +183,9 @@ def main(): path = 'sites' + # Convert labels + labels = msc.lookup_labels(module.params['labels'], 'site') + # Query for msc.existing object(s) if site_id is None and site is None: msc.existing = msc.query_objs(path) @@ -175,31 +214,43 @@ def main(): if module.check_mode: msc.existing = {} else: - msc.existing = msc.request(path, method='DELETE') + msc.existing = msc.request(path, method='DELETE', qs=dict(force='true')) elif state == 'present': msc.previous = msc.existing - msc.sanitize(dict( + payload = dict( apicSiteId=apic_site_id, id=site_id, name=site, urls=urls, + labels=labels, username=apic_username, password=apic_password, - ), collate=True) + ) + + if location is not None: + payload['location'] = dict( + lat=latitude, + long=longitude, + ) + + msc.sanitize(payload, collate=True) if msc.existing: if not issubset(msc.sent, msc.existing): if module.check_mode: msc.existing = msc.proposed else: - msc.request(path, method='PUT', data=msc.sent) + msc.existing = msc.request(path, method='PUT', data=msc.sent) else: if module.check_mode: msc.existing = msc.proposed else: - msc.request(path, method='POST', data=msc.sent) + msc.existing = msc.request(path, method='POST', data=msc.sent) + + if 'password' in msc.existing: + msc.existing['password'] = '******' msc.exit_json() diff --git a/lib/ansible/modules/network/aci/msc_tenant.py b/lib/ansible/modules/network/aci/msc_tenant.py index b4b127f40e..975183c41f 100644 --- a/lib/ansible/modules/network/aci/msc_tenant.py +++ b/lib/ansible/modules/network/aci/msc_tenant.py @@ -24,10 +24,10 @@ options: description: - The ID of the tenant. type: str - required: yes tenant: description: - The name of the tenant. + - Alternative to the name, you can use C(tenant_id). type: str required: yes aliases: [ name, tenant_name ] @@ -161,14 +161,20 @@ def main(): elif state == 'present': msc.previous = msc.existing - msc.sanitize(dict( + payload = dict( description=description, id=tenant_id, name=tenant, displayName=display_name, siteAssociations=[], userAssociations=[dict(userId="0000ffff0000000000000020")], - ), collate=True) + ) + + msc.sanitize(payload, collate=True) + + # Ensure displayName is not undefined + if msc.sent.get('displayName') is None: + msc.sent['displayName'] = tenant if msc.existing: if not issubset(msc.sent, msc.existing): diff --git a/lib/ansible/modules/network/aci/msc_user.py b/lib/ansible/modules/network/aci/msc_user.py index 230afb7144..1cd53f006b 100644 --- a/lib/ansible/modules/network/aci/msc_user.py +++ b/lib/ansible/modules/network/aci/msc_user.py @@ -23,55 +23,87 @@ options: user_id: description: - The ID of the user. - required: yes + type: str user: description: - The name of the user. + - Alternative to the name, you can use C(user_id). + type: str required: yes aliases: [ name, user_name ] user_password: description: - The password of the user. + type: str first_name: description: - The first name of the user. + - This parameter is required when creating new users. + type: str last_name: description: - The last name of the user. + - This parameter is required when creating new users. + type: str email: description: - The email address of the user. + - This parameter is required when creating new users. + type: str phone: description: - The phone number of the user. + - This parameter is required when creating new users. + type: str account_status: description: - The status of the user account. + type: str choices: [ active ] domain: description: - The domain this user belongs to. + - When creating new users, this defaults to C(Local). + type: str roles: description: - - The roles this user has. + - The roles for this user. + type: list state: description: - Use C(present) or C(absent) for adding or removing. - Use C(query) for listing an object or multiple objects. + type: str choices: [ absent, present, query ] default: present +notes: +- A default installation of ACI Multi-Site ships with admin password 'we1come!' which requires a password change on first login. + See the examples of how to change the 'admin' password using Ansible. extends_documentation_fragment: msc ''' EXAMPLES = r''' +- name: Update initial admin password + msc_user: + host: msc_host + username: admin + password: we1come! + user_name: admin + user_password: SomeSecretPassword + state: present + delegate_to: localhost + - name: Add a new user msc_user: host: msc_host username: admin password: SomeSecretPassword - name: north_europe - user_id: 101 - description: North European Datacenter + user_name: dag + description: Test user + first_name: Dag + last_name: Wieers + email: dag@wieers.com + phone: +32 478 436 299 state: present delegate_to: localhost @@ -80,7 +112,7 @@ EXAMPLES = r''' host: msc_host username: admin password: SomeSecretPassword - name: north_europe + user_name: dag state: absent delegate_to: localhost @@ -89,7 +121,7 @@ EXAMPLES = r''' host: msc_host username: admin password: SomeSecretPassword - name: north_europe + user_name: dag state: query delegate_to: localhost register: query_result @@ -120,7 +152,7 @@ def main(): last_name=dict(type='str'), email=dict(type='str'), phone=dict(type='str'), - # FIXME: What possible options do we have ? + # TODO: What possible options do we have ? account_status=dict(type='str', choices=['active']), domain=dict(type='str'), roles=dict(type='list'), @@ -132,7 +164,7 @@ def main(): supports_check_mode=True, required_if=[ ['state', 'absent', ['user_name']], - ['state', 'present', ['user_name', 'password', 'first_name', 'last_name', 'email', 'phone', 'account_status']], + ['state', 'present', ['user_name']], ], ) @@ -144,18 +176,13 @@ def main(): email = module.params['email'] phone = module.params['phone'] account_status = module.params['account_status'] - # FIXME: Look up domain - domain = module.params['domain'] - # FIXME: Look up roles - roles = module.params['roles'] - roles_dict = list() - if roles: - for role in roles: - roles_dict.append(dict(roleId=role)) state = module.params['state'] msc = MSCModule(module) + roles = msc.lookup_roles(module.params['roles']) + domain = msc.lookup_domain(module.params['domain']) + path = 'users' # Query for existing object(s) @@ -191,7 +218,7 @@ def main(): elif state == 'present': msc.previous = msc.existing - msc.sanitize(dict( + payload = dict( id=user_id, username=user_name, password=user_password, @@ -199,19 +226,23 @@ def main(): lastName=last_name, emailAddress=email, phoneNumber=phone, - # accountStatus={}, accountStatus=account_status, - needsPasswordUpdate=False, domainId=domain, - roles=roles_dict, + roles=roles, # active=True, # remote=True, - ), collate=True) + ) + + msc.sanitize(payload, collate=True) + + if msc.sent.get('accountStatus') is None: + msc.sent['accountStatus'] = 'active' if msc.existing: if not issubset(msc.sent, msc.existing): # NOTE: Since MSC always returns '******' as password, we need to assume a change - if 'password' in msc.sent: + if 'password' in msc.proposed: + msc.module.warn("A password change is assumed, as the MSC REST API does not return passwords we do not know.") msc.result['changed'] = True if module.check_mode: diff --git a/lib/ansible/utils/module_docs_fragments/msc.py b/lib/ansible/utils/module_docs_fragments/msc.py index 4589389edd..8b32615dbd 100644 --- a/lib/ansible/utils/module_docs_fragments/msc.py +++ b/lib/ansible/utils/module_docs_fragments/msc.py @@ -48,18 +48,18 @@ options: description: - If C(no), it will not use a proxy, even if one is defined in an environment variable on the target hosts. type: bool - default: 'yes' + default: yes use_ssl: description: - If C(no), an HTTP connection will be used instead of the default HTTPS connection. type: bool - default: 'yes' + default: yes validate_certs: description: - If C(no), SSL certificates will not be validated. - This should only set to C(no) when used on personally controlled sites using self-signed certificates. type: bool - default: 'yes' + default: yes notes: - Please read the :ref:`aci_guide` for more detailed information on how to manage your ACI infrastructure using Ansible. ''' diff --git a/test/integration/targets/msc_site/tasks/main.yml b/test/integration/targets/msc_site/tasks/main.yml index fb5490cc59..3bdd4b6f20 100644 --- a/test/integration/targets/msc_site/tasks/main.yml +++ b/test/integration/targets/msc_site/tasks/main.yml @@ -10,7 +10,7 @@ # CLEAN ENVIRONMENT -- name: Remove site ansible_test2 +- name: Remove site 2 msc_site: &site_absent host: '{{ msc_hostname }}' username: '{{ msc_username }}' @@ -19,13 +19,13 @@ use_ssl: '{{ msc_use_ssl | default(true) }}' use_proxy: '{{ msc_use_proxy | default(true) }}' output_level: '{{ msc_output_level | default("info") }}' - site: ansible_test2 + site: '{{ msc_site | default("ansible_test") }}_2' state: absent -- name: Remove site ansible_test +- name: Remove site msc_site: <<: *site_absent - site: ansible_test + site: '{{ msc_site | default("ansible_test") }}' register: cm_remove_site @@ -39,12 +39,19 @@ use_ssl: '{{ msc_use_ssl | default(true) }}' use_proxy: '{{ msc_use_proxy | default(true) }}' output_level: '{{ msc_output_level | default("info") }}' - site: ansible_test + site: '{{ msc_site | default("ansible_test") }}' apic_username: admin apic_password: '{{ apic_password }}' apic_site_id: 101 urls: - - https://{{ apic_hostname }}/ + - https://{{ apic_hostname }} + location: + latitude: 50.887318 + longitude: 4.447084 + labels: + - Diegem + - EMEA + - POD51 state: present check_mode: yes register: cm_add_site @@ -55,7 +62,7 @@ - cm_add_site is changed - cm_add_site.previous == {} - cm_add_site.current.id is not defined - - cm_add_site.current.name == 'ansible_test' + - cm_add_site.current.name == msc_site|default("ansible_test") - name: Add site (normal mode) msc_site: *site_present @@ -67,7 +74,7 @@ - nm_add_site is changed - nm_add_site.previous == {} - nm_add_site.current.id is defined - - nm_add_site.current.name == 'ansible_test' + - nm_add_site.current.name == msc_site|default("ansible_test") - name: Add site again (check_mode) msc_site: *site_present @@ -78,9 +85,9 @@ assert: that: - cm_add_site_again is not changed - - cm_add_site_again.previous.name == 'ansible_test' + - cm_add_site_again.previous.name == msc_site|default("ansible_test") - cm_add_site_again.current.id == nm_add_site.current.id - - cm_add_site_again.current.name == 'ansible_test' + - cm_add_site_again.current.name == msc_site|default("ansible_test") - name: Add site again (normal mode) msc_site: *site_present @@ -90,9 +97,9 @@ assert: that: - nm_add_site_again is not changed - - nm_add_site_again.previous.name == 'ansible_test' + - nm_add_site_again.previous.name == msc_site|default("ansible_test") - nm_add_site_again.current.id == nm_add_site.current.id - - nm_add_site_again.current.name == 'ansible_test' + - nm_add_site_again.current.name == msc_site|default("ansible_test") # CHANGE SITE @@ -100,7 +107,7 @@ msc_site: <<: *site_present site_id: '{{ nm_add_site.current.id }}' - site: ansible_test2 + site: '{{ msc_site | default("ansible_test") }}_2' check_mode: yes register: cm_change_site @@ -109,13 +116,13 @@ that: - cm_change_site is changed - cm_change_site.current.id == nm_add_site.current.id - - cm_change_site.current.name == 'ansible_test2' + - cm_change_site.current.name == '{{ msc_site | default("ansible_test") }}_2' - name: Change site (normal mode) msc_site: <<: *site_present site_id: '{{ nm_add_site.current.id }}' - site: ansible_test2 + site: '{{ msc_site | default("ansible_test") }}_2' output_level: debug register: nm_change_site @@ -124,13 +131,13 @@ that: - nm_change_site is changed - nm_change_site.current.id == nm_add_site.current.id - - nm_change_site.current.name == 'ansible_test2' + - nm_change_site.current.name == '{{ msc_site | default("ansible_test") }}_2' - name: Change site again (check_mode) msc_site: <<: *site_present site_id: '{{ nm_add_site.current.id }}' - site: ansible_test2 + site: '{{ msc_site | default("ansible_test") }}_2' check_mode: yes register: cm_change_site_again @@ -139,13 +146,13 @@ that: - cm_change_site_again is not changed - cm_change_site_again.current.id == nm_add_site.current.id - - cm_change_site_again.current.name == 'ansible_test2' + - cm_change_site_again.current.name == '{{ msc_site | default("ansible_test") }}_2' - name: Change site again (normal mode) msc_site: <<: *site_present site_id: '{{ nm_add_site.current.id }}' - site: ansible_test2 + site: '{{ msc_site | default("ansible_test") }}_2' register: nm_change_site_again - name: Verify nm_change_site_again @@ -153,7 +160,7 @@ that: - nm_change_site_again is not changed - nm_change_site_again.current.id == nm_add_site.current.id - - nm_change_site_again.current.name == 'ansible_test2' + - nm_change_site_again.current.name == '{{ msc_site | default("ansible_test") }}_2' # QUERY ALL SITES @@ -187,14 +194,14 @@ - name: Query our site msc_site: <<: *site_query - site: ansible_test2 + site: '{{ msc_site | default("ansible_test") }}_2' check_mode: yes register: cm_query_site - name: Query our site msc_site: <<: *site_query - site: ansible_test2 + site: '{{ msc_site | default("ansible_test") }}_2' register: nm_query_site - name: Verify query_site @@ -202,10 +209,10 @@ that: - cm_query_site is not changed - cm_query_site.current.id == nm_add_site.current.id - - cm_query_site.current.name == 'ansible_test2' + - cm_query_site.current.name == '{{ msc_site | default("ansible_test") }}_2' - nm_query_site is not changed - nm_query_site.current.id == nm_add_site.current.id - - nm_query_site.current.name == 'ansible_test2' + - nm_query_site.current.name == '{{ msc_site | default("ansible_test") }}_2' - cm_query_site == nm_query_site @@ -257,14 +264,14 @@ - name: Query non-existing site (check_mode) msc_site: <<: *site_query - site: ansible_test + site: '{{ msc_site | default("ansible_test") }}' check_mode: yes register: cm_query_non_site - name: Query non-existing site (normal mode) msc_site: <<: *site_query - site: ansible_test + site: '{{ msc_site | default("ansible_test") }}' register: nm_query_non_site # TODO: Implement more tests diff --git a/test/integration/targets/msc_user/tasks/main.yml b/test/integration/targets/msc_user/tasks/main.yml index ca2feeb8c1..4136e6e8e6 100644 --- a/test/integration/targets/msc_user/tasks/main.yml +++ b/test/integration/targets/msc_user/tasks/main.yml @@ -48,7 +48,8 @@ phone: +32 478 436 299 account_status: active roles: - - 0000ffff0000000000000031 + - powerUser + domain: Local state: present check_mode: yes