Server IP : 85.214.239.14 / Your IP : 3.144.1.100 Web Server : Apache/2.4.62 (Debian) System : Linux h2886529.stratoserver.net 4.9.0 #1 SMP Tue Jan 9 19:45:01 MSK 2024 x86_64 User : www-data ( 33) PHP Version : 7.4.18 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : OFF | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /lib/python3/dist-packages/ansible_collections/community/vmware/plugins/modules/ |
Upload File : |
#!/usr/bin/python # -*- coding: utf-8 -*- # Copyright: (c) 2015, Joseph Callen <jcallen () csc.com> # Copyright: (c) 2017-18, Ansible Project # Copyright: (c) 2017-18, Abhijeet Kasurde <akasurde@redhat.com> # Copyright: (c) 2018, Christian Kotte <christian.kotte@gmx.de> # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later from __future__ import absolute_import, division, print_function __metaclass__ = type DOCUMENTATION = r''' --- module: vmware_vmkernel short_description: Manages a VMware VMkernel Adapter of an ESXi host. description: - This module can be used to manage the VMKernel adapters / VMKernel network interfaces of an ESXi host. - The module assumes that the host is already configured with the Port Group in case of a vSphere Standard Switch (vSS). - The module assumes that the host is already configured with the Distributed Port Group in case of a vSphere Distributed Switch (vDS). - The module automatically migrates the VMKernel adapter from vSS to vDS or vice versa if present. author: - Joseph Callen (@jcpowermac) - Russell Teague (@mtnbikenc) - Abhijeet Kasurde (@Akasurde) - Christian Kotte (@ckotte) notes: - The option C(device) need to be used with DHCP because otherwise it's not possible to check if a VMkernel device is already present - You can only change from DHCP to static, and vSS to vDS, or vice versa, in one step, without creating a new device, with C(device) specified. - You can only create the VMKernel adapter on a vDS if authenticated to vCenter and not if authenticated to ESXi. options: vswitch_name: description: - The name of the vSwitch where to add the VMKernel interface. - Required parameter only if C(state) is set to C(present). - Optional parameter from version 2.5 and onwards. type: str aliases: ['vswitch'] dvswitch_name: description: - The name of the vSphere Distributed Switch (vDS) where to add the VMKernel interface. - Required parameter only if C(state) is set to C(present). - Optional parameter from version 2.8 and onwards. type: str aliases: ['dvswitch'] portgroup_name: description: - The name of the port group for the VMKernel interface. required: true aliases: ['portgroup'] type: str network: description: - A dictionary of network details. suboptions: type: type: str description: - Type of IP assignment. choices: [ 'static', 'dhcp' ] default: 'static' ip_address: type: str description: - Static IP address. - Required if C(type) is set to C(static). subnet_mask: type: str description: - Static netmask required. - Required if C(type) is set to C(static). default_gateway: type: str description: Default gateway (Override default gateway for this adapter). tcpip_stack: type: str description: - The TCP/IP stack for the VMKernel interface. choices: [ 'default', 'provisioning', 'vmotion', 'vxlan' ] default: 'default' type: dict default: { type: 'static', tcpip_stack: 'default', } mtu: description: - The MTU for the VMKernel interface. - The default value of 1500 is valid from version 2.5 and onwards. default: 1500 type: int device: description: - Search VMkernel adapter by device name. - The parameter is required only in case of C(type) is set to C(dhcp). type: str enable_vsan: description: - Enable VSAN traffic on the VMKernel adapter. - This option is only allowed if the default TCP/IP stack is used. type: bool default: false enable_vmotion: description: - Enable vMotion traffic on the VMKernel adapter. - This option is only allowed if the default TCP/IP stack is used. - You cannot enable vMotion on an additional adapter if you already have an adapter with the vMotion TCP/IP stack configured. type: bool default: false enable_mgmt: description: - Enable Management traffic on the VMKernel adapter. - This option is only allowed if the default TCP/IP stack is used. type: bool default: false enable_ft: description: - Enable Fault Tolerance traffic on the VMKernel adapter. - This option is only allowed if the default TCP/IP stack is used. type: bool default: false enable_provisioning: description: - Enable Provisioning traffic on the VMKernel adapter. - This option is only allowed if the default TCP/IP stack is used. type: bool default: false enable_replication: description: - Enable vSphere Replication traffic on the VMKernel adapter. - This option is only allowed if the default TCP/IP stack is used. type: bool default: false enable_replication_nfc: description: - Enable vSphere Replication NFC traffic on the VMKernel adapter. - This option is only allowed if the default TCP/IP stack is used. type: bool default: false state: description: - If set to C(present), the VMKernel adapter will be created with the given specifications. - If set to C(absent), the VMKernel adapter will be removed. - If set to C(present) and VMKernel adapter exists, the configurations will be updated. choices: [ present, absent ] default: present type: str esxi_hostname: description: - Name of ESXi host to which VMKernel is to be managed. - "From version 2.5 onwards, this parameter is required." required: true type: str extends_documentation_fragment: - community.vmware.vmware.documentation ''' EXAMPLES = r''' - name: Add Management vmkernel port using static network type community.vmware.vmware_vmkernel: hostname: '{{ esxi_hostname }}' username: '{{ esxi_username }}' password: '{{ esxi_password }}' esxi_hostname: '{{ esxi_hostname }}' vswitch_name: vSwitch0 portgroup_name: PG_0001 network: type: 'static' ip_address: 192.168.127.10 subnet_mask: 255.255.255.0 state: present enable_mgmt: true delegate_to: localhost - name: Add Management vmkernel port using DHCP network type community.vmware.vmware_vmkernel: hostname: '{{ esxi_hostname }}' username: '{{ esxi_username }}' password: '{{ esxi_password }}' esxi_hostname: '{{ esxi_hostname }}' vswitch_name: vSwitch0 portgroup_name: PG_0002 state: present network: type: 'dhcp' enable_mgmt: true delegate_to: localhost - name: Change IP allocation from static to dhcp community.vmware.vmware_vmkernel: hostname: '{{ esxi_hostname }}' username: '{{ esxi_username }}' password: '{{ esxi_password }}' esxi_hostname: '{{ esxi_hostname }}' vswitch_name: vSwitch0 portgroup_name: PG_0002 state: present device: vmk1 network: type: 'dhcp' enable_mgmt: true delegate_to: localhost - name: Delete VMkernel port community.vmware.vmware_vmkernel: hostname: '{{ esxi_hostname }}' username: '{{ esxi_username }}' password: '{{ esxi_password }}' esxi_hostname: '{{ esxi_hostname }}' vswitch_name: vSwitch0 portgroup_name: PG_0002 state: absent delegate_to: localhost - name: Add Management vmkernel port to Distributed Switch community.vmware.vmware_vmkernel: hostname: '{{ vcenter_hostname }}' username: '{{ vcenter_username }}' password: '{{ vcenter_password }}' esxi_hostname: '{{ esxi_hostname }}' dvswitch_name: dvSwitch1 portgroup_name: dvPG_0001 network: type: 'static' ip_address: 192.168.127.10 subnet_mask: 255.255.255.0 state: present enable_mgmt: true delegate_to: localhost - name: Add vMotion vmkernel port with vMotion TCP/IP stack community.vmware.vmware_vmkernel: hostname: '{{ vcenter_hostname }}' username: '{{ vcenter_username }}' password: '{{ vcenter_password }}' esxi_hostname: '{{ esxi_hostname }}' dvswitch_name: dvSwitch1 portgroup_name: dvPG_0001 network: type: 'static' ip_address: 192.168.127.10 subnet_mask: 255.255.255.0 tcpip_stack: vmotion state: present delegate_to: localhost ''' RETURN = r''' result: description: metadata about VMKernel name returned: always type: dict sample: { "changed": false, "msg": "VMkernel Adapter already configured properly", "device": "vmk1", "ipv4": "static", "ipv4_gw": "No override", "ipv4_ip": "192.168.1.15", "ipv4_sm": "255.255.255.0", "mtu": 9000, "services": "vMotion", "switch": "vDS" } ''' try: from pyVmomi import vim, vmodl except ImportError: pass from ansible.module_utils.basic import AnsibleModule from ansible_collections.community.vmware.plugins.module_utils.vmware import ( PyVmomi, TaskError, vmware_argument_spec, wait_for_task, find_dvspg_by_name, find_dvs_by_name, get_all_objs ) from ansible.module_utils._text import to_native class PyVmomiHelper(PyVmomi): """Class to manage VMkernel configuration of an ESXi host system""" def __init__(self, module): super(PyVmomiHelper, self).__init__(module) if self.params['network']: self.network_type = self.params['network'].get('type') self.ip_address = self.params['network'].get('ip_address', None) self.subnet_mask = self.params['network'].get('subnet_mask', None) self.default_gateway = self.params['network'].get('default_gateway', None) self.tcpip_stack = self.params['network'].get('tcpip_stack') self.device = self.params['device'] if self.network_type == 'dhcp' and not self.device: module.fail_json(msg="device is a required parameter when network type is set to 'dhcp'") self.mtu = self.params['mtu'] self.enable_vsan = self.params['enable_vsan'] self.enable_vmotion = self.params['enable_vmotion'] self.enable_mgmt = self.params['enable_mgmt'] self.enable_ft = self.params['enable_ft'] self.enable_provisioning = self.params['enable_provisioning'] self.enable_replication = self.params['enable_replication'] self.enable_replication_nfc = self.params['enable_replication_nfc'] self.vswitch_name = self.params['vswitch_name'] self.vds_name = self.params['dvswitch_name'] self.port_group_name = self.params['portgroup_name'] self.esxi_host_name = self.params['esxi_hostname'] hosts = self.get_all_host_objs(esxi_host_name=self.esxi_host_name) if hosts: self.esxi_host_obj = hosts[0] else: self.module.fail_json( msg="Failed to get details of ESXi server. Please specify esxi_hostname." ) if self.network_type == 'static': if self.module.params['state'] == 'absent': pass elif not self.ip_address: module.fail_json(msg="ip_address is a required parameter when network type is set to 'static'") elif not self.subnet_mask: module.fail_json(msg="subnet_mask is a required parameter when network type is set to 'static'") # find Port Group if self.vswitch_name: self.port_group_obj = self.get_port_group_by_name( host_system=self.esxi_host_obj, portgroup_name=self.port_group_name, vswitch_name=self.vswitch_name ) if not self.port_group_obj: module.fail_json(msg="Portgroup '%s' not found on vSS '%s'" % (self.port_group_name, self.vswitch_name)) elif self.vds_name: self.dv_switch_obj = find_dvs_by_name(self.content, self.vds_name) if not self.dv_switch_obj: module.fail_json(msg="vDS '%s' not found" % self.vds_name) self.port_group_obj = find_dvspg_by_name(self.dv_switch_obj, self.port_group_name) if not self.port_group_obj: module.fail_json(msg="Portgroup '%s' not found on vDS '%s'" % (self.port_group_name, self.vds_name)) # find VMkernel Adapter if self.device: self.vnic = self.get_vmkernel_by_device(device_name=self.device) else: # config change (e.g. DHCP to static, or vice versa); doesn't work with virtual port change self.vnic = self.get_vmkernel_by_portgroup_new(port_group_name=self.port_group_name) if not self.vnic and self.network_type == 'static': # vDS to vSS or vSS to vSS (static IP) self.vnic = self.get_vmkernel_by_ip(ip_address=self.ip_address) def get_port_group_by_name(self, host_system, portgroup_name, vswitch_name): """ Get specific port group by given name Args: host_system: Name of Host System portgroup_name: Name of Port Group vswitch_name: Name of the vSwitch Returns: List of port groups by given specifications """ portgroups = self.get_all_port_groups_by_host(host_system=host_system) for portgroup in portgroups: if portgroup.spec.vswitchName == vswitch_name and portgroup.spec.name == portgroup_name: return portgroup return None def ensure(self): """ Manage internal VMKernel management Returns: NA """ host_vmk_states = { 'absent': { 'present': self.host_vmk_delete, 'absent': self.host_vmk_unchange, }, 'present': { 'present': self.host_vmk_update, 'absent': self.host_vmk_create, } } try: host_vmk_states[self.module.params['state']][self.check_state()]() except vmodl.RuntimeFault as runtime_fault: self.module.fail_json(msg=to_native(runtime_fault.msg)) except vmodl.MethodFault as method_fault: self.module.fail_json(msg=to_native(method_fault.msg)) def get_vmkernel_by_portgroup_new(self, port_group_name=None): """ Check if vmkernel available or not Args: port_group_name: name of port group Returns: vmkernel managed object if vmkernel found, false if not """ for vnic in self.esxi_host_obj.config.network.vnic: # check if it's a vSS Port Group if vnic.spec.portgroup == port_group_name: return vnic # check if it's a vDS Port Group try: if vnic.spec.distributedVirtualPort.portgroupKey == self.port_group_obj.key: return vnic except AttributeError: pass return False def get_vmkernel_by_ip(self, ip_address): """ Check if vmkernel available or not Args: ip_address: IP address of vmkernel device Returns: vmkernel managed object if vmkernel found, false if not """ for vnic in self.esxi_host_obj.config.network.vnic: if vnic.spec.ip.ipAddress == ip_address: return vnic return None def get_vmkernel_by_device(self, device_name): """ Check if vmkernel available or not Args: device_name: name of vmkernel device Returns: vmkernel managed object if vmkernel found, false if not """ for vnic in self.esxi_host_obj.config.network.vnic: if vnic.device == device_name: return vnic return None def check_state(self): """ Check internal state management Returns: Present if found and absent if not found """ return 'present' if self.vnic else 'absent' def host_vmk_delete(self): """ Delete VMKernel Returns: NA """ results = dict(changed=False, msg='') vmk_device = self.vnic.device try: if self.module.check_mode: results['msg'] = "VMkernel Adapter would be deleted" else: self.esxi_host_obj.configManager.networkSystem.RemoveVirtualNic(vmk_device) results['msg'] = "VMkernel Adapter deleted" results['changed'] = True results['device'] = vmk_device except vim.fault.NotFound as not_found: self.module.fail_json( msg="Failed to find vmk to delete due to %s" % to_native(not_found.msg) ) except vim.fault.HostConfigFault as host_config_fault: self.module.fail_json( msg="Failed to delete vmk due host config issues : %s" % to_native(host_config_fault.msg) ) self.module.exit_json(**results) def host_vmk_unchange(self): """ Denote no change in VMKernel Returns: NA """ self.module.exit_json(changed=False) def host_vmk_update(self): """ Update VMKernel with given parameters Returns: NA """ changed = changed_settings = changed_vds = changed_services = \ changed_service_vmotion = changed_service_mgmt = changed_service_ft = \ changed_service_vsan = changed_service_prov = changed_service_rep = changed_service_rep_nfc = False changed_list = [] results = dict(changed=False, msg='') results['tcpip_stack'] = self.tcpip_stack net_stack_instance_key = self.get_api_net_stack_instance(self.tcpip_stack) if self.vnic.spec.netStackInstanceKey != net_stack_instance_key: self.module.fail_json(msg="The TCP/IP stack cannot be changed on an existing VMkernel adapter!") # Check MTU results['mtu'] = self.mtu if self.vnic.spec.mtu != self.mtu: changed_settings = True changed_list.append("MTU") results['mtu_previous'] = self.vnic.spec.mtu # Check IPv4 settings results['ipv4'] = self.network_type results['ipv4_ip'] = self.ip_address results['ipv4_sm'] = self.subnet_mask if self.default_gateway: results['ipv4_gw'] = self.default_gateway else: results['ipv4_gw'] = "No override" if self.vnic.spec.ip.dhcp: if self.network_type == 'static': changed_settings = True changed_list.append("IPv4 settings") results['ipv4_previous'] = "DHCP" if not self.vnic.spec.ip.dhcp: if self.network_type == 'dhcp': changed_settings = True changed_list.append("IPv4 settings") results['ipv4_previous'] = "static" elif self.network_type == 'static': if self.ip_address != self.vnic.spec.ip.ipAddress: changed_settings = True changed_list.append("IP") results['ipv4_ip_previous'] = self.vnic.spec.ip.ipAddress if self.subnet_mask != self.vnic.spec.ip.subnetMask: changed_settings = True changed_list.append("SM") results['ipv4_sm_previous'] = self.vnic.spec.ip.subnetMask if self.default_gateway: try: if self.default_gateway != self.vnic.spec.ipRouteSpec.ipRouteConfig.defaultGateway: changed_settings = True changed_list.append("GW override") results['ipv4_gw_previous'] = self.vnic.spec.ipRouteSpec.ipRouteConfig.defaultGateway except AttributeError: changed_settings = True changed_list.append("GW override") results['ipv4_gw_previous'] = "No override" else: try: if self.vnic.spec.ipRouteSpec.ipRouteConfig.defaultGateway: changed_settings = True changed_list.append("GW override") results['ipv4_gw_previous'] = self.vnic.spec.ipRouteSpec.ipRouteConfig.defaultGateway except AttributeError: pass # Check virtual port (vSS or vDS) results['portgroup'] = self.port_group_name dvs_uuid = None if self.vswitch_name: results['switch'] = self.vswitch_name try: if self.vnic.spec.distributedVirtualPort.switchUuid: changed_vds = True changed_list.append("Virtual Port") dvs_uuid = self.vnic.spec.distributedVirtualPort.switchUuid except AttributeError: pass if changed_vds: results['switch_previous'] = self.find_dvs_by_uuid(dvs_uuid) self.dv_switch_obj = find_dvs_by_name(self.content, results['switch_previous']) results['portgroup_previous'] = self.find_dvspg_by_key( self.dv_switch_obj, self.vnic.spec.distributedVirtualPort.portgroupKey ) elif self.vds_name: results['switch'] = self.vds_name try: if self.vnic.spec.distributedVirtualPort.switchUuid != self.dv_switch_obj.uuid: changed_vds = True changed_list.append("Virtual Port") dvs_uuid = self.vnic.spec.distributedVirtualPort.switchUuid except AttributeError: changed_vds = True changed_list.append("Virtual Port") if changed_vds: results['switch_previous'] = self.find_dvs_by_uuid(dvs_uuid) results['portgroup_previous'] = self.vnic.spec.portgroup portgroups = self.get_all_port_groups_by_host(host_system=self.esxi_host_obj) for portgroup in portgroups: if portgroup.spec.name == self.vnic.spec.portgroup: results['switch_previous'] = portgroup.spec.vswitchName results['services'] = self.create_enabled_services_string() # Check configuration of service types (only if default TCP/IP stack is used) if self.vnic.spec.netStackInstanceKey == 'defaultTcpipStack': service_type_vmks = self.get_all_vmks_by_service_type() if (self.enable_vmotion and self.vnic.device not in service_type_vmks['vmotion']) or \ (not self.enable_vmotion and self.vnic.device in service_type_vmks['vmotion']): changed_services = changed_service_vmotion = True if (self.enable_mgmt and self.vnic.device not in service_type_vmks['management']) or \ (not self.enable_mgmt and self.vnic.device in service_type_vmks['management']): changed_services = changed_service_mgmt = True if (self.enable_ft and self.vnic.device not in service_type_vmks['faultToleranceLogging']) or \ (not self.enable_ft and self.vnic.device in service_type_vmks['faultToleranceLogging']): changed_services = changed_service_ft = True if (self.enable_vsan and self.vnic.device not in service_type_vmks['vsan']) or \ (not self.enable_vsan and self.vnic.device in service_type_vmks['vsan']): changed_services = changed_service_vsan = True if (self.enable_provisioning and self.vnic.device not in service_type_vmks['vSphereProvisioning']) or \ (not self.enable_provisioning and self.vnic.device in service_type_vmks['vSphereProvisioning']): changed_services = changed_service_prov = True if (self.enable_replication and self.vnic.device not in service_type_vmks['vSphereReplication']) or \ (not self.enable_replication and self.vnic.device in service_type_vmks['vSphereReplication']): changed_services = changed_service_rep = True if (self.enable_replication_nfc and self.vnic.device not in service_type_vmks['vSphereReplicationNFC']) or \ (not self.enable_replication_nfc and self.vnic.device in service_type_vmks['vSphereReplicationNFC']): changed_services = changed_service_rep_nfc = True if changed_services: changed_list.append("services") if changed_settings or changed_vds or changed_services: changed = True if self.module.check_mode: changed_suffix = ' would be updated' else: changed_suffix = ' updated' if len(changed_list) > 2: message = ', '.join(changed_list[:-1]) + ', and ' + str(changed_list[-1]) elif len(changed_list) == 2: message = ' and '.join(changed_list) elif len(changed_list) == 1: message = changed_list[0] message = "VMkernel Adapter " + message + changed_suffix if changed_settings or changed_vds: vnic_config = vim.host.VirtualNic.Specification() ip_spec = vim.host.IpConfig() if self.network_type == 'dhcp': ip_spec.dhcp = True else: ip_spec.dhcp = False ip_spec.ipAddress = self.ip_address ip_spec.subnetMask = self.subnet_mask if self.default_gateway: vnic_config.ipRouteSpec = vim.host.VirtualNic.IpRouteSpec() vnic_config.ipRouteSpec.ipRouteConfig = vim.host.IpRouteConfig() vnic_config.ipRouteSpec.ipRouteConfig.defaultGateway = self.default_gateway else: vnic_config.ipRouteSpec = vim.host.VirtualNic.IpRouteSpec() vnic_config.ipRouteSpec.ipRouteConfig = vim.host.IpRouteConfig() vnic_config.ip = ip_spec vnic_config.mtu = self.mtu if changed_vds: if self.vswitch_name: vnic_config.portgroup = self.port_group_name elif self.vds_name: vnic_config.distributedVirtualPort = vim.dvs.PortConnection() vnic_config.distributedVirtualPort.switchUuid = self.dv_switch_obj.uuid vnic_config.distributedVirtualPort.portgroupKey = self.port_group_obj.key try: if not self.module.check_mode: self.esxi_host_obj.configManager.networkSystem.UpdateVirtualNic(self.vnic.device, vnic_config) except vim.fault.NotFound as not_found: self.module.fail_json( msg="Failed to update vmk as virtual network adapter cannot be found %s" % to_native(not_found.msg) ) except vim.fault.HostConfigFault as host_config_fault: self.module.fail_json( msg="Failed to update vmk due to host config issues : %s" % to_native(host_config_fault.msg) ) except vim.fault.InvalidState as invalid_state: self.module.fail_json( msg="Failed to update vmk as ipv6 address is specified in an ipv4 only system : %s" % to_native(invalid_state.msg) ) except vmodl.fault.InvalidArgument as invalid_arg: self.module.fail_json( msg="Failed to update vmk as IP address or Subnet Mask in the IP configuration" "are invalid or PortGroup does not exist : %s" % to_native(invalid_arg.msg) ) if changed_services: changed_list.append("Services") services_previous = [] vnic_manager = self.esxi_host_obj.configManager.virtualNicManager if changed_service_mgmt: if self.vnic.device in service_type_vmks['management']: services_previous.append('Mgmt') operation = 'select' if self.enable_mgmt else 'deselect' self.set_service_type( vnic_manager=vnic_manager, vmk=self.vnic, service_type='management', operation=operation ) if changed_service_vmotion: if self.vnic.device in service_type_vmks['vmotion']: services_previous.append('vMotion') operation = 'select' if self.enable_vmotion else 'deselect' self.set_service_type( vnic_manager=vnic_manager, vmk=self.vnic, service_type='vmotion', operation=operation ) if changed_service_ft: if self.vnic.device in service_type_vmks['faultToleranceLogging']: services_previous.append('FT') operation = 'select' if self.enable_ft else 'deselect' self.set_service_type( vnic_manager=vnic_manager, vmk=self.vnic, service_type='faultToleranceLogging', operation=operation ) if changed_service_prov: if self.vnic.device in service_type_vmks['vSphereProvisioning']: services_previous.append('Prov') operation = 'select' if self.enable_provisioning else 'deselect' self.set_service_type( vnic_manager=vnic_manager, vmk=self.vnic, service_type='vSphereProvisioning', operation=operation ) if changed_service_rep: if self.vnic.device in service_type_vmks['vSphereReplication']: services_previous.append('Repl') operation = 'select' if self.enable_replication else 'deselect' self.set_service_type( vnic_manager=vnic_manager, vmk=self.vnic, service_type='vSphereReplication', operation=operation ) if changed_service_rep_nfc: if self.vnic.device in service_type_vmks['vSphereReplicationNFC']: services_previous.append('Repl_NFC') operation = 'select' if self.enable_replication_nfc else 'deselect' self.set_service_type( vnic_manager=vnic_manager, vmk=self.vnic, service_type='vSphereReplicationNFC', operation=operation ) if changed_service_vsan: if self.vnic.device in service_type_vmks['vsan']: services_previous.append('VSAN') results['vsan'] = self.set_vsan_service_type(self.enable_vsan) results['services_previous'] = ', '.join(services_previous) else: message = "VMkernel Adapter already configured properly" results['changed'] = changed results['msg'] = message results['device'] = self.vnic.device self.module.exit_json(**results) def find_dvs_by_uuid(self, uuid): """ Find DVS by UUID Returns: DVS name """ dvs_list = get_all_objs(self.content, [vim.DistributedVirtualSwitch]) for dvs in dvs_list: if dvs.uuid == uuid: return dvs.summary.name return None def find_dvspg_by_key(self, dv_switch, portgroup_key): """ Find dvPortgroup by key Returns: dvPortgroup name """ portgroups = dv_switch.portgroup for portgroup in portgroups: if portgroup.key == portgroup_key: return portgroup.name return None def set_vsan_service_type(self, enable_vsan): """ Set VSAN service type Returns: result of UpdateVsan_Task """ result = None vsan_system = self.esxi_host_obj.configManager.vsanSystem vsan_system_config = vsan_system.config vsan_config = vim.vsan.host.ConfigInfo() vsan_config.networkInfo = vsan_system_config.networkInfo current_vsan_vnics = [portConfig.device for portConfig in vsan_system_config.networkInfo.port] changed = False result = "%s NIC %s (currently enabled NICs: %s) : " % ("Enable" if enable_vsan else "Disable", self.vnic.device, current_vsan_vnics) if not enable_vsan: if self.vnic.device in current_vsan_vnics: vsan_config.networkInfo.port = list(filter(lambda portConfig: portConfig.device != self.vnic.device, vsan_config.networkInfo.port)) changed = True else: if self.vnic.device not in current_vsan_vnics: vsan_port_config = vim.vsan.host.ConfigInfo.NetworkInfo.PortConfig() vsan_port_config.device = self.vnic.device if vsan_config.networkInfo is None: vsan_config.networkInfo = vim.vsan.host.ConfigInfo.NetworkInfo() vsan_config.networkInfo.port = [vsan_port_config] else: vsan_config.networkInfo.port.append(vsan_port_config) changed = True if not self.module.check_mode and changed: try: vsan_task = vsan_system.UpdateVsan_Task(vsan_config) task_result = wait_for_task(vsan_task) if task_result[0]: result += "Success" else: result += "Failed" except TaskError as task_err: self.module.fail_json( msg="Failed to set service type to vsan for %s : %s" % (self.vnic.device, to_native(task_err)) ) if self.module.check_mode: result += "Dry-run" return result def host_vmk_create(self): """ Create VMKernel Returns: NA """ results = dict(changed=False, message='') if self.vswitch_name: results['switch'] = self.vswitch_name elif self.vds_name: results['switch'] = self.vds_name results['portgroup'] = self.port_group_name vnic_config = vim.host.VirtualNic.Specification() ip_spec = vim.host.IpConfig() results['ipv4'] = self.network_type if self.network_type == 'dhcp': ip_spec.dhcp = True else: ip_spec.dhcp = False results['ipv4_ip'] = self.ip_address results['ipv4_sm'] = self.subnet_mask ip_spec.ipAddress = self.ip_address ip_spec.subnetMask = self.subnet_mask if self.default_gateway: vnic_config.ipRouteSpec = vim.host.VirtualNic.IpRouteSpec() vnic_config.ipRouteSpec.ipRouteConfig = vim.host.IpRouteConfig() vnic_config.ipRouteSpec.ipRouteConfig.defaultGateway = self.default_gateway vnic_config.ip = ip_spec results['mtu'] = self.mtu vnic_config.mtu = self.mtu results['tcpip_stack'] = self.tcpip_stack vnic_config.netStackInstanceKey = self.get_api_net_stack_instance(self.tcpip_stack) vmk_device = None try: if self.module.check_mode: results['msg'] = "VMkernel Adapter would be created" else: if self.vswitch_name: vmk_device = self.esxi_host_obj.configManager.networkSystem.AddVirtualNic( self.port_group_name, vnic_config ) elif self.vds_name: vnic_config.distributedVirtualPort = vim.dvs.PortConnection() vnic_config.distributedVirtualPort.switchUuid = self.dv_switch_obj.uuid vnic_config.distributedVirtualPort.portgroupKey = self.port_group_obj.key vmk_device = self.esxi_host_obj.configManager.networkSystem.AddVirtualNic(portgroup="", nic=vnic_config) results['msg'] = "VMkernel Adapter created" results['changed'] = True results['device'] = vmk_device if self.network_type != 'dhcp': if self.default_gateway: results['ipv4_gw'] = self.default_gateway else: results['ipv4_gw'] = "No override" results['services'] = self.create_enabled_services_string() except vim.fault.AlreadyExists as already_exists: self.module.fail_json( msg="Failed to add vmk as portgroup already has a virtual network adapter %s" % to_native(already_exists.msg) ) except vim.fault.HostConfigFault as host_config_fault: self.module.fail_json( msg="Failed to add vmk due to host config issues : %s" % to_native(host_config_fault.msg) ) except vim.fault.InvalidState as invalid_state: self.module.fail_json( msg="Failed to add vmk as ipv6 address is specified in an ipv4 only system : %s" % to_native(invalid_state.msg) ) except vmodl.fault.InvalidArgument as invalid_arg: self.module.fail_json( msg="Failed to add vmk as IP address or Subnet Mask in the IP configuration " "are invalid or PortGroup does not exist : %s" % to_native(invalid_arg.msg) ) # do service type configuration if self.tcpip_stack == 'default' and not all( option is False for option in [self.enable_vsan, self.enable_vmotion, self.enable_mgmt, self.enable_ft, self.enable_provisioning, self.enable_replication, self.enable_replication_nfc]): self.vnic = self.get_vmkernel_by_device(device_name=vmk_device) # VSAN if self.enable_vsan: results['vsan'] = self.set_vsan_service_type(self.enable_vsan) # Other service type host_vnic_manager = self.esxi_host_obj.configManager.virtualNicManager if self.enable_vmotion: self.set_service_type(host_vnic_manager, self.vnic, 'vmotion') if self.enable_mgmt: self.set_service_type(host_vnic_manager, self.vnic, 'management') if self.enable_ft: self.set_service_type(host_vnic_manager, self.vnic, 'faultToleranceLogging') if self.enable_provisioning: self.set_service_type(host_vnic_manager, self.vnic, 'vSphereProvisioning') if self.enable_replication: self.set_service_type(host_vnic_manager, self.vnic, 'vSphereReplication') if self.enable_replication_nfc: self.set_service_type(host_vnic_manager, self.vnic, 'vSphereReplicationNFC') self.module.exit_json(**results) def set_service_type(self, vnic_manager, vmk, service_type, operation='select'): """ Set service type to given VMKernel Args: vnic_manager: Virtual NIC manager object vmk: VMkernel managed object service_type: Name of service type operation: Select to select service type, deselect to deselect service type """ try: if operation == 'select': if not self.module.check_mode: vnic_manager.SelectVnicForNicType(service_type, vmk.device) elif operation == 'deselect': if not self.module.check_mode: vnic_manager.DeselectVnicForNicType(service_type, vmk.device) except vmodl.fault.InvalidArgument as invalid_arg: self.module.fail_json( msg="Failed to %s VMK service type '%s' on '%s' due to : %s" % (operation, service_type, vmk.device, to_native(invalid_arg.msg)) ) def get_all_vmks_by_service_type(self): """ Return information about service types and VMKernel Returns: Dictionary of service type as key and VMKernel list as value """ service_type_vmk = dict( vmotion=[], vsan=[], management=[], faultToleranceLogging=[], vSphereProvisioning=[], vSphereReplication=[], vSphereReplicationNFC=[], ) for service_type in list(service_type_vmk): vmks_list = self.query_service_type_for_vmks(service_type) service_type_vmk[service_type] = vmks_list return service_type_vmk def query_service_type_for_vmks(self, service_type): """ Return list of VMKernels Args: service_type: Name of service type Returns: List of VMKernel which belongs to that service type """ vmks_list = [] query = None try: query = self.esxi_host_obj.configManager.virtualNicManager.QueryNetConfig(service_type) except vim.fault.HostConfigFault as config_fault: self.module.fail_json( msg="Failed to get all VMKs for service type %s due to host config fault : %s" % (service_type, to_native(config_fault.msg)) ) except vmodl.fault.InvalidArgument as invalid_argument: self.module.fail_json( msg="Failed to get all VMKs for service type %s due to invalid arguments : %s" % (service_type, to_native(invalid_argument.msg)) ) if not query.selectedVnic: return vmks_list vnics_with_service_type = [vnic.device for vnic in query.candidateVnic if vnic.key in query.selectedVnic] return vnics_with_service_type def create_enabled_services_string(self): """Create services list""" services = [] if self.enable_mgmt: services.append('Mgmt') if self.enable_vmotion: services.append('vMotion') if self.enable_ft: services.append('FT') if self.enable_vsan: services.append('VSAN') if self.enable_provisioning: services.append('Prov') if self.enable_replication: services.append('Repl') if self.enable_replication_nfc: services.append('Repl_NFC') return ', '.join(services) @staticmethod def get_api_net_stack_instance(tcpip_stack): """Get TCP/IP stack instance name or key""" net_stack_instance = None if tcpip_stack == 'default': net_stack_instance = 'defaultTcpipStack' elif tcpip_stack == 'provisioning': net_stack_instance = 'vSphereProvisioning' # vmotion and vxlan stay the same elif tcpip_stack == 'vmotion': net_stack_instance = 'vmotion' elif tcpip_stack == 'vxlan': net_stack_instance = 'vxlan' elif tcpip_stack == 'defaultTcpipStack': net_stack_instance = 'default' elif tcpip_stack == 'vSphereProvisioning': net_stack_instance = 'provisioning' return net_stack_instance def main(): """Main""" argument_spec = vmware_argument_spec() argument_spec.update(dict( esxi_hostname=dict(required=True, type='str'), portgroup_name=dict(required=True, type='str', aliases=['portgroup']), mtu=dict(required=False, type='int', default=1500), device=dict(type='str'), enable_vsan=dict(required=False, type='bool', default=False), enable_vmotion=dict(required=False, type='bool', default=False), enable_mgmt=dict(required=False, type='bool', default=False), enable_ft=dict(required=False, type='bool', default=False), enable_provisioning=dict(type='bool', default=False), enable_replication=dict(type='bool', default=False), enable_replication_nfc=dict(type='bool', default=False), vswitch_name=dict(required=False, type='str', aliases=['vswitch']), dvswitch_name=dict(required=False, type='str', aliases=['dvswitch']), network=dict( type='dict', options=dict( type=dict(type='str', default='static', choices=['static', 'dhcp']), ip_address=dict(type='str'), subnet_mask=dict(type='str'), default_gateway=dict(type='str'), tcpip_stack=dict(type='str', default='default', choices=['default', 'provisioning', 'vmotion', 'vxlan']), ), default=dict( type='static', tcpip_stack='default', ), ), state=dict( type='str', default='present', choices=['absent', 'present'] ), )) module = AnsibleModule(argument_spec=argument_spec, mutually_exclusive=[ ['vswitch_name', 'dvswitch_name'], ], required_one_of=[ ['vswitch_name', 'dvswitch_name'], ['portgroup_name', 'device'], ], required_if=[ ['state', 'present', ['portgroup_name']], ['state', 'absent', ['device']] ], supports_check_mode=True) pyv = PyVmomiHelper(module) pyv.ensure() if __name__ == '__main__': main()