Add aci_vmm_credential.py (#60910)

* add module to create aci VMM credential objects
add initial remove and add integration tests for VMM credential objects

* update 'credential' var name to 'name'

* move vmware tests to domain type specific file

* move vmware tests to domain type specific file
add include task in main file to reference domain type specific tests

* update task names
add test to remove credential prior to first credential add
add tests for querying individual credentials
add tests for query all credentials
add additional tests for removing credentials

* update version added to 2.9
remove invalid module references from 'seealso' section

* fix list reference in query all assertions

* add reference to VM_PROVIDER_MAPPING keys for vm_provider arg
This commit is contained in:
jasonjuenger 2019-08-27 05:08:24 -07:00 committed by Dag Wieers
parent b53bc94cc5
commit dfd1b29777
4 changed files with 561 additions and 0 deletions

View file

@ -0,0 +1,308 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = r'''
---
module: aci_vmm_credential
short_description: Manage virtual domain credential profiles (vmm:UsrAccP)
description:
- Manage virtual domain credential profiles on Cisco ACI fabrics.
version_added: '2.9'
options:
name:
description:
- Name of the credential profile.
type: str
aliases: [ credential_name, credential_profile ]
credential_password:
description:
- VMM controller password.
type: str
aliases: []
credential_username:
description:
- VMM controller username.
type: str
aliases: []
description:
description:
- Description for the tenant.
type: str
aliases: [ descr ]
domain:
description:
- Name of the virtual domain profile.
type: str
aliases: [ domain_name, domain_profile, name ]
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
vm_provider:
description:
- The VM platform for VMM Domains.
- Support for Kubernetes was added in ACI v3.0.
- Support for CloudFoundry, OpenShift and Red Hat was added in ACI v3.1.
type: str
choices: [ cloudfoundry, kubernetes, microsoft, openshift, openstack, redhat, vmware ]
extends_documentation_fragment: aci
seealso:
- module: aci_domain
- name: APIC Management Information Model reference
description: More information about the internal APIC classes B(vmm:DomP)
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Jason Juenger (@jasonjuenger)
'''
EXAMPLES = r'''
- name: Add credential to VMware VMM domain
aci_vmm_credential:
host: apic
username: admin
password: SomeSecretPassword
domain: vmware_dom
description: secure credential
name: vCenterCredential
credential_username: vCenterUsername
credential_password: vCenterPassword
vm_provider: vmware
state: present
- name: Remove credential from VMware VMM domain
aci_vmm_credential:
host: apic
username: admin
password: SomeSecretPassword
domain: vmware_dom
name: myCredential
vm_provider: vmware
state: absent
- name: Query a specific VMware VMM credential
aci_vmm_credential:
host: apic
username: admin
password: SomeSecretPassword
domain: vmware_dom
name: vCenterCredential
vm_provider: vmware
state: query
delegate_to: localhost
register: query_result
- name: Query all VMware VMM credentials
aci_vmm_credential:
host: apic
username: admin
password: SomeSecretPassword
domain: vmware_dom
vm_provider: vmware
state: query
delegate_to: localhost
register: query_result
'''
RETURN = r'''
current:
description: The existing configuration from the APIC after the module has finished
returned: success
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
error:
description: The error information as returned from the APIC
returned: failure
type: dict
sample:
{
"code": "122",
"text": "unknown managed object class foo"
}
raw:
description: The raw output returned by the APIC REST API (xml or json)
returned: parse error
type: str
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
sent:
description: The actual/minimal configuration pushed to the APIC
returned: info
type: list
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment"
}
}
}
previous:
description: The original configuration from the APIC before the module has started
returned: info
type: list
sample:
[
{
"fvTenant": {
"attributes": {
"descr": "Production",
"dn": "uni/tn-production",
"name": "production",
"nameAlias": "",
"ownerKey": "",
"ownerTag": ""
}
}
}
]
proposed:
description: The assembled configuration from the user-provided parameters
returned: info
type: dict
sample:
{
"fvTenant": {
"attributes": {
"descr": "Production environment",
"name": "production"
}
}
}
filter_string:
description: The filter string used for the request
returned: failure or debug
type: str
sample: ?rsp-prop-include=config-only
method:
description: The HTTP method used for the request to the APIC
returned: failure or debug
type: str
sample: POST
response:
description: The HTTP response from the APIC
returned: failure or debug
type: str
sample: OK (30 bytes)
status:
description: The HTTP status from the APIC
returned: failure or debug
type: int
sample: 200
url:
description: The HTTP url used for the request to the APIC
returned: failure or debug
type: str
sample: https://10.11.12.13/api/mo/uni/tn-production.json
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
VM_PROVIDER_MAPPING = dict(
cloudfoundry='CloudFoundry',
kubernetes='Kubernetes',
microsoft='Microsoft',
openshift='OpenShift',
openstack='OpenStack',
redhat='Redhat',
vmware='VMware',
)
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
name=dict(type='str', aliases=['credential_name', 'credential_profile']),
credential_password=dict(type='str'),
credential_username=dict(type='str'),
description=dict(type='str', aliases=['descr']),
domain=dict(type='str', aliases=['domain_name', 'domain_profile']),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
vm_provider=dict(type='str', choices=VM_PROVIDER_MAPPING.keys())
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['domain']],
['state', 'present', ['domain']],
],
)
name = module.params['name']
credential_password = module.params['credential_password']
credential_username = module.params['credential_username']
description = module.params['description']
domain = module.params['domain']
state = module.params['state']
vm_provider = module.params['vm_provider']
credential_class = 'vmmUsrAccP'
usracc_mo = 'uni/vmmp-{0}/dom-{1}/usracc-{2}'.format(VM_PROVIDER_MAPPING[vm_provider], domain, name)
usracc_rn = 'vmmp-{0}/dom-{1}/usracc-{2}'.format(VM_PROVIDER_MAPPING[vm_provider], domain, name)
# Ensure that querying all objects works when only domain is provided
if name is None:
usracc_mo = None
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
aci_class=credential_class,
aci_rn=usracc_rn,
module_object=usracc_mo,
target_filter={'name': domain, 'usracc': name},
),
)
aci.get_existing()
if state == 'present':
aci.payload(
aci_class=credential_class,
class_config=dict(
descr=description,
name=name,
pwd=credential_password,
usr=credential_username
),
)
aci.get_diff(aci_class=credential_class)
aci.post_config()
elif state == 'absent':
aci.delete_config()
aci.exit_json()
if __name__ == "__main__":
main()

View file

@ -0,0 +1,2 @@
# No ACI simulator yet, so not enabled
unsupported

View file

@ -0,0 +1,12 @@
# Test code for the ACI modules
# Copyright: (c) 2018, Dag Wieers (@dagwieers) <dag@wieers.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
- name: Test that we have an ACI APIC host, ACI username and ACI password
fail:
msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.'
when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined
- include_tasks: vmware.yml
when: vmware is not defined or vmware

View file

@ -0,0 +1,239 @@
# Test code for the ACI modules
# Copyright: (c) 2017, Dag Wieers (@dagwieers) <dag@wieers.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# Remove VMM domain
- name: Remove VMM domain (normal mode)
aci_domain: &domain_absent
host: '{{ aci_hostname }}'
username: '{{ aci_username }}'
password: '{{ aci_password }}'
validate_certs: '{{ aci_validate_certs | default(false) }}'
use_ssl: '{{ aci_use_ssl | default(true) }}'
use_proxy: '{{ aci_use_proxy | default(true) }}'
output_level: '{{ aci_output_level | default("info") }}'
domain: vmm_dom
domain_type: vmm
vm_provider: vmware
state: absent
register: nm_remove_domain
# ADD VMM domain for testing
- name: Add VMM domain (normal mode)
aci_domain: &domain_present
host: '{{ aci_hostname }}'
username: '{{ aci_username }}'
password: '{{ aci_password }}'
validate_certs: '{{ aci_validate_certs | default(false) }}'
use_ssl: '{{ aci_use_ssl | default(true) }}'
use_proxy: '{{ aci_use_proxy | default(true) }}'
output_level: '{{ aci_output_level | default("info") }}'
domain: vmm_dom
domain_type: vmm
vm_provider: vmware
state: present
register: nm_add_domain
- name: Verify add_domain
assert:
that:
- nm_add_domain is changed
# REMOVE credential
- name: Remove credential (check mode)
aci_vmm_credential: &credential_absent
host: '{{ aci_hostname }}'
username: '{{ aci_username }}'
password: '{{ aci_password }}'
validate_certs: '{{ aci_validate_certs | default(false) }}'
use_ssl: '{{ aci_use_ssl | default(true) }}'
use_proxy: '{{ aci_use_proxy | default(true) }}'
output_level: '{{ aci_output_level | default("info") }}'
name: vmm_cred
description: my_new_cred
domain: vmm_dom
credential_username: myUsername
credential_password: mySecretPassword
vm_provider: vmware
state: absent
check_mode: yes
register: cm_remove_credential
- name: Remove vmware VMM credential (normal mode)
aci_vmm_credential: *credential_absent
register: nm_remove_credential
- name: Verify remove_credential
assert:
that:
- cm_remove_credential is not changed
- nm_remove_credential is not changed
# ADD credential
- name: Add vmware VMM credential (check mode)
aci_vmm_credential: &credential_present
host: '{{ aci_hostname }}'
username: '{{ aci_username }}'
password: '{{ aci_password }}'
validate_certs: '{{ aci_validate_certs | default(false) }}'
use_ssl: '{{ aci_use_ssl | default(true) }}'
use_proxy: '{{ aci_use_proxy | default(true) }}'
output_level: '{{ aci_output_level | default("info") }}'
name: vmm_cred
description: my_new_cred
domain: vmm_dom
credential_username: myUsername
credential_password: mySecretPassword
vm_provider: vmware
state: present
check_mode: yes
register: cm_add_credential
# NOTE: Setting password is not idempotent
- name: Add vmware VMM credential (normal mode)
aci_vmm_credential: *credential_present
register: nm_add_credential
# NOTE: Setting password is not idempotent
- name: Add vmware VMM credential again (check mode)
aci_vmm_credential: *credential_present
check_mode: yes
register: cm_add_credential_again
- name: Verify add_credential
assert:
that:
- cm_add_credential is changed
- nm_add_credential is changed
- 'cm_add_credential.sent == nm_add_credential.sent == {"vmmUsrAccP": {"attributes": {"descr": "my_new_cred", "name": "vmm_cred", "pwd": "mySecretPassword", "usr": "myUsername"}}}'
- 'cm_add_credential.proposed == nm_add_credential.proposed == {"vmmUsrAccP": {"attributes": {"descr": "my_new_cred", "name": "vmm_cred", "pwd": "mySecretPassword", "usr": "myUsername"}}}'
- cm_add_credential.current == cm_add_credential.previous == nm_add_credential.previous == []
- nm_add_credential.current.0.vmmUsrAccP.attributes.dn == 'uni/vmmp-VMware/dom-vmm_dom/usracc-vmm_cred'
- nm_add_credential.current.0.vmmUsrAccP.attributes.name == 'vmm_cred'
# MODIFY credential
- name: Modify vmware VMM credential (check mode)
aci_vmm_credential: &credential_mod
host: '{{ aci_hostname }}'
username: '{{ aci_username }}'
password: '{{ aci_password }}'
validate_certs: '{{ aci_validate_certs | default(false) }}'
use_ssl: '{{ aci_use_ssl | default(true) }}'
use_proxy: '{{ aci_use_proxy | default(true) }}'
output_level: '{{ aci_output_level | default("info") }}'
name: vmm_cred
description: my_updated_descr
domain: vmm_dom
credential_username: myNewUsername
credential_password: myNewSecretPassword
vm_provider: vmware
state: present
check_mode: yes
register: cm_mod_credential
- name: Modify vmware VMM credential (normal mode)
aci_vmm_credential: *credential_mod
register: nm_mod_credential
- name: Verify mod_credential
assert:
that:
- cm_mod_credential is changed
- nm_mod_credential is changed
- 'cm_mod_credential.sent == nm_mod_credential.sent == {"vmmUsrAccP": {"attributes": {"descr": "my_updated_descr", "pwd": "myNewSecretPassword", "usr": "myNewUsername"}}}'
- 'cm_mod_credential.proposed == nm_mod_credential.proposed == {"vmmUsrAccP": {"attributes": {"descr": "my_updated_descr", "name": "vmm_cred", "pwd": "myNewSecretPassword", "usr": "myNewUsername"}}}'
- nm_mod_credential.current.0.vmmUsrAccP.attributes.dn == 'uni/vmmp-VMware/dom-vmm_dom/usracc-vmm_cred'
- nm_mod_credential.current.0.vmmUsrAccP.attributes.name == 'vmm_cred'
- name: Query existing vmware VMM credential (check mode)
aci_vmm_credential: &query_existing_cred
host: '{{ aci_hostname }}'
username: '{{ aci_username }}'
password: '{{ aci_password }}'
validate_certs: '{{ aci_validate_certs | default(false) }}'
use_ssl: '{{ aci_use_ssl | default(true) }}'
use_proxy: '{{ aci_use_proxy | default(true) }}'
output_level: '{{ aci_output_level | default("info") }}'
name: vmm_cred
domain: vmm_dom
vm_provider: vmware
state: query
check_mode: yes
register: cm_query_credential
- name: Query existing vmware VMM credential (normal mode)
aci_vmm_credential: *query_existing_cred
register: nm_query_credential
- name: Query non-existent vmware VMM credential
aci_vmm_credential:
host: '{{ aci_hostname }}'
username: '{{ aci_username }}'
password: '{{ aci_password }}'
validate_certs: '{{ aci_validate_certs | default(false) }}'
use_ssl: '{{ aci_use_ssl | default(true) }}'
use_proxy: '{{ aci_use_proxy | default(true) }}'
output_level: '{{ aci_output_level | default("info") }}'
name: vmm_fake_cred
domain: vmm_dom
vm_provider: vmware
state: query
register: nm_query_fake_credential
- name: Query all vmware VMM credentials (check mode)
aci_vmm_credential: &query_all_creds
host: '{{ aci_hostname }}'
username: '{{ aci_username }}'
password: '{{ aci_password }}'
validate_certs: '{{ aci_validate_certs | default(false) }}'
use_ssl: '{{ aci_use_ssl | default(true) }}'
use_proxy: '{{ aci_use_proxy | default(true) }}'
output_level: '{{ aci_output_level | default("info") }}'
vm_provider: vmware
state: query
check_mode: yes
register: cm_query_all_credential
- name: Query all vmware VMM credentials (normal mode)
aci_vmm_credential: *query_all_creds
register: nm_query_all_credential
- name: Verify query_credential
assert:
that:
- cm_query_credential is not changed
- nm_query_credential is not changed
- nm_query_fake_credential is not changed
- cm_query_all_credential is not changed
- nm_query_all_credential is not changed
- cm_query_credential.current.0.vmmUsrAccP.attributes.name == 'vmm_cred'
- nm_query_credential.current.0.vmmUsrAccP.attributes.name == 'vmm_cred'
- nm_query_fake_credential.current == []
- cm_query_all_credential.current.0.vmmUsrAccP.attributes.name == 'vmm_cred'
- nm_query_all_credential.current.0.vmmUsrAccP.attributes.name == 'vmm_cred'
- name: Remove credential (check_mode)
aci_vmm_credential: *credential_absent
check_mode: yes
register: cm_remove_credential_again
- name: Remove credential (normal_mode)
aci_vmm_credential: *credential_absent
register: nm_remove_credential_again
- name: Remove credential (normal_mode)
aci_vmm_credential: *credential_absent
register: nm_remove_credential_final
- name: Verify remove_credential
assert:
that:
- cm_remove_credential_again is changed
- nm_remove_credential_again is changed
- nm_remove_credential_final is not changed
# Remove VMM domain after testing
- name: Remove VMM domain (normal_mode)
aci_domain: *domain_absent
register: nm_remove_domain_again