Source code for saltext.vmware.modules.dvswitch

# Copyright 2021 VMware, Inc.
# SPDX-License-Identifier: Apache-2.0
import logging

import salt.exceptions
import saltext.vmware.utils.common as utils_common
import saltext.vmware.utils.datacenter as utils_datacenter
import saltext.vmware.utils.esxi as utils_esxi
import saltext.vmware.utils.vmware as utils_vmware
from saltext.vmware.utils.connect import get_service_instance

log = logging.getLogger(__name__)

try:
    from pyVmomi import vim, vmodl

    HAS_PYVMOMI = True
except ImportError:
    HAS_PYVMOMI = False

__virtualname__ = "vmware_dvswitch"
__proxyenabled__ = ["vmware_dvswitch"]


def __virtual__():
    if not HAS_PYVMOMI:
        return False, "Unable to import pyVmomi module."
    return __virtualname__


def _get_switch_config_spec(service_instance, datacenter_name, switch_name):
    dc_ref = switch_ref = config_spec = None
    dc_ref = utils_datacenter.get_datacenter(service_instance, datacenter_name)
    switch_refs = utils_vmware.get_dvss(dc_ref=dc_ref, dvs_names=[switch_name])
    if switch_refs:
        switch_ref = switch_refs[0]
        dvs_props = utils_common.get_properties_of_managed_object(
            switch_ref, ["config", "capability"]
        )
        config_spec = vim.dvs.VmwareDistributedVirtualSwitch.ConfigSpec()
        # Copy all of the properties in the config of the of the DVS to a
        # DvsConfigSpec
        skipped_properties = ["host"]
        for prop in config_spec.__dict__.keys():
            if prop in skipped_properties:
                continue
            if hasattr(dvs_props["config"], prop):
                setattr(config_spec, prop, getattr(dvs_props["config"], prop))
    return dc_ref, switch_ref, config_spec


