support for iscsi vnics based on customer feature request (#48377)

* support for iscsi vnics based on customer feature request
integration tests added for iscsi vnics and vnic state absent

* correct version_added for iscsi and vnic lists
This commit is contained in:
David Soper 2018-11-09 10:26:23 -06:00 committed by John R Barker
parent f4fa3314c4
commit 9757d9d4c3
2 changed files with 341 additions and 105 deletions

View file

@ -44,17 +44,60 @@ options:
description: description:
- List of vNICs used by the LAN Connectivity Policy. - List of vNICs used by the LAN Connectivity Policy.
- vNICs used by the LAN Connectivity Policy must be created from a vNIC template. - vNICs used by the LAN Connectivity Policy must be created from a vNIC template.
- "Each list element has the following suboptions:" suboptions:
- "= name" name:
- " The name of the vNIC (required)." description:
- "= vnic_template" - The name of the vNIC.
- " The name of the vNIC template (required)." required: yes
- "- adapter_policy" vnic_template:
- " The name of the Ethernet adapter policy." description:
- " A user defined policy can be used, or one of the system defined policies." - The name of the vNIC template.
- "- order" required: yes
- " String specifying the vNIC assignment order (e.g., '1', '2')." adapter_policy:
- " [Default: unspecified]" description:
- The name of the Ethernet adapter policy.
- A user defined policy can be used, or one of the system defined policies.
order:
description:
- String specifying the vNIC assignment order (e.g., '1', '2').
default: 'unspecified'
state:
description:
- If C(present), will verify vnic is configured within policy.
If C(absent), will verify vnic is absent from policy.
choices: [ present, absent ]
default: present
version_added: '2.8'
iscsi_vnic_list:
description:
- List of iSCSI vNICs used by the LAN Connectivity Policy.
suboptions:
name:
description:
- The name of the iSCSI vNIC.
required: yes
overlay_vnic:
description:
- The LAN vNIC associated with this iSCSI vNIC.
iscsi_adapter_policy:
description:
- The iSCSI adapter policy associated with this iSCSI vNIC.
mac_address:
description:
- The MAC address associated with this iSCSI vNIC.
- If the MAC address is not set, Cisco UCS Manager uses a derived MAC address.
default: derived
vlan_name:
description:
- The VLAN used for the iSCSI vNIC.
default: default
state:
description:
- If C(present), will verify iscsi vnic is configured within policy.
If C(absent), will verify iscsi vnic is absent from policy.
choices: [ present, absent ]
default: present
version_added: '2.8'
org_dn: org_dn:
description: description:
- Org dn (distinguished name) - Org dn (distinguished name)
@ -73,21 +116,33 @@ EXAMPLES = r'''
hostname: 172.16.143.150 hostname: 172.16.143.150
username: admin username: admin
password: password password: password
name: Cntr-LAN-Boot name: Cntr-FC-Boot
vnic_list: vnic_list:
- name: Fabric-A - name: eno1
vnic_template: vNIC-Template-A vnic_template: Cntr-Template
adapter_policy: Linux adapter_policy: Linux
- name: Fabric-B - name: eno2
vnic_template: vNIC-Template-B vnic_template: Container-NFS-A
adapter_policy: Linux adapter_policy: Linux
- name: eno3
vnic_template: Container-NFS-B
adapter_policy: Linux
iscsi_vnic_list:
- name: iSCSIa
overlay_vnic: eno1
iscsi_adapter_policy: default
vlan_name: Container-MGMT-VLAN
- name: iSCSIb
overlay_vnic: eno3
iscsi_adapter_policy: default
vlan_name: Container-TNT-A-NFS
- name: Remove LAN Connectivity Policy - name: Remove LAN Connectivity Policy
ucs_lan_connectivity: ucs_lan_connectivity:
hostname: 172.16.143.150 hostname: 172.16.143.150
username: admin username: admin
password: password password: password
name: Cntr-LAN-Boot name: Cntr-FC-Boot
state: absent state: absent
''' '''
@ -99,76 +154,14 @@ from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.remote_management.ucs import UCSModule, ucs_argument_spec from ansible.module_utils.remote_management.ucs import UCSModule, ucs_argument_spec
def main(): def configure_lan_connectivity(ucs, module, dn):
argument_spec = ucs_argument_spec
argument_spec.update(
org_dn=dict(type='str', default='org-root'),
name=dict(type='str', required=True),
description=dict(type='str', aliases=['descr'], default=''),
vnic_list=dict(type='list'),
state=dict(type='str', default='present', choices=['present', 'absent']),
)
module = AnsibleModule(
argument_spec,
supports_check_mode=True,
)
ucs = UCSModule(module)
err = False
# UCSModule creation above verifies ucsmsdk is present and exits on failure. Additional imports are done below.
from ucsmsdk.mometa.vnic.VnicLanConnPolicy import VnicLanConnPolicy from ucsmsdk.mometa.vnic.VnicLanConnPolicy import VnicLanConnPolicy
from ucsmsdk.mometa.vnic.VnicEther import VnicEther from ucsmsdk.mometa.vnic.VnicEther import VnicEther
from ucsmsdk.mometa.vnic.VnicEtherIf import VnicEtherIf from ucsmsdk.mometa.vnic.VnicIScsiLCP import VnicIScsiLCP
from ucsmsdk.mometa.vnic.VnicVlan import VnicVlan
changed = False if not module.check_mode:
try: try:
mo_exists = False
props_match = False
# dn is <org_dn>/lan-conn-pol-<name>
dn = module.params['org_dn'] + '/lan-conn-pol-' + module.params['name']
mo = ucs.login_handle.query_dn(dn)
if mo:
mo_exists = True
if module.params['state'] == 'absent':
# mo must exist but all properties do not have to match
if mo_exists:
if not module.check_mode:
ucs.login_handle.remove_mo(mo)
ucs.login_handle.commit()
changed = True
else:
# set default params. Done here to set values for lists which can't be done in the argument_spec
if module.params.get('vnic_list'):
for vnic in module.params['vnic_list']:
if not vnic.get('adapter_policy'):
vnic['adapter_policy'] = ''
if not vnic.get('order'):
vnic['order'] = 'unspecified'
if mo_exists:
# check top-level mo props
kwargs = dict(descr=module.params['description'])
if (mo.check_prop_match(**kwargs)):
# top-level props match, check next level mo/props
if not module.params.get('vnic_list'):
props_match = True
else:
# check vnicEther props
for vnic in module.params['vnic_list']:
child_dn = dn + '/ether-' + vnic['name']
mo_1 = ucs.login_handle.query_dn(child_dn)
if mo_1:
kwargs = dict(adaptor_profile_name=vnic['adapter_policy'])
kwargs['order'] = vnic['order']
kwargs['nw_templ_name'] = vnic['vnic_template']
if (mo_1.check_prop_match(**kwargs)):
props_match = True
if not props_match:
if not module.check_mode:
# create if mo does not already exist # create if mo does not already exist
mo = VnicLanConnPolicy( mo = VnicLanConnPolicy(
parent_mo_or_dn=module.params['org_dn'], parent_mo_or_dn=module.params['org_dn'],
@ -178,6 +171,12 @@ def main():
if module.params.get('vnic_list'): if module.params.get('vnic_list'):
for vnic in module.params['vnic_list']: for vnic in module.params['vnic_list']:
if vnic['state'] == 'absent':
child_dn = dn + '/ether-' + vnic['name']
mo_1 = ucs.login_handle.query_dn(child_dn)
if mo_1:
ucs.login_handle.remove_mo(mo_1)
else: # state == 'present'
mo_1 = VnicEther( mo_1 = VnicEther(
addr='derived', addr='derived',
parent_mo_or_dn=mo, parent_mo_or_dn=mo,
@ -187,17 +186,168 @@ def main():
order=vnic['order'], order=vnic['order'],
) )
if module.params.get('iscsi_vnic_list'):
for iscsi_vnic in module.params['iscsi_vnic_list']:
if iscsi_vnic['state'] == 'absent':
child_dn = dn + '/iscsi-' + iscsi_vnic['name']
mo_1 = ucs.login_handle.query_dn(child_dn)
if mo_1:
ucs.login_handle.remove_mo(mo_1)
else: # state == 'present'
mo_1 = VnicIScsiLCP(
parent_mo_or_dn=mo,
name=iscsi_vnic['name'],
adaptor_profile_name=iscsi_vnic['iscsi_adapter_policy'],
vnic_name=iscsi_vnic['overlay_vnic'],
addr=iscsi_vnic['mac_address'],
)
VnicVlan(
parent_mo_or_dn=mo_1,
vlan_name=iscsi_vnic['vlan_name'],
)
ucs.login_handle.add_mo(mo, True) ucs.login_handle.add_mo(mo, True)
ucs.login_handle.commit() ucs.login_handle.commit()
changed = True except Exception as e: # generic Exception handling because SDK can throw a variety of exceptions
except Exception as e:
err = True
ucs.result['msg'] = "setup error: %s " % str(e) ucs.result['msg'] = "setup error: %s " % str(e)
ucs.result['changed'] = changed
if err:
module.fail_json(**ucs.result) module.fail_json(**ucs.result)
ucs.result['changed'] = True
def check_vnic_props(ucs, module, dn):
props_match = True
if module.params.get('vnic_list'):
# check vnicEther props
for vnic in module.params['vnic_list']:
child_dn = dn + '/ether-' + vnic['name']
mo_1 = ucs.login_handle.query_dn(child_dn)
if mo_1:
if vnic['state'] == 'absent':
props_match = False
break
else: # state == 'present'
kwargs = dict(adaptor_profile_name=vnic['adapter_policy'])
kwargs['order'] = vnic['order']
kwargs['nw_templ_name'] = vnic['vnic_template']
if not (mo_1.check_prop_match(**kwargs)):
props_match = False
break
else: # mo_1 did not exist
if vnic['state'] == 'present':
props_match = False
break
return props_match
def check_iscsi_vnic_props(ucs, module, dn):
props_match = True
if module.params.get('iscsi_vnic_list'):
# check vnicIScsiLCP props
for iscsi_vnic in module.params['iscsi_vnic_list']:
child_dn = dn + '/iscsi-' + iscsi_vnic['name']
mo_1 = ucs.login_handle.query_dn(child_dn)
if mo_1:
if iscsi_vnic['state'] == 'absent':
props_match = False
break
else: # state == 'present'
kwargs = dict(vnic_name=iscsi_vnic['overlay_vnic'])
kwargs['adaptor_profile_name'] = iscsi_vnic['iscsi_adapter_policy']
kwargs['addr'] = iscsi_vnic['mac_address']
if (mo_1.check_prop_match(**kwargs)):
# check vlan
child_dn = child_dn + '/vlan'
mo_2 = ucs.login_handle.query_dn(child_dn)
if mo_2:
kwargs = dict(vlan_name=iscsi_vnic['vlan_name'])
if not (mo_2.check_prop_match(**kwargs)):
props_match = False
break
else: # mo_1 props did not match
props_match = False
break
else: # mo_1 did not exist
if iscsi_vnic['state'] == 'present':
props_match = False
break
return props_match
def check_lan_connecivity_props(ucs, module, mo, dn):
props_match = False
# check top-level mo props
kwargs = dict(descr=module.params['description'])
if (mo.check_prop_match(**kwargs)):
# top-level props match, check next level mo/props
# check vnic 1st
props_match = check_vnic_props(ucs, module, dn)
if props_match:
props_match = check_iscsi_vnic_props(ucs, module, dn)
return props_match
def main():
vnic = dict(
name=dict(type='str', required=True),
vnic_template=dict(type='str', required=True),
adapter_policy=dict(type='str', default=''),
order=dict(type='str', default='unspecified'),
state=dict(type='str', default='present', choices=['present', 'absent']),
)
iscsi_vnic = dict(
name=dict(type='str', required=True),
overlay_vnic=dict(type='str', default=''),
iscsi_adapter_policy=dict(type='str', default=''),
mac_address=dict(type='str', default='derived'),
vlan_name=dict(type='str', default='default'),
state=dict(type='str', default='present', choices=['present', 'absent']),
)
argument_spec = ucs_argument_spec
argument_spec.update(
org_dn=dict(type='str', default='org-root'),
name=dict(type='str', required=True),
description=dict(type='str', aliases=['descr'], default=''),
vnic_list=dict(type='list', elements='dict', options=vnic),
iscsi_vnic_list=dict(type='list', elements='dict', options=iscsi_vnic),
state=dict(type='str', default='present', choices=['present', 'absent']),
)
module = AnsibleModule(
argument_spec,
supports_check_mode=True,
)
ucs = UCSModule(module)
# UCSModule creation above verifies ucsmsdk is present and exits on failure.
# Additional imports are done below or in called functions.
ucs.result['changed'] = False
props_match = False
# dn is <org_dn>/lan-conn-pol-<name>
dn = module.params['org_dn'] + '/lan-conn-pol-' + module.params['name']
mo = ucs.login_handle.query_dn(dn)
if mo:
if module.params['state'] == 'absent':
# mo must exist but all properties do not have to match
if not module.check_mode:
ucs.login_handle.remove_mo(mo)
ucs.login_handle.commit()
ucs.result['changed'] = True
else: # state == 'present'
props_match = check_lan_connecivity_props(ucs, module, mo, dn)
if module.params['state'] == 'present' and not props_match:
configure_lan_connectivity(ucs, module, dn)
module.exit_json(**ucs.result) module.exit_json(**ucs.result)

View file

@ -15,20 +15,33 @@
- name: LAN Connectivity Policies absent - name: LAN Connectivity Policies absent
ucs_lan_connectivity: &lan_connectivity_absent ucs_lan_connectivity: &lan_connectivity_absent
<<: *login_info <<: *login_info
name: Cntr-LAN-Boot name: Cntr-FC-Boot
state: absent state: absent
# Test present (check_mode) # Test present (check_mode)
- name: LAN Connectivity Policies present (check_mode) - name: LAN Connectivity Policies present (check_mode)
ucs_lan_connectivity: &lan_connectivity_present ucs_lan_connectivity: &lan_connectivity_present
<<: *login_info <<: *login_info
name: Cntr-LAN-Boot name: Cntr-FC-Boot
vnic_list: vnic_list:
- name: Fabric-A - name: eno1
vnic_template: vNIC-Template-A vnic_template: Cntr-Template
- name: Fabric-B
vnic_template: vNIC-Template-B
adapter_policy: Linux adapter_policy: Linux
- name: eno2
vnic_template: Container-NFS-A
adapter_policy: Linux
- name: eno3
vnic_template: Container-NFS-B
adapter_policy: Linux
iscsi_vnic_list:
- name: iSCSIa
overlay_vnic: eno1
iscsi_adapter_policy: default
vlan_name: Container-MGMT-VLAN
- name: iSCSIb
overlay_vnic: eno3
iscsi_adapter_policy: default
vlan_name: Container-TNT-A-NFS
check_mode: yes check_mode: yes
register: cm_lan_connectivity_present register: cm_lan_connectivity_present
@ -56,10 +69,29 @@
- cm_lan_connectivity_present_again.changed == nm_lan_connectivity_present_again.changed == false - cm_lan_connectivity_present_again.changed == nm_lan_connectivity_present_again.changed == false
# Test change (check_mode) # Test change (check_mode)
- name: LAN Connectivity Policies description change (check_mode) - name: LAN Connectivity Policies change (check_mode)
ucs_lan_connectivity: &lan_connectivity_change ucs_lan_connectivity: &lan_connectivity_change
<<: *lan_connectivity_present <<: *login_info
descr: Testing Ansible name: Cntr-FC-Boot
vnic_list:
- name: eno1
vnic_template: Cntr-Template
adapter_policy: Linux
- name: eno2
vnic_template: Container-NFS-A
adapter_policy: Linux
- name: eno3
vnic_template: Container-NFS-B
adapter_policy: default
iscsi_vnic_list:
- name: iSCSIa
overlay_vnic: eno1
iscsi_adapter_policy: default
vlan_name: Container-MGMT-VLAN
- name: iSCSIb
overlay_vnic: eno3
iscsi_adapter_policy: default
vlan_name: Container-TNT-A-NFS
check_mode: yes check_mode: yes
register: cm_lan_connectivity_descr_change register: cm_lan_connectivity_descr_change
@ -86,6 +118,60 @@
- cm_lan_connectivity_descr_change.changed == nm_lan_connectivity_descr_change.changed == true - cm_lan_connectivity_descr_change.changed == nm_lan_connectivity_descr_change.changed == true
- cm_lan_connectivity_descr_change_again.changed == nm_lan_connectivity_descr_change_again.changed == false - cm_lan_connectivity_descr_change_again.changed == nm_lan_connectivity_descr_change_again.changed == false
# Test vnic and iscsi vnic removal
- name: LAN Connectivity Policies vnic removal (check_mode)
ucs_lan_connectivity: &lan_connectivity_vnic_change
<<: *login_info
name: Cntr-FC-Boot
vnic_list:
- name: eno1
vnic_template: Cntr-Template
adapter_policy: Linux
- name: eno2
vnic_template: Container-NFS-A
adapter_policy: Linux
- name: eno3
vnic_template: Container-NFS-B
adapter_policy: default
state: absent
iscsi_vnic_list:
- name: iSCSIa
overlay_vnic: eno1
iscsi_adapter_policy: default
vlan_name: Container-MGMT-VLAN
state: absent
- name: iSCSIb
overlay_vnic: eno3
iscsi_adapter_policy: default
vlan_name: Container-TNT-A-NFS
state: absent
check_mode: yes
register: cm_lan_connectivity_vnic_change
# Change (normal mode)
- name: LAN Connectivity Policies vnic removal (normal mode)
ucs_lan_connectivity: *lan_connectivity_vnic_change
register: nm_lan_connectivity_vnic_change
# Test change again (idempotent)
- name: LAN Connectivity Policies vnic removal again (check_mode)
ucs_lan_connectivity: *lan_connectivity_vnic_change
check_mode: yes
register: cm_lan_connectivity_vnic_change_again
# Change again (normal mode)
- name: LAN Connectivity Policies vnic removal again (normal mode)
ucs_lan_connectivity: *lan_connectivity_vnic_change
register: nm_lan_connectivity_vnic_change_again
# Verfiy change
- name: Verify LAN Connectivity Policies vnic removal results
assert:
that:
- cm_lan_connectivity_vnic_change.changed == nm_lan_connectivity_vnic_change.changed == true
- cm_lan_connectivity_vnic_change_again.changed == nm_lan_connectivity_vnic_change_again.changed == false
# Teardown (clean environment) # Teardown (clean environment)
- name: LAN Connectivity Policies absent (check_mode) - name: LAN Connectivity Policies absent (check_mode)
ucs_lan_connectivity: *lan_connectivity_absent ucs_lan_connectivity: *lan_connectivity_absent