1#!/usr/local/bin/python3.8 2# -*- coding: utf-8 -*- 3 4# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 5 6from __future__ import absolute_import, division, print_function 7__metaclass__ = type 8 9ANSIBLE_METADATA = {'metadata_version': '1.1', 10 'status': ['preview'], 11 'supported_by': 'certified'} 12 13DOCUMENTATION = r''' 14--- 15module: ucs_lan_connectivity 16short_description: Configures LAN Connectivity Policies on Cisco UCS Manager 17description: 18- Configures LAN Connectivity Policies on Cisco UCS Manager. 19extends_documentation_fragment: cisco.ucs.ucs 20options: 21 state: 22 description: 23 - If C(present), will verify LAN Connectivity Policies are present and will create if needed. 24 - If C(absent), will verify LAN Connectivity Policies are absent and will delete if needed. 25 choices: [present, absent] 26 default: present 27 name: 28 description: 29 - The name of the LAN Connectivity Policy. 30 - This name can be between 1 and 16 alphanumeric characters. 31 - "You cannot use spaces or any special characters other than - (hyphen), \"_\" (underscore), : (colon), and . (period)." 32 - You cannot change this name after the policy is created. 33 required: yes 34 description: 35 description: 36 - A description of the LAN Connectivity Policy. 37 - Cisco recommends including information about where and when to use the policy. 38 - Enter up to 256 characters. 39 - "You can use any characters or spaces except the following:" 40 - "` (accent mark), \ (backslash), ^ (carat), \" (double quote), = (equal sign), > (greater than), < (less than), or ' (single quote)." 41 aliases: [ descr ] 42 vnic_list: 43 description: 44 - List of vNICs used by the LAN Connectivity Policy. 45 - vNICs used by the LAN Connectivity Policy must be created from a vNIC template. 46 suboptions: 47 name: 48 description: 49 - The name of the vNIC. 50 required: yes 51 vnic_template: 52 description: 53 - The name of the vNIC template. 54 required: yes 55 adapter_policy: 56 description: 57 - The name of the Ethernet adapter policy. 58 - A user defined policy can be used, or one of the system defined policies. 59 order: 60 description: 61 - String specifying the vNIC assignment order (e.g., '1', '2'). 62 default: 'unspecified' 63 state: 64 description: 65 - If C(present), will verify vnic is configured within policy. 66 If C(absent), will verify vnic is absent from policy. 67 choices: [ present, absent ] 68 default: present 69 version_added: '2.8' 70 iscsi_vnic_list: 71 description: 72 - List of iSCSI vNICs used by the LAN Connectivity Policy. 73 suboptions: 74 name: 75 description: 76 - The name of the iSCSI vNIC. 77 required: yes 78 overlay_vnic: 79 description: 80 - The LAN vNIC associated with this iSCSI vNIC. 81 iscsi_adapter_policy: 82 description: 83 - The iSCSI adapter policy associated with this iSCSI vNIC. 84 mac_address: 85 description: 86 - The MAC address associated with this iSCSI vNIC. 87 - If the MAC address is not set, Cisco UCS Manager uses a derived MAC address. 88 default: derived 89 vlan_name: 90 description: 91 - The VLAN used for the iSCSI vNIC. 92 default: default 93 state: 94 description: 95 - If C(present), will verify iscsi vnic is configured within policy. 96 If C(absent), will verify iscsi vnic is absent from policy. 97 choices: [ present, absent ] 98 default: present 99 version_added: '2.8' 100 org_dn: 101 description: 102 - Org dn (distinguished name) 103 default: org-root 104requirements: 105- ucsmsdk 106author: 107- David Soper (@dsoper2) 108- John McDonough (@movinalot) 109- CiscoUcs (@CiscoUcs) 110version_added: '2.5' 111''' 112 113EXAMPLES = r''' 114- name: Configure LAN Connectivity Policy 115 cisco.ucs.ucs_lan_connectivity: 116 hostname: 172.16.143.150 117 username: admin 118 password: password 119 name: Cntr-FC-Boot 120 vnic_list: 121 - name: eno1 122 vnic_template: Cntr-Template 123 adapter_policy: Linux 124 - name: eno2 125 vnic_template: Container-NFS-A 126 adapter_policy: Linux 127 - name: eno3 128 vnic_template: Container-NFS-B 129 adapter_policy: Linux 130 iscsi_vnic_list: 131 - name: iSCSIa 132 overlay_vnic: eno1 133 iscsi_adapter_policy: default 134 vlan_name: Container-MGMT-VLAN 135 - name: iSCSIb 136 overlay_vnic: eno3 137 iscsi_adapter_policy: default 138 vlan_name: Container-TNT-A-NFS 139 140- name: Remove LAN Connectivity Policy 141 cisco.ucs.ucs_lan_connectivity: 142 hostname: 172.16.143.150 143 username: admin 144 password: password 145 name: Cntr-FC-Boot 146 state: absent 147''' 148 149RETURN = r''' 150# 151''' 152 153from ansible.module_utils.basic import AnsibleModule 154from ansible_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec 155 156 157def configure_lan_connectivity(ucs, module, dn): 158 from ucsmsdk.mometa.vnic.VnicLanConnPolicy import VnicLanConnPolicy 159 from ucsmsdk.mometa.vnic.VnicEther import VnicEther 160 from ucsmsdk.mometa.vnic.VnicIScsiLCP import VnicIScsiLCP 161 from ucsmsdk.mometa.vnic.VnicVlan import VnicVlan 162 163 if not module.check_mode: 164 try: 165 # create if mo does not already exist 166 mo = VnicLanConnPolicy( 167 parent_mo_or_dn=module.params['org_dn'], 168 name=module.params['name'], 169 descr=module.params['description'], 170 ) 171 172 if module.params.get('vnic_list'): 173 for vnic in module.params['vnic_list']: 174 if vnic['state'] == 'absent': 175 child_dn = dn + '/ether-' + vnic['name'] 176 mo_1 = ucs.login_handle.query_dn(child_dn) 177 if mo_1: 178 ucs.login_handle.remove_mo(mo_1) 179 else: # state == 'present' 180 mo_1 = VnicEther( 181 addr='derived', 182 parent_mo_or_dn=mo, 183 name=vnic['name'], 184 adaptor_profile_name=vnic['adapter_policy'], 185 nw_templ_name=vnic['vnic_template'], 186 order=vnic['order'], 187 ) 188 189 if module.params.get('iscsi_vnic_list'): 190 for iscsi_vnic in module.params['iscsi_vnic_list']: 191 if iscsi_vnic['state'] == 'absent': 192 child_dn = dn + '/iscsi-' + iscsi_vnic['name'] 193 mo_1 = ucs.login_handle.query_dn(child_dn) 194 if mo_1: 195 ucs.login_handle.remove_mo(mo_1) 196 else: # state == 'present' 197 mo_1 = VnicIScsiLCP( 198 parent_mo_or_dn=mo, 199 name=iscsi_vnic['name'], 200 adaptor_profile_name=iscsi_vnic['iscsi_adapter_policy'], 201 vnic_name=iscsi_vnic['overlay_vnic'], 202 addr=iscsi_vnic['mac_address'], 203 ) 204 VnicVlan( 205 parent_mo_or_dn=mo_1, 206 vlan_name=iscsi_vnic['vlan_name'], 207 ) 208 209 ucs.login_handle.add_mo(mo, True) 210 ucs.login_handle.commit() 211 except Exception as e: # generic Exception handling because SDK can throw a variety of exceptions 212 ucs.result['msg'] = "setup error: %s " % str(e) 213 module.fail_json(**ucs.result) 214 215 ucs.result['changed'] = True 216 217 218def check_vnic_props(ucs, module, dn): 219 props_match = True 220 221 if module.params.get('vnic_list'): 222 # check vnicEther props 223 for vnic in module.params['vnic_list']: 224 child_dn = dn + '/ether-' + vnic['name'] 225 mo_1 = ucs.login_handle.query_dn(child_dn) 226 if mo_1: 227 if vnic['state'] == 'absent': 228 props_match = False 229 break 230 else: # state == 'present' 231 kwargs = dict(adaptor_profile_name=vnic['adapter_policy']) 232 kwargs['order'] = vnic['order'] 233 kwargs['nw_templ_name'] = vnic['vnic_template'] 234 if not (mo_1.check_prop_match(**kwargs)): 235 props_match = False 236 break 237 else: # mo_1 did not exist 238 if vnic['state'] == 'present': 239 props_match = False 240 break 241 242 return props_match 243 244 245def check_iscsi_vnic_props(ucs, module, dn): 246 props_match = True 247 248 if module.params.get('iscsi_vnic_list'): 249 # check vnicIScsiLCP props 250 for iscsi_vnic in module.params['iscsi_vnic_list']: 251 child_dn = dn + '/iscsi-' + iscsi_vnic['name'] 252 mo_1 = ucs.login_handle.query_dn(child_dn) 253 if mo_1: 254 if iscsi_vnic['state'] == 'absent': 255 props_match = False 256 break 257 else: # state == 'present' 258 kwargs = dict(vnic_name=iscsi_vnic['overlay_vnic']) 259 kwargs['adaptor_profile_name'] = iscsi_vnic['iscsi_adapter_policy'] 260 kwargs['addr'] = iscsi_vnic['mac_address'] 261 if (mo_1.check_prop_match(**kwargs)): 262 # check vlan 263 child_dn = child_dn + '/vlan' 264 mo_2 = ucs.login_handle.query_dn(child_dn) 265 if mo_2: 266 kwargs = dict(vlan_name=iscsi_vnic['vlan_name']) 267 if not (mo_2.check_prop_match(**kwargs)): 268 props_match = False 269 break 270 else: # mo_1 props did not match 271 props_match = False 272 break 273 else: # mo_1 did not exist 274 if iscsi_vnic['state'] == 'present': 275 props_match = False 276 break 277 278 return props_match 279 280 281def check_lan_connecivity_props(ucs, module, mo, dn): 282 props_match = False 283 284 # check top-level mo props 285 kwargs = dict(descr=module.params['description']) 286 if (mo.check_prop_match(**kwargs)): 287 # top-level props match, check next level mo/props 288 # check vnic 1st 289 props_match = check_vnic_props(ucs, module, dn) 290 291 if props_match: 292 props_match = check_iscsi_vnic_props(ucs, module, dn) 293 294 return props_match 295 296 297def main(): 298 vnic = dict( 299 name=dict(type='str', required=True), 300 vnic_template=dict(type='str', required=True), 301 adapter_policy=dict(type='str', default=''), 302 order=dict(type='str', default='unspecified'), 303 state=dict(type='str', default='present', choices=['present', 'absent']), 304 ) 305 iscsi_vnic = dict( 306 name=dict(type='str', required=True), 307 overlay_vnic=dict(type='str', default=''), 308 iscsi_adapter_policy=dict(type='str', default=''), 309 mac_address=dict(type='str', default='derived'), 310 vlan_name=dict(type='str', default='default'), 311 state=dict(type='str', default='present', choices=['present', 'absent']), 312 ) 313 314 argument_spec = ucs_argument_spec 315 argument_spec.update( 316 org_dn=dict(type='str', default='org-root'), 317 name=dict(type='str', required=True), 318 description=dict(type='str', aliases=['descr'], default=''), 319 vnic_list=dict(type='list', elements='dict', options=vnic), 320 iscsi_vnic_list=dict(type='list', elements='dict', options=iscsi_vnic), 321 state=dict(type='str', default='present', choices=['present', 'absent']), 322 ) 323 324 module = AnsibleModule( 325 argument_spec, 326 supports_check_mode=True, 327 ) 328 ucs = UCSModule(module) 329 # UCSModule creation above verifies ucsmsdk is present and exits on failure. 330 # Additional imports are done below or in called functions. 331 332 ucs.result['changed'] = False 333 props_match = False 334 # dn is <org_dn>/lan-conn-pol-<name> 335 dn = module.params['org_dn'] + '/lan-conn-pol-' + module.params['name'] 336 337 mo = ucs.login_handle.query_dn(dn) 338 if mo: 339 if module.params['state'] == 'absent': 340 # mo must exist but all properties do not have to match 341 if not module.check_mode: 342 ucs.login_handle.remove_mo(mo) 343 ucs.login_handle.commit() 344 ucs.result['changed'] = True 345 else: # state == 'present' 346 props_match = check_lan_connecivity_props(ucs, module, mo, dn) 347 348 if module.params['state'] == 'present' and not props_match: 349 configure_lan_connectivity(ucs, module, dn) 350 351 module.exit_json(**ucs.result) 352 353 354if __name__ == '__main__': 355 main() 356