[docs]def configure( datacenter_name, switch_name, uplink_count=None, uplink_prefix="Uplink ", switch_version=None, switch_description=None, mtu=None, discovery_protocol=None, discovery_operation=None, multicast_filtering_mode=None, contact_name=None, contact_description=None, network_forged_transmits=None, network_mac_changes=None, network_promiscuous=None, health_check_teaming_failover=None, health_teaming_failover_interval=None, health_vlan_mtu=None, health_vlan_mtu_interval=None, service_instance=None, ): """ Creates a new distributed vSwitch or updates an existing vSwitch. switch_name Name of the distributed vSwitch to create or update. uplink_count Count of uplink per ESXi per host. Optional. uplink_prefix The prefix to be used for uplinks. Optional. Default: "Uplink ". switch_version The version of the distributed vSwitch to create or update. Optional. switch_description Description of the distributed vSwitch. Optional. Default: None. mtu Maximum transmission unit for the switch. Optional. discovery_protocol Link discovery protocol between Cisco and Link Layer discovery. Optional. Valid values: "cdp", "lldp", "disabled". discovery_operation Discovery operation for the switch. Optional. Valid values: "both", "advertise", "listen". multicast_filtering_mode Multicast filtering mode for the switch. Optional. Valid values: "basic", "snooping". contact_name Administrator contact name. Optional. Default: "". contact_description Administrator contact information. Optional. Default: "". network_forged_transmits Allow forged transmits. Type: Boolean. Optional. Valid values: "True", "False". network_mac_changes Allow mac changes. Type: Boolean. Optional. Valid values: "True", "False". network_promiscuous Allow promiscuous mode. Type: Boolean. Optional. Valid values: "True", "False". health_check_teaming_failover Enable teaming and failover health check. Type: Boolean. Optional. Valid values: "True", "False". health_teaming_failover_interval Teaming and failover health check interval in minutes. Optional. health_vlan_mtu Enable VLAN and MTU health check. Type: Boolean. Optional. Valid values: "True", "False". health_vlan_mtu_interval VLAN and MTU health check interval in minutes. Optional. service_instance Use this vCenter service connection instance instead of creating a new one. Optional. .. code-block:: bash salt '*' vmware_dvswitch.configure dvs1 """ if not service_instance: service_instance = get_service_instance(opts=__opts__, pillar=__pillar__) try: health_spec = product_spec = spec = None dc_ref, switch_ref, config_spec = _get_switch_config_spec( service_instance=service_instance, datacenter_name=datacenter_name, switch_name=switch_name, ) if not switch_ref: spec = vim.DistributedVirtualSwitch.CreateSpec() spec.configSpec = vim.dvs.VmwareDistributedVirtualSwitch.ConfigSpec() config_spec = spec.configSpec config_spec.name = switch_name if mtu: config_spec.maxMtu = mtu if uplink_count: config_spec.uplinkPortPolicy = vim.DistributedVirtualSwitch.NameArrayUplinkPortPolicy() for i in range(uplink_count): config_spec.uplinkPortPolicy.uplinkPortName.append( "{}{}".format(uplink_prefix, i + 1) ) if switch_version: product_spec = vim.dvs.ProductSpec() product_spec.version = switch_version if spec: spec.productInfo = product_spec if switch_description: config_spec.description = switch_description if contact_name or contact_description: contact_info_spec = vim.DistributedVirtualSwitch.ContactInfo() contact_info_spec.contact = contact_description contact_info_spec.name = contact_name if switch_ref: contact_info_spec.contact = contact_description or switch_ref.config.contact.contact contact_info_spec.name = contact_name or switch_ref.config.contact.name config_spec.contact = contact_info_spec if discovery_operation or discovery_protocol: ldp_config_spec = vim.host.LinkDiscoveryProtocolConfig() ldp_config_spec.operation = discovery_operation ldp_config_spec.protocol = discovery_protocol if switch_ref: ldp_config_spec.protocol = ( discovery_protocol or switch_ref.config.linkDiscoveryProtocolConfig.protocol ) ldp_config_spec.operation = ( discovery_operation or switch_ref.config.linkDiscoveryProtocolConfig.operation ) if discovery_protocol == "disabled": ldp_config_spec.protocol = "cdp" ldp_config_spec.operation = "none" config_spec.linkDiscoveryProtocolConfig = ldp_config_spec if multicast_filtering_mode: if multicast_filtering_mode == "basic": config_spec.multicastFilteringMode = "legacyFiltering" else: config_spec.multicastFilteringMode = multicast_filtering_mode if not switch_ref: utils_vmware.create_dvs(dc_ref=dc_ref, dvs_name=switch_name, dvs_create_spec=spec) if ( network_promiscuous is not None or network_mac_changes is not None or network_forged_transmits is not None ): policy = vim.dvs.VmwareDistributedVirtualSwitch.SecurityPolicy() if not switch_ref: dc_ref, switch_ref, config_spec = _get_switch_config_spec( service_instance=service_instance, datacenter_name=datacenter_name, switch_name=switch_name, ) if network_promiscuous is None: network_promiscuous = ( switch_ref.config.defaultPortConfig.securityPolicy.allowPromiscuous.value ) if network_mac_changes is None: network_mac_changes = ( switch_ref.config.defaultPortConfig.securityPolicy.macChanges.value ) if network_forged_transmits is None: network_forged_transmits = ( switch_ref.config.defaultPortConfig.securityPolicy.forgedTransmits.value ) if network_promiscuous is not None: policy.allowPromiscuous = vim.BoolPolicy(value=network_promiscuous) if network_mac_changes is not None: policy.macChanges = vim.BoolPolicy(value=network_mac_changes) if network_forged_transmits is not None: policy.forgedTransmits = vim.BoolPolicy(value=network_forged_transmits) config_spec.defaultPortConfig.securityPolicy = policy if ( health_check_teaming_failover is not None or health_teaming_failover_interval is not None or health_vlan_mtu is not None or health_vlan_mtu_interval is not None ): if not switch_ref: dc_ref, switch_ref, config_spec = _get_switch_config_spec( service_instance=service_instance, datacenter_name=datacenter_name, switch_name=switch_name, ) health_spec = vim.DistributedVirtualSwitch.HealthCheckConfig.Array() for config in switch_ref.config.healthCheckConfig: if isinstance( config, vim.dvs.VmwareDistributedVirtualSwitch.VlanMtuHealthCheckConfig ): if health_vlan_mtu is not None: config.enable = health_vlan_mtu if health_vlan_mtu_interval is not None: config.interval = health_vlan_mtu_interval health_spec.append(config) if isinstance( config, vim.dvs.VmwareDistributedVirtualSwitch.TeamingHealthCheckConfig ): if health_check_teaming_failover is not None: config.enable = health_check_teaming_failover if health_teaming_failover_interval is not None: config.interval = health_teaming_failover_interval health_spec.append(config) if switch_ref: utils_vmware.update_dvs(dvs_ref=switch_ref, dvs_config_spec=config_spec) if product_spec: utils_vmware.update_dvs_version(dvs_ref=switch_ref, dvs_product_spec=product_spec) if health_spec: utils_vmware.update_dvs_health(dvs_ref=switch_ref, dvs_health_spec=health_spec) return True except ( vim.fault.DvsFault, vmodl.fault.NotSupported, salt.exceptions.VMwareApiError, vmodl.RuntimeFault, vmodl.MethodFault, ) as exc: raise salt.exceptions.SaltException(str(exc))
[docs]def remove_hosts( switch_name, host_name=None, datacenter_name=None, cluster_name=None, service_instance=None, ): """ Remove ESXi host(s) from a distributed vSwitch. switch_name Name of the distributed vSwitch. datacenter_name Filter by this datacenter name (required when cluster is specified) cluster_name Filter by this cluster name (optional) host_name Filter by this ESXi hostname (optional) service_instance Use this vCenter service connection instance instead of creating a new one. (optional). .. code-block:: bash salt '*' vmware_dvswitch.remove_hosts switch_name=dvs1 hostname=host1 """ log.debug("Running vmware_dvswitch.remove_hosts") ret = {} if not service_instance: service_instance = get_service_instance(opts=__opts__, pillar=__pillar__) hosts = utils_esxi.get_hosts( service_instance=service_instance, host_names=[host_name] if host_name else None, cluster_name=cluster_name, datacenter_name=datacenter_name, get_all_hosts=host_name is None, ) try: for h in hosts: ret[h.name] = False if hasattr(h.configManager.networkSystem.networkInfo, "vswitch"): h.configManager.networkSystem.RemoveVirtualSwitch(vswitchName=switch_name) ret[h.name] = True return ret except ( vim.fault.InvalidState, vim.fault.NotFound, vim.fault.HostConfigFault, vim.fault.ResourceInUse, vmodl.fault.InvalidArgument, salt.exceptions.VMwareApiError, ) as exc: raise salt.exceptions.SaltException(str(exc))
[docs]def add_hosts( switch_name, host_name=None, datacenter_name=None, cluster_name=None, nics=None, service_instance=None, ): """ Add ESXi host(s) to a distributed vSwitch. switch_name Name of the distributed vSwitch. datacenter_name Filter by this datacenter name (required when cluster is specified) cluster_name Filter by this cluster name (optional) host_name Filter by this ESXi hostname (optional) nics List of vmnics to attach to vSwitch. (optional). Default "None". service_instance Use this vCenter service connection instance instead of creating a new one. (optional). .. code-block:: bash salt '*' vmware_dvswitch.add_hosts switch_name=dvs1 host_name=host1 num_ports=256 mtu=1800 """ log.debug("Running vmware_dvswitch.add_hosts") ret = {} if not service_instance: service_instance = get_service_instance(opts=__opts__, pillar=__pillar__) _, switch_ref, _ = _get_switch_config_spec( service_instance=service_instance, datacenter_name=datacenter_name, switch_name=switch_name, ) hosts = utils_esxi.get_hosts( service_instance=service_instance, host_names=[host_name] if host_name else None, cluster_name=cluster_name, datacenter_name=datacenter_name, get_all_hosts=host_name is None, ) try: for h in hosts: ret[h.name] = False network_manager = h.configManager.networkSystem if not network_manager: continue if isinstance(nics, str): nics = [nics] vss_spec = vim.host.VirtualSwitch.Specification() vss_spec.mtu = switch_ref.config.maxMtu or 1500 vss_spec.numPorts = switch_ref.config.numPorts or 128 if nics: vss_spec.bridge = vim.host.VirtualSwitch.BondBridge(nicDevice=nics) network_manager.AddVirtualSwitch(vswitchName=switch_name, spec=vss_spec) ret[h.name] = True return ret except ( vim.fault.InvalidState, vim.fault.NotFound, vim.fault.HostConfigFault, vim.fault.ResourceInUse, vmodl.fault.InvalidArgument, salt.exceptions.VMwareApiError, ) as exc: raise salt.exceptions.SaltException(str(exc))
[docs]def update_hosts( switch_name, host_name=None, datacenter_name=None, cluster_name=None, nics=None, num_ports=None, mtu=None, service_instance=None, ): """ Update ESXi host(s) on a distributed vSwitch. switch_name Name of the distributed vSwitch. datacenter_name Filter by this datacenter name (required when cluster is specified) cluster_name Filter by this cluster name (optional) host_name Filter by this ESXi hostname (optional) nics List of vmnics to attach to vSwitch. (optional). Default "None". num_ports Number of ports to configure on the vSwitch. (optional). Default 128. mtu MTU to configure on the vSwitch. (optional). Default 1600. service_instance Use this vCenter service connection instance instead of creating a new one. (optional). .. code-block:: bash salt '*' vmware_dvswitch.update_hosts switch_name=dvs1 host_name=host1 num_ports=256 mtu=1800 """ log.debug("Running vmware_dvswitch.update_hosts") ret = {} if not service_instance: service_instance = get_service_instance(opts=__opts__, pillar=__pillar__) _, switch_ref, _ = _get_switch_config_spec( service_instance=service_instance, datacenter_name=datacenter_name, switch_name=switch_name, ) hosts = utils_esxi.get_hosts( service_instance=service_instance, host_names=[host_name] if host_name else None, cluster_name=cluster_name, datacenter_name=datacenter_name, get_all_hosts=host_name is None, ) try: for h in hosts: ret[h.name] = False network_manager = h.configManager.networkSystem if not network_manager: continue if isinstance(nics, str): nics = [nics] vss_spec = vim.host.VirtualSwitch.Specification() if hasattr(network_manager.networkInfo, "vswitch"): for switch in network_manager.networkInfo.vswitch: if switch.name != switch_name: continue vss_spec.mtu = mtu or switch.mtu or switch_ref.config.maxMtu vss_spec.numPorts = ( num_ports or switch.spec.numPorts or switch_ref.config.numPorts ) if switch.pnic or nics: vss_spec.bridge = vim.host.VirtualSwitch.BondBridge( nicDevice=nics or list(map(lambda x: x.split("-", 3)[-1], switch.pnic)) ) network_manager.UpdateVirtualSwitch(vswitchName=switch_name, spec=vss_spec) ret[h.name] = True return ret except ( vim.fault.InvalidState, vim.fault.NotFound, vim.fault.HostConfigFault, vim.fault.ResourceInUse, vmodl.fault.InvalidArgument, salt.exceptions.VMwareApiError, ) as exc: raise salt.exceptions.SaltException(str(exc))