"Fossies" - the Fresh Open Source Software Archive

Member "salt-3002.2/salt/modules/vsphere.py" (18 Nov 2020, 377785 Bytes) of package /linux/misc/salt-3002.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "vsphere.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3002.1_vs_3002.2.

    1 """
    2 Manage VMware vCenter servers and ESXi hosts.
    3 
    4 .. versionadded:: 2015.8.4
    5 
    6 :codeauthor: Alexandru Bleotu <alexandru.bleotu@morganstaley.com>
    7 
    8 Dependencies
    9 ============
   10 
   11 - pyVmomi Python Module
   12 - ESXCLI
   13 
   14 pyVmomi
   15 -------
   16 
   17 PyVmomi can be installed via pip:
   18 
   19 .. code-block:: bash
   20 
   21     pip install pyVmomi
   22 
   23 .. note::
   24 
   25     Version 6.0 of pyVmomi has some problems with SSL error handling on certain
   26     versions of Python. If using version 6.0 of pyVmomi, Python 2.7.9,
   27     or newer must be present. This is due to an upstream dependency
   28     in pyVmomi 6.0 that is not supported in Python versions 2.7 to 2.7.8. If the
   29     version of Python is not in the supported range, you will need to install an
   30     earlier version of pyVmomi. See `Issue #29537`_ for more information.
   31 
   32 .. _Issue #29537: https://github.com/saltstack/salt/issues/29537
   33 
   34 Based on the note above, to install an earlier version of pyVmomi than the
   35 version currently listed in PyPi, run the following:
   36 
   37 .. code-block:: bash
   38 
   39     pip install pyVmomi==5.5.0.2014.1.1
   40 
   41 The 5.5.0.2014.1.1 is a known stable version that this original vSphere Execution
   42 Module was developed against.
   43 
   44 vSphere Automation SDK
   45 ----------------------
   46 
   47 vSphere Automation SDK can be installed via pip:
   48 
   49 .. code-block:: bash
   50 
   51     pip install --upgrade pip setuptools
   52     pip install --upgrade git+https://github.com/vmware/vsphere-automation-sdk-python.git
   53 
   54 .. note::
   55 
   56     The SDK also requires OpenSSL 1.0.1+ if you want to connect to vSphere 6.5+ in order to support
   57     TLS1.1 & 1.2.
   58 
   59     In order to use the tagging functions in this module, vSphere Automation SDK is necessary to
   60     install.
   61 
   62 The module is currently in version 1.0.3
   63 (as of 8/26/2019)
   64 
   65 ESXCLI
   66 ------
   67 
   68 Currently, about a third of the functions used in the vSphere Execution Module require
   69 the ESXCLI package be installed on the machine running the Proxy Minion process.
   70 
   71 The ESXCLI package is also referred to as the VMware vSphere CLI, or vCLI. VMware
   72 provides vCLI package installation instructions for `vSphere 5.5`_ and
   73 `vSphere 6.0`_.
   74 
   75 .. _vSphere 5.5: http://pubs.vmware.com/vsphere-55/index.jsp#com.vmware.vcli.getstart.doc/cli_install.4.2.html
   76 .. _vSphere 6.0: http://pubs.vmware.com/vsphere-60/index.jsp#com.vmware.vcli.getstart.doc/cli_install.4.2.html
   77 
   78 Once all of the required dependencies are in place and the vCLI package is
   79 installed, you can check to see if you can connect to your ESXi host or vCenter
   80 server by running the following command:
   81 
   82 .. code-block:: bash
   83 
   84     esxcli -s <host-location> -u <username> -p <password> system syslog config get
   85 
   86 If the connection was successful, ESXCLI was successfully installed on your system.
   87 You should see output related to the ESXi host's syslog configuration.
   88 
   89 .. note::
   90 
   91     Be aware that some functionality in this execution module may depend on the
   92     type of license attached to a vCenter Server or ESXi host(s).
   93 
   94     For example, certain services are only available to manipulate service state
   95     or policies with a VMware vSphere Enterprise or Enterprise Plus license, while
   96     others are available with a Standard license. The ``ntpd`` service is restricted
   97     to an Enterprise Plus license, while ``ssh`` is available via the Standard
   98     license.
   99 
  100     Please see the `vSphere Comparison`_ page for more information.
  101 
  102 .. _vSphere Comparison: https://www.vmware.com/products/vsphere/compare
  103 
  104 
  105 About
  106 =====
  107 
  108 This execution module was designed to be able to handle connections both to a
  109 vCenter Server, as well as to an ESXi host. It utilizes the pyVmomi Python
  110 library and the ESXCLI package to run remote execution functions against either
  111 the defined vCenter server or the ESXi host.
  112 
  113 Whether or not the function runs against a vCenter Server or an ESXi host depends
  114 entirely upon the arguments passed into the function. Each function requires a
  115 ``host`` location, ``username``, and ``password``. If the credentials provided
  116 apply to a vCenter Server, then the function will be run against the vCenter
  117 Server. For example, when listing hosts using vCenter credentials, you'll get a
  118 list of hosts associated with that vCenter Server:
  119 
  120 .. code-block:: bash
  121 
  122     # salt my-minion vsphere.list_hosts <vcenter-ip> <vcenter-user> <vcenter-password>
  123     my-minion:
  124     - esxi-1.example.com
  125     - esxi-2.example.com
  126 
  127 However, some functions should be used against ESXi hosts, not vCenter Servers.
  128 Functionality such as getting a host's coredump network configuration should be
  129 performed against a host and not a vCenter server. If the authentication
  130 information you're using is against a vCenter server and not an ESXi host, you
  131 can provide the host name that is associated with the vCenter server in the
  132 command, as a list, using the ``host_names`` or ``esxi_host`` kwarg. For
  133 example:
  134 
  135 .. code-block:: bash
  136 
  137     # salt my-minion vsphere.get_coredump_network_config <vcenter-ip> <vcenter-user> \
  138         <vcenter-password> esxi_hosts='[esxi-1.example.com, esxi-2.example.com]'
  139     my-minion:
  140     ----------
  141         esxi-1.example.com:
  142             ----------
  143             Coredump Config:
  144                 ----------
  145                 enabled:
  146                     False
  147         esxi-2.example.com:
  148             ----------
  149             Coredump Config:
  150                 ----------
  151                 enabled:
  152                     True
  153                 host_vnic:
  154                     vmk0
  155                 ip:
  156                     coredump-location.example.com
  157                 port:
  158                     6500
  159 
  160 You can also use these functions against an ESXi host directly by establishing a
  161 connection to an ESXi host using the host's location, username, and password. If ESXi
  162 connection credentials are used instead of vCenter credentials, the ``host_names`` and
  163 ``esxi_hosts`` arguments are not needed.
  164 
  165 .. code-block:: bash
  166 
  167     # salt my-minion vsphere.get_coredump_network_config esxi-1.example.com root <host-password>
  168     local:
  169     ----------
  170         10.4.28.150:
  171             ----------
  172             Coredump Config:
  173                 ----------
  174                 enabled:
  175                     True
  176                 host_vnic:
  177                     vmk0
  178                 ip:
  179                     coredump-location.example.com
  180                 port:
  181                     6500
  182 """
  183 
  184 
  185 import datetime
  186 import logging
  187 import sys
  188 from functools import wraps
  189 
  190 import salt.utils.args
  191 import salt.utils.dictupdate as dictupdate
  192 import salt.utils.http
  193 import salt.utils.path
  194 import salt.utils.pbm
  195 import salt.utils.vmware
  196 import salt.utils.vsan
  197 from salt.config.schemas.esxcluster import (
  198     ESXClusterConfigSchema,
  199     ESXClusterEntitySchema,
  200 )
  201 from salt.config.schemas.esxi import (
  202     DiskGroupsDiskIdSchema,
  203     SimpleHostCacheSchema,
  204     VmfsDatastoreSchema,
  205 )
  206 from salt.config.schemas.esxvm import (
  207     ESXVirtualMachineDeleteSchema,
  208     ESXVirtualMachineUnregisterSchema,
  209 )
  210 from salt.config.schemas.vcenter import VCenterEntitySchema
  211 from salt.exceptions import (
  212     ArgumentValueError,
  213     CommandExecutionError,
  214     InvalidConfigError,
  215     InvalidEntityError,
  216     VMwareApiError,
  217     VMwareObjectExistsError,
  218     VMwareObjectRetrievalError,
  219     VMwareSaltError,
  220 )
  221 from salt.utils.decorators import depends, ignores_kwargs
  222 from salt.utils.dictdiffer import recursive_diff
  223 from salt.utils.listdiffer import list_diff
  224 
  225 log = logging.getLogger(__name__)
  226 
  227 try:
  228     import jsonschema
  229 
  230     HAS_JSONSCHEMA = True
  231 except ImportError:
  232     HAS_JSONSCHEMA = False
  233 
  234 try:
  235     # pylint: disable=no-name-in-module
  236     from pyVmomi import (
  237         vim,
  238         vmodl,
  239         pbm,
  240         VmomiSupport,
  241     )
  242 
  243     # pylint: enable=no-name-in-module
  244 
  245     # We check the supported vim versions to infer the pyVmomi version
  246     if (
  247         "vim25/6.0" in VmomiSupport.versionMap
  248         and sys.version_info > (2, 7)
  249         and sys.version_info < (2, 7, 9)
  250     ):
  251 
  252         log.debug(
  253             "pyVmomi not loaded: Incompatible versions " "of Python. See Issue #29537."
  254         )
  255         raise ImportError()
  256     HAS_PYVMOMI = True
  257 except ImportError:
  258     HAS_PYVMOMI = False
  259 
  260 # vSphere SDK Automation
  261 # pylint: disable=unused-import
  262 try:
  263     from com.vmware.cis.tagging_client import Category, CategoryModel
  264     from com.vmware.cis.tagging_client import Tag, TagModel, TagAssociation
  265     from com.vmware.vcenter_client import Cluster
  266     from com.vmware.vapi.std_client import DynamicID
  267 
  268     # Error Handling
  269     from com.vmware.vapi.std.errors_client import (
  270         AlreadyExists,
  271         InvalidArgument,
  272         NotFound,
  273         Unauthenticated,
  274         Unauthorized,
  275     )
  276 
  277     vsphere_errors = (
  278         AlreadyExists,
  279         InvalidArgument,
  280         NotFound,
  281         Unauthenticated,
  282         Unauthorized,
  283     )
  284     HAS_VSPHERE_SDK = True
  285 except ImportError:
  286     HAS_VSPHERE_SDK = False
  287 # pylint: enable=unused-import
  288 
  289 # ESXI
  290 esx_cli = salt.utils.path.which("esxcli")
  291 if esx_cli:
  292     HAS_ESX_CLI = True
  293 else:
  294     HAS_ESX_CLI = False
  295 
  296 __virtualname__ = "vsphere"
  297 __proxyenabled__ = ["esxi", "esxcluster", "esxdatacenter", "vcenter", "esxvm"]
  298 
  299 
  300 def __virtual__():
  301     return __virtualname__
  302 
  303 
  304 def get_proxy_type():
  305     """
  306     Returns the proxy type retrieved either from the pillar of from the proxy
  307     minion's config.  Returns ``<undefined>`` otherwise.
  308 
  309     CLI Example:
  310 
  311     .. code-block:: bash
  312 
  313         salt '*' vsphere.get_proxy_type
  314     """
  315     if __pillar__.get("proxy", {}).get("proxytype"):
  316         return __pillar__["proxy"]["proxytype"]
  317     if __opts__.get("proxy", {}).get("proxytype"):
  318         return __opts__["proxy"]["proxytype"]
  319     return "<undefined>"
  320 
  321 
  322 def _get_proxy_connection_details():
  323     """
  324     Returns the connection details of the following proxies: esxi
  325     """
  326     proxytype = get_proxy_type()
  327     if proxytype == "esxi":
  328         details = __salt__["esxi.get_details"]()
  329     elif proxytype == "esxcluster":
  330         details = __salt__["esxcluster.get_details"]()
  331     elif proxytype == "esxdatacenter":
  332         details = __salt__["esxdatacenter.get_details"]()
  333     elif proxytype == "vcenter":
  334         details = __salt__["vcenter.get_details"]()
  335     elif proxytype == "esxvm":
  336         details = __salt__["esxvm.get_details"]()
  337     else:
  338         raise CommandExecutionError("'{}' proxy is not supported" "".format(proxytype))
  339     return (
  340         details.get("vcenter") if "vcenter" in details else details.get("host"),
  341         details.get("username"),
  342         details.get("password"),
  343         details.get("protocol"),
  344         details.get("port"),
  345         details.get("mechanism"),
  346         details.get("principal"),
  347         details.get("domain"),
  348     )
  349 
  350 
  351 def supports_proxies(*proxy_types):
  352     """
  353     Decorator to specify which proxy types are supported by a function
  354 
  355     proxy_types:
  356         Arbitrary list of strings with the supported types of proxies
  357     """
  358 
  359     def _supports_proxies(fn):
  360         @wraps(fn)
  361         def __supports_proxies(*args, **kwargs):
  362             proxy_type = get_proxy_type()
  363             if proxy_type not in proxy_types:
  364                 raise CommandExecutionError(
  365                     "'{}' proxy is not supported by function {}"
  366                     "".format(proxy_type, fn.__name__)
  367                 )
  368             return fn(*args, **salt.utils.args.clean_kwargs(**kwargs))
  369 
  370         return __supports_proxies
  371 
  372     return _supports_proxies
  373 
  374 
  375 def gets_service_instance_via_proxy(fn):
  376     """
  377     Decorator that connects to a target system (vCenter or ESXi host) using the
  378     proxy details and passes the connection (vim.ServiceInstance) to
  379     the decorated function.
  380 
  381     Supported proxies: esxi, esxcluster, esxdatacenter.
  382 
  383     Notes:
  384         1. The decorated function must have a ``service_instance`` parameter
  385         or a ``**kwarg`` type argument (name of argument is not important);
  386         2. If the ``service_instance`` parameter is already defined, the value
  387         is passed through to the decorated function;
  388         3. If the ``service_instance`` parameter in not defined, the
  389         connection is created using the proxy details and the service instance
  390         is returned.
  391 
  392     CLI Example:
  393         None, this is a decorator
  394     """
  395     fn_name = fn.__name__
  396     (
  397         arg_names,
  398         args_name,
  399         kwargs_name,
  400         default_values,
  401     ) = salt.utils.args.get_function_argspec(fn)
  402     default_values = default_values if default_values is not None else []
  403 
  404     @wraps(fn)
  405     def _gets_service_instance_via_proxy(*args, **kwargs):
  406         if "service_instance" not in arg_names and not kwargs_name:
  407             raise CommandExecutionError(
  408                 "Function {} must have either a 'service_instance', or a "
  409                 "'**kwargs' type parameter".format(fn_name)
  410             )
  411         connection_details = _get_proxy_connection_details()
  412         # Figure out how to pass in the connection value
  413         local_service_instance = None
  414         if "service_instance" in arg_names:
  415             idx = arg_names.index("service_instance")
  416             if idx >= len(arg_names) - len(default_values):
  417                 # 'service_instance' has a default value:
  418                 #     we check if we need to instantiate it or
  419                 #     pass it through
  420                 #
  421                 # NOTE: if 'service_instance' doesn't have a default value
  422                 # it must be explicitly set in the function call so we pass it
  423                 # through
  424 
  425                 # There are two cases:
  426                 #   1. service_instance was passed in as a positional parameter
  427                 #   2. service_instance was passed in as a named paramter
  428                 if len(args) > idx:
  429                     # case 1: The call was made with enough positional
  430                     # parameters to include 'service_instance'
  431                     if not args[idx]:
  432                         local_service_instance = salt.utils.vmware.get_service_instance(
  433                             *connection_details
  434                         )
  435                         # Tuples are immutable, so if we want to change what
  436                         # was passed in, we need to first convert to a list.
  437                         args = list(args)
  438                         args[idx] = local_service_instance
  439                 else:
  440                     # case 2: Not enough positional parameters so
  441                     # 'service_instance' must be a named parameter
  442                     if not kwargs.get("service_instance"):
  443                         local_service_instance = salt.utils.vmware.get_service_instance(
  444                             *connection_details
  445                         )
  446                         kwargs["service_instance"] = local_service_instance
  447         else:
  448             # 'service_instance' is not a paremter in the function definition
  449             # but it will be caught by the **kwargs parameter
  450             if not kwargs.get("service_instance"):
  451                 local_service_instance = salt.utils.vmware.get_service_instance(
  452                     *connection_details
  453                 )
  454                 kwargs["service_instance"] = local_service_instance
  455         try:
  456             ret = fn(*args, **salt.utils.args.clean_kwargs(**kwargs))
  457             # Disconnect if connected in the decorator
  458             if local_service_instance:
  459                 salt.utils.vmware.disconnect(local_service_instance)
  460             return ret
  461         except Exception as e:  # pylint: disable=broad-except
  462             # Disconnect if connected in the decorator
  463             if local_service_instance:
  464                 salt.utils.vmware.disconnect(local_service_instance)
  465             # raise original exception and traceback
  466             raise
  467 
  468     return _gets_service_instance_via_proxy
  469 
  470 
  471 @depends(HAS_PYVMOMI)
  472 @supports_proxies("esxi", "esxcluster", "esxdatacenter", "vcenter", "esxvm")
  473 def get_service_instance_via_proxy(service_instance=None):
  474     """
  475     Returns a service instance to the proxied endpoint (vCenter/ESXi host).
  476 
  477     service_instance
  478         Service instance (vim.ServiceInstance) of the vCenter.
  479         Default is None.
  480 
  481     Note:
  482         Should be used by state functions not invoked directly.
  483 
  484     CLI Example:
  485         See note above
  486     """
  487     connection_details = _get_proxy_connection_details()
  488     return salt.utils.vmware.get_service_instance(*connection_details)
  489 
  490 
  491 @depends(HAS_PYVMOMI)
  492 @supports_proxies("esxi", "esxcluster", "esxdatacenter", "vcenter", "esxvm")
  493 def disconnect(service_instance):
  494     """
  495     Disconnects from a vCenter or ESXi host
  496 
  497     Note:
  498         Should be used by state functions, not invoked directly.
  499 
  500     service_instance
  501         Service instance (vim.ServiceInstance)
  502 
  503     CLI Example:
  504 
  505         See note above.
  506     """
  507     salt.utils.vmware.disconnect(service_instance)
  508     return True
  509 
  510 
  511 @depends(HAS_ESX_CLI)
  512 def esxcli_cmd(
  513     cmd_str,
  514     host=None,
  515     username=None,
  516     password=None,
  517     protocol=None,
  518     port=None,
  519     esxi_hosts=None,
  520     credstore=None,
  521 ):
  522     """
  523     Run an ESXCLI command directly on the host or list of hosts.
  524 
  525     host
  526         The location of the host.
  527 
  528     username
  529         The username used to login to the host, such as ``root``.
  530 
  531     password
  532         The password used to login to the host.
  533 
  534     cmd_str
  535         The ESXCLI command to run. Note: This should not include the ``-s``, ``-u``,
  536         ``-p``, ``-h``, ``--protocol``, or ``--portnumber`` arguments that are
  537         frequently passed when using a bare ESXCLI command from the command line.
  538         Those arguments are handled by this function via the other args and kwargs.
  539 
  540     protocol
  541         Optionally set to alternate protocol if the host is not using the default
  542         protocol. Default protocol is ``https``.
  543 
  544     port
  545         Optionally set to alternate port if the host is not using the default
  546         port. Default port is ``443``.
  547 
  548     esxi_hosts
  549         If ``host`` is a vCenter host, then use esxi_hosts to execute this function
  550         on a list of one or more ESXi machines.
  551 
  552     credstore
  553         Optionally set to path to the credential store file.
  554 
  555     CLI Example:
  556 
  557     .. code-block:: bash
  558 
  559         # Used for ESXi host connection information
  560         salt '*' vsphere.esxcli_cmd my.esxi.host root bad-password \
  561             'system coredump network get'
  562 
  563         # Used for connecting to a vCenter Server
  564         salt '*' vsphere.esxcli_cmd my.vcenter.location root bad-password \
  565             'system coredump network get' esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
  566     """
  567     ret = {}
  568     if esxi_hosts:
  569         if not isinstance(esxi_hosts, list):
  570             raise CommandExecutionError("'esxi_hosts' must be a list.")
  571 
  572         for esxi_host in esxi_hosts:
  573             response = salt.utils.vmware.esxcli(
  574                 host,
  575                 username,
  576                 password,
  577                 cmd_str,
  578                 protocol=protocol,
  579                 port=port,
  580                 esxi_host=esxi_host,
  581                 credstore=credstore,
  582             )
  583             if response["retcode"] != 0:
  584                 ret.update({esxi_host: {"Error": response.get("stdout")}})
  585             else:
  586                 ret.update({esxi_host: response})
  587     else:
  588         # Handles a single host or a vCenter connection when no esxi_hosts are provided.
  589         response = salt.utils.vmware.esxcli(
  590             host,
  591             username,
  592             password,
  593             cmd_str,
  594             protocol=protocol,
  595             port=port,
  596             credstore=credstore,
  597         )
  598         if response["retcode"] != 0:
  599             ret.update({host: {"Error": response.get("stdout")}})
  600         else:
  601             ret.update({host: response})
  602 
  603     return ret
  604 
  605 
  606 @depends(HAS_ESX_CLI)
  607 def get_coredump_network_config(
  608     host, username, password, protocol=None, port=None, esxi_hosts=None, credstore=None
  609 ):
  610     """
  611     Retrieve information on ESXi or vCenter network dump collection and
  612     format it into a dictionary.
  613 
  614     host
  615         The location of the host.
  616 
  617     username
  618         The username used to login to the host, such as ``root``.
  619 
  620     password
  621         The password used to login to the host.
  622 
  623     protocol
  624         Optionally set to alternate protocol if the host is not using the default
  625         protocol. Default protocol is ``https``.
  626 
  627     port
  628         Optionally set to alternate port if the host is not using the default
  629         port. Default port is ``443``.
  630 
  631     esxi_hosts
  632         If ``host`` is a vCenter host, then use esxi_hosts to execute this function
  633         on a list of one or more ESXi machines.
  634 
  635     credstore
  636         Optionally set to path to the credential store file.
  637 
  638     :return: A dictionary with the network configuration, or, if getting
  639              the network config failed, a an error message retrieved from the
  640              standard cmd.run_all dictionary, per host.
  641 
  642     CLI Example:
  643 
  644     .. code-block:: bash
  645 
  646         # Used for ESXi host connection information
  647         salt '*' vsphere.get_coredump_network_config my.esxi.host root bad-password
  648 
  649         # Used for connecting to a vCenter Server
  650         salt '*' vsphere.get_coredump_network_config my.vcenter.location root bad-password \
  651             esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
  652 
  653     """
  654     cmd = "system coredump network get"
  655     ret = {}
  656     if esxi_hosts:
  657         if not isinstance(esxi_hosts, list):
  658             raise CommandExecutionError("'esxi_hosts' must be a list.")
  659 
  660         for esxi_host in esxi_hosts:
  661             response = salt.utils.vmware.esxcli(
  662                 host,
  663                 username,
  664                 password,
  665                 cmd,
  666                 protocol=protocol,
  667                 port=port,
  668                 esxi_host=esxi_host,
  669                 credstore=credstore,
  670             )
  671             if response["retcode"] != 0:
  672                 ret.update({esxi_host: {"Error": response.get("stdout")}})
  673             else:
  674                 # format the response stdout into something useful
  675                 ret.update(
  676                     {esxi_host: {"Coredump Config": _format_coredump_stdout(response)}}
  677                 )
  678     else:
  679         # Handles a single host or a vCenter connection when no esxi_hosts are provided.
  680         response = salt.utils.vmware.esxcli(
  681             host,
  682             username,
  683             password,
  684             cmd,
  685             protocol=protocol,
  686             port=port,
  687             credstore=credstore,
  688         )
  689         if response["retcode"] != 0:
  690             ret.update({host: {"Error": response.get("stdout")}})
  691         else:
  692             # format the response stdout into something useful
  693             stdout = _format_coredump_stdout(response)
  694             ret.update({host: {"Coredump Config": stdout}})
  695 
  696     return ret
  697 
  698 
  699 @depends(HAS_ESX_CLI)
  700 def coredump_network_enable(
  701     host,
  702     username,
  703     password,
  704     enabled,
  705     protocol=None,
  706     port=None,
  707     esxi_hosts=None,
  708     credstore=None,
  709 ):
  710     """
  711     Enable or disable ESXi core dump collection. Returns ``True`` if coredump is enabled
  712     and returns ``False`` if core dump is not enabled. If there was an error, the error
  713     will be the value printed in the ``Error`` key dictionary for the given host.
  714 
  715     host
  716         The location of the host.
  717 
  718     username
  719         The username used to login to the host, such as ``root``.
  720 
  721     password
  722         The password used to login to the host.
  723 
  724     enabled
  725         Python True or False to enable or disable coredumps.
  726 
  727     protocol
  728         Optionally set to alternate protocol if the host is not using the default
  729         protocol. Default protocol is ``https``.
  730 
  731     port
  732         Optionally set to alternate port if the host is not using the default
  733         port. Default port is ``443``.
  734 
  735     esxi_hosts
  736         If ``host`` is a vCenter host, then use esxi_hosts to execute this function
  737         on a list of one or more ESXi machines.
  738 
  739     credstore
  740         Optionally set to path to the credential store file.
  741 
  742     CLI Example:
  743 
  744     .. code-block:: bash
  745 
  746         # Used for ESXi host connection information
  747         salt '*' vsphere.coredump_network_enable my.esxi.host root bad-password True
  748 
  749         # Used for connecting to a vCenter Server
  750         salt '*' vsphere.coredump_network_enable my.vcenter.location root bad-password True \
  751             esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
  752     """
  753     if enabled:
  754         enable_it = 1
  755     else:
  756         enable_it = 0
  757     cmd = "system coredump network set -e {}".format(enable_it)
  758 
  759     ret = {}
  760     if esxi_hosts:
  761         if not isinstance(esxi_hosts, list):
  762             raise CommandExecutionError("'esxi_hosts' must be a list.")
  763 
  764         for esxi_host in esxi_hosts:
  765             response = salt.utils.vmware.esxcli(
  766                 host,
  767                 username,
  768                 password,
  769                 cmd,
  770                 protocol=protocol,
  771                 port=port,
  772                 esxi_host=esxi_host,
  773                 credstore=credstore,
  774             )
  775             if response["retcode"] != 0:
  776                 ret.update({esxi_host: {"Error": response.get("stdout")}})
  777             else:
  778                 ret.update({esxi_host: {"Coredump Enabled": enabled}})
  779 
  780     else:
  781         # Handles a single host or a vCenter connection when no esxi_hosts are provided.
  782         response = salt.utils.vmware.esxcli(
  783             host,
  784             username,
  785             password,
  786             cmd,
  787             protocol=protocol,
  788             port=port,
  789             credstore=credstore,
  790         )
  791         if response["retcode"] != 0:
  792             ret.update({host: {"Error": response.get("stdout")}})
  793         else:
  794             ret.update({host: {"Coredump Enabled": enabled}})
  795 
  796     return ret
  797 
  798 
  799 @depends(HAS_ESX_CLI)
  800 def set_coredump_network_config(
  801     host,
  802     username,
  803     password,
  804     dump_ip,
  805     protocol=None,
  806     port=None,
  807     host_vnic="vmk0",
  808     dump_port=6500,
  809     esxi_hosts=None,
  810     credstore=None,
  811 ):
  812     """
  813 
  814     Set the network parameters for a network coredump collection.
  815     Note that ESXi requires that the dumps first be enabled (see
  816     `coredump_network_enable`) before these parameters may be set.
  817 
  818     host
  819         The location of the host.
  820 
  821     username
  822         The username used to login to the host, such as ``root``.
  823 
  824     password
  825         The password used to login to the host.
  826 
  827     dump_ip
  828         IP address of host that will accept the dump.
  829 
  830     protocol
  831         Optionally set to alternate protocol if the host is not using the default
  832         protocol. Default protocol is ``https``.
  833 
  834     port
  835         Optionally set to alternate port if the host is not using the default
  836         port. Default port is ``443``.
  837 
  838     esxi_hosts
  839         If ``host`` is a vCenter host, then use esxi_hosts to execute this function
  840         on a list of one or more ESXi machines.
  841 
  842     host_vnic
  843         Host VNic port through which to communicate. Defaults to ``vmk0``.
  844 
  845     dump_port
  846         TCP port to use for the dump, defaults to ``6500``.
  847 
  848     credstore
  849         Optionally set to path to the credential store file.
  850 
  851     :return: A standard cmd.run_all dictionary with a `success` key added, per host.
  852              `success` will be True if the set succeeded, False otherwise.
  853 
  854     CLI Example:
  855 
  856     .. code-block:: bash
  857 
  858         # Used for ESXi host connection information
  859         salt '*' vsphere.set_coredump_network_config my.esxi.host root bad-password 'dump_ip.host.com'
  860 
  861         # Used for connecting to a vCenter Server
  862         salt '*' vsphere.set_coredump_network_config my.vcenter.location root bad-password 'dump_ip.host.com' \
  863             esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
  864     """
  865     cmd = "system coredump network set -v {} -i {} -o {}".format(
  866         host_vnic, dump_ip, dump_port
  867     )
  868     ret = {}
  869     if esxi_hosts:
  870         if not isinstance(esxi_hosts, list):
  871             raise CommandExecutionError("'esxi_hosts' must be a list.")
  872 
  873         for esxi_host in esxi_hosts:
  874             response = salt.utils.vmware.esxcli(
  875                 host,
  876                 username,
  877                 password,
  878                 cmd,
  879                 protocol=protocol,
  880                 port=port,
  881                 esxi_host=esxi_host,
  882                 credstore=credstore,
  883             )
  884             if response["retcode"] != 0:
  885                 response["success"] = False
  886             else:
  887                 response["success"] = True
  888 
  889             # Update the cmd.run_all dictionary for each particular host.
  890             ret.update({esxi_host: response})
  891     else:
  892         # Handles a single host or a vCenter connection when no esxi_hosts are provided.
  893         response = salt.utils.vmware.esxcli(
  894             host,
  895             username,
  896             password,
  897             cmd,
  898             protocol=protocol,
  899             port=port,
  900             credstore=credstore,
  901         )
  902         if response["retcode"] != 0:
  903             response["success"] = False
  904         else:
  905             response["success"] = True
  906         ret.update({host: response})
  907 
  908     return ret
  909 
  910 
  911 @depends(HAS_ESX_CLI)
  912 def get_firewall_status(
  913     host, username, password, protocol=None, port=None, esxi_hosts=None, credstore=None
  914 ):
  915     """
  916     Show status of all firewall rule sets.
  917 
  918     host
  919         The location of the host.
  920 
  921     username
  922         The username used to login to the host, such as ``root``.
  923 
  924     password
  925         The password used to login to the host.
  926 
  927     protocol
  928         Optionally set to alternate protocol if the host is not using the default
  929         protocol. Default protocol is ``https``.
  930 
  931     port
  932         Optionally set to alternate port if the host is not using the default
  933         port. Default port is ``443``.
  934 
  935     esxi_hosts
  936         If ``host`` is a vCenter host, then use esxi_hosts to execute this function
  937         on a list of one or more ESXi machines.
  938 
  939     credstore
  940         Optionally set to path to the credential store file.
  941 
  942     :return: Nested dictionary with two toplevel keys ``rulesets`` and ``success``
  943              ``success`` will be True or False depending on query success
  944              ``rulesets`` will list the rulesets and their statuses if ``success``
  945              was true, per host.
  946 
  947     CLI Example:
  948 
  949     .. code-block:: bash
  950 
  951         # Used for ESXi host connection information
  952         salt '*' vsphere.get_firewall_status my.esxi.host root bad-password
  953 
  954         # Used for connecting to a vCenter Server
  955         salt '*' vsphere.get_firewall_status my.vcenter.location root bad-password \
  956             esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
  957     """
  958     cmd = "network firewall ruleset list"
  959 
  960     ret = {}
  961     if esxi_hosts:
  962         if not isinstance(esxi_hosts, list):
  963             raise CommandExecutionError("'esxi_hosts' must be a list.")
  964 
  965         for esxi_host in esxi_hosts:
  966             response = salt.utils.vmware.esxcli(
  967                 host,
  968                 username,
  969                 password,
  970                 cmd,
  971                 protocol=protocol,
  972                 port=port,
  973                 esxi_host=esxi_host,
  974                 credstore=credstore,
  975             )
  976             if response["retcode"] != 0:
  977                 ret.update(
  978                     {
  979                         esxi_host: {
  980                             "Error": response["stdout"],
  981                             "success": False,
  982                             "rulesets": None,
  983                         }
  984                     }
  985                 )
  986             else:
  987                 # format the response stdout into something useful
  988                 ret.update({esxi_host: _format_firewall_stdout(response)})
  989     else:
  990         # Handles a single host or a vCenter connection when no esxi_hosts are provided.
  991         response = salt.utils.vmware.esxcli(
  992             host,
  993             username,
  994             password,
  995             cmd,
  996             protocol=protocol,
  997             port=port,
  998             credstore=credstore,
  999         )
 1000         if response["retcode"] != 0:
 1001             ret.update(
 1002                 {
 1003                     host: {
 1004                         "Error": response["stdout"],
 1005                         "success": False,
 1006                         "rulesets": None,
 1007                     }
 1008                 }
 1009             )
 1010         else:
 1011             # format the response stdout into something useful
 1012             ret.update({host: _format_firewall_stdout(response)})
 1013 
 1014     return ret
 1015 
 1016 
 1017 @depends(HAS_ESX_CLI)
 1018 def enable_firewall_ruleset(
 1019     host,
 1020     username,
 1021     password,
 1022     ruleset_enable,
 1023     ruleset_name,
 1024     protocol=None,
 1025     port=None,
 1026     esxi_hosts=None,
 1027     credstore=None,
 1028 ):
 1029     """
 1030     Enable or disable an ESXi firewall rule set.
 1031 
 1032     host
 1033         The location of the host.
 1034 
 1035     username
 1036         The username used to login to the host, such as ``root``.
 1037 
 1038     password
 1039         The password used to login to the host.
 1040 
 1041     ruleset_enable
 1042         True to enable the ruleset, false to disable.
 1043 
 1044     ruleset_name
 1045         Name of ruleset to target.
 1046 
 1047     protocol
 1048         Optionally set to alternate protocol if the host is not using the default
 1049         protocol. Default protocol is ``https``.
 1050 
 1051     port
 1052         Optionally set to alternate port if the host is not using the default
 1053         port. Default port is ``443``.
 1054 
 1055     esxi_hosts
 1056         If ``host`` is a vCenter host, then use esxi_hosts to execute this function
 1057         on a list of one or more ESXi machines.
 1058 
 1059     credstore
 1060         Optionally set to path to the credential store file.
 1061 
 1062     :return: A standard cmd.run_all dictionary, per host.
 1063 
 1064     CLI Example:
 1065 
 1066     .. code-block:: bash
 1067 
 1068         # Used for ESXi host connection information
 1069         salt '*' vsphere.enable_firewall_ruleset my.esxi.host root bad-password True 'syslog'
 1070 
 1071         # Used for connecting to a vCenter Server
 1072         salt '*' vsphere.enable_firewall_ruleset my.vcenter.location root bad-password True 'syslog' \
 1073             esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
 1074     """
 1075     cmd = "network firewall ruleset set --enabled {} --ruleset-id={}".format(
 1076         ruleset_enable, ruleset_name
 1077     )
 1078 
 1079     ret = {}
 1080     if esxi_hosts:
 1081         if not isinstance(esxi_hosts, list):
 1082             raise CommandExecutionError("'esxi_hosts' must be a list.")
 1083 
 1084         for esxi_host in esxi_hosts:
 1085             response = salt.utils.vmware.esxcli(
 1086                 host,
 1087                 username,
 1088                 password,
 1089                 cmd,
 1090                 protocol=protocol,
 1091                 port=port,
 1092                 esxi_host=esxi_host,
 1093                 credstore=credstore,
 1094             )
 1095             ret.update({esxi_host: response})
 1096     else:
 1097         # Handles a single host or a vCenter connection when no esxi_hosts are provided.
 1098         response = salt.utils.vmware.esxcli(
 1099             host,
 1100             username,
 1101             password,
 1102             cmd,
 1103             protocol=protocol,
 1104             port=port,
 1105             credstore=credstore,
 1106         )
 1107         ret.update({host: response})
 1108 
 1109     return ret
 1110 
 1111 
 1112 @depends(HAS_ESX_CLI)
 1113 def syslog_service_reload(
 1114     host, username, password, protocol=None, port=None, esxi_hosts=None, credstore=None
 1115 ):
 1116     """
 1117     Reload the syslog service so it will pick up any changes.
 1118 
 1119     host
 1120         The location of the host.
 1121 
 1122     username
 1123         The username used to login to the host, such as ``root``.
 1124 
 1125     password
 1126         The password used to login to the host.
 1127 
 1128     protocol
 1129         Optionally set to alternate protocol if the host is not using the default
 1130         protocol. Default protocol is ``https``.
 1131 
 1132     port
 1133         Optionally set to alternate port if the host is not using the default
 1134         port. Default port is ``443``.
 1135 
 1136     esxi_hosts
 1137         If ``host`` is a vCenter host, then use esxi_hosts to execute this function
 1138         on a list of one or more ESXi machines.
 1139 
 1140     credstore
 1141         Optionally set to path to the credential store file.
 1142 
 1143     :return: A standard cmd.run_all dictionary.  This dictionary will at least
 1144              have a `retcode` key.  If `retcode` is 0 the command was successful.
 1145 
 1146     CLI Example:
 1147 
 1148     .. code-block:: bash
 1149 
 1150         # Used for ESXi host connection information
 1151         salt '*' vsphere.syslog_service_reload my.esxi.host root bad-password
 1152 
 1153         # Used for connecting to a vCenter Server
 1154         salt '*' vsphere.syslog_service_reload my.vcenter.location root bad-password \
 1155             esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
 1156     """
 1157     cmd = "system syslog reload"
 1158 
 1159     ret = {}
 1160     if esxi_hosts:
 1161         if not isinstance(esxi_hosts, list):
 1162             raise CommandExecutionError("'esxi_hosts' must be a list.")
 1163 
 1164         for esxi_host in esxi_hosts:
 1165             response = salt.utils.vmware.esxcli(
 1166                 host,
 1167                 username,
 1168                 password,
 1169                 cmd,
 1170                 protocol=protocol,
 1171                 port=port,
 1172                 esxi_host=esxi_host,
 1173                 credstore=credstore,
 1174             )
 1175             ret.update({esxi_host: response})
 1176     else:
 1177         # Handles a single host or a vCenter connection when no esxi_hosts are provided.
 1178         response = salt.utils.vmware.esxcli(
 1179             host,
 1180             username,
 1181             password,
 1182             cmd,
 1183             protocol=protocol,
 1184             port=port,
 1185             credstore=credstore,
 1186         )
 1187         ret.update({host: response})
 1188 
 1189     return ret
 1190 
 1191 
 1192 @depends(HAS_ESX_CLI)
 1193 def set_syslog_config(
 1194     host,
 1195     username,
 1196     password,
 1197     syslog_config,
 1198     config_value,
 1199     protocol=None,
 1200     port=None,
 1201     firewall=True,
 1202     reset_service=True,
 1203     esxi_hosts=None,
 1204     credstore=None,
 1205 ):
 1206     """
 1207     Set the specified syslog configuration parameter. By default, this function will
 1208     reset the syslog service after the configuration is set.
 1209 
 1210     host
 1211         ESXi or vCenter host to connect to.
 1212 
 1213     username
 1214         User to connect as, usually root.
 1215 
 1216     password
 1217         Password to connect with.
 1218 
 1219     syslog_config
 1220         Name of parameter to set (corresponds to the command line switch for
 1221         esxcli without the double dashes (--))
 1222 
 1223         Valid syslog_config values are ``logdir``, ``loghost``, ``default-rotate`,
 1224         ``default-size``, ``default-timeout``, and ``logdir-unique``.
 1225 
 1226     config_value
 1227         Value for the above parameter. For ``loghost``, URLs or IP addresses to
 1228         use for logging. Multiple log servers can be specified by listing them,
 1229         comma-separated, but without spaces before or after commas.
 1230 
 1231         (reference: https://blogs.vmware.com/vsphere/2012/04/configuring-multiple-syslog-servers-for-esxi-5.html)
 1232 
 1233     protocol
 1234         Optionally set to alternate protocol if the host is not using the default
 1235         protocol. Default protocol is ``https``.
 1236 
 1237     port
 1238         Optionally set to alternate port if the host is not using the default
 1239         port. Default port is ``443``.
 1240 
 1241     firewall
 1242         Enable the firewall rule set for syslog. Defaults to ``True``.
 1243 
 1244     reset_service
 1245         After a successful parameter set, reset the service. Defaults to ``True``.
 1246 
 1247     esxi_hosts
 1248         If ``host`` is a vCenter host, then use esxi_hosts to execute this function
 1249         on a list of one or more ESXi machines.
 1250 
 1251     credstore
 1252         Optionally set to path to the credential store file.
 1253 
 1254     :return: Dictionary with a top-level key of 'success' which indicates
 1255              if all the parameters were reset, and individual keys
 1256              for each parameter indicating which succeeded or failed, per host.
 1257 
 1258     CLI Example:
 1259 
 1260     .. code-block:: bash
 1261 
 1262         # Used for ESXi host connection information
 1263         salt '*' vsphere.set_syslog_config my.esxi.host root bad-password \
 1264             loghost ssl://localhost:5432,tcp://10.1.0.1:1514
 1265 
 1266         # Used for connecting to a vCenter Server
 1267         salt '*' vsphere.set_syslog_config my.vcenter.location root bad-password \
 1268             loghost ssl://localhost:5432,tcp://10.1.0.1:1514 \
 1269             esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
 1270 
 1271     """
 1272     ret = {}
 1273 
 1274     # First, enable the syslog firewall ruleset, for each host, if needed.
 1275     if firewall and syslog_config == "loghost":
 1276         if esxi_hosts:
 1277             if not isinstance(esxi_hosts, list):
 1278                 raise CommandExecutionError("'esxi_hosts' must be a list.")
 1279 
 1280             for esxi_host in esxi_hosts:
 1281                 response = enable_firewall_ruleset(
 1282                     host,
 1283                     username,
 1284                     password,
 1285                     ruleset_enable=True,
 1286                     ruleset_name="syslog",
 1287                     protocol=protocol,
 1288                     port=port,
 1289                     esxi_hosts=[esxi_host],
 1290                     credstore=credstore,
 1291                 ).get(esxi_host)
 1292                 if response["retcode"] != 0:
 1293                     ret.update(
 1294                         {
 1295                             esxi_host: {
 1296                                 "enable_firewall": {
 1297                                     "message": response["stdout"],
 1298                                     "success": False,
 1299                                 }
 1300                             }
 1301                         }
 1302                     )
 1303                 else:
 1304                     ret.update({esxi_host: {"enable_firewall": {"success": True}}})
 1305         else:
 1306             # Handles a single host or a vCenter connection when no esxi_hosts are provided.
 1307             response = enable_firewall_ruleset(
 1308                 host,
 1309                 username,
 1310                 password,
 1311                 ruleset_enable=True,
 1312                 ruleset_name="syslog",
 1313                 protocol=protocol,
 1314                 port=port,
 1315                 credstore=credstore,
 1316             ).get(host)
 1317             if response["retcode"] != 0:
 1318                 ret.update(
 1319                     {
 1320                         host: {
 1321                             "enable_firewall": {
 1322                                 "message": response["stdout"],
 1323                                 "success": False,
 1324                             }
 1325                         }
 1326                     }
 1327                 )
 1328             else:
 1329                 ret.update({host: {"enable_firewall": {"success": True}}})
 1330 
 1331     # Set the config value on each esxi_host, if provided.
 1332     if esxi_hosts:
 1333         if not isinstance(esxi_hosts, list):
 1334             raise CommandExecutionError("'esxi_hosts' must be a list.")
 1335 
 1336         for esxi_host in esxi_hosts:
 1337             response = _set_syslog_config_helper(
 1338                 host,
 1339                 username,
 1340                 password,
 1341                 syslog_config,
 1342                 config_value,
 1343                 protocol=protocol,
 1344                 port=port,
 1345                 reset_service=reset_service,
 1346                 esxi_host=esxi_host,
 1347                 credstore=credstore,
 1348             )
 1349             # Ensure we don't overwrite any dictionary data already set
 1350             # By updating the esxi_host directly.
 1351             if ret.get(esxi_host) is None:
 1352                 ret.update({esxi_host: {}})
 1353             ret[esxi_host].update(response)
 1354 
 1355     else:
 1356         # Handles a single host or a vCenter connection when no esxi_hosts are provided.
 1357         response = _set_syslog_config_helper(
 1358             host,
 1359             username,
 1360             password,
 1361             syslog_config,
 1362             config_value,
 1363             protocol=protocol,
 1364             port=port,
 1365             reset_service=reset_service,
 1366             credstore=credstore,
 1367         )
 1368         # Ensure we don't overwrite any dictionary data already set
 1369         # By updating the host directly.
 1370         if ret.get(host) is None:
 1371             ret.update({host: {}})
 1372         ret[host].update(response)
 1373 
 1374     return ret
 1375 
 1376 
 1377 @depends(HAS_ESX_CLI)
 1378 def get_syslog_config(
 1379     host, username, password, protocol=None, port=None, esxi_hosts=None, credstore=None
 1380 ):
 1381     """
 1382     Retrieve the syslog configuration.
 1383 
 1384     host
 1385         The location of the host.
 1386 
 1387     username
 1388         The username used to login to the host, such as ``root``.
 1389 
 1390     password
 1391         The password used to login to the host.
 1392 
 1393     protocol
 1394         Optionally set to alternate protocol if the host is not using the default
 1395         protocol. Default protocol is ``https``.
 1396 
 1397     port
 1398         Optionally set to alternate port if the host is not using the default
 1399         port. Default port is ``443``.
 1400 
 1401     esxi_hosts
 1402         If ``host`` is a vCenter host, then use esxi_hosts to execute this function
 1403         on a list of one or more ESXi machines.
 1404 
 1405     credstore
 1406         Optionally set to path to the credential store file.
 1407 
 1408     :return: Dictionary with keys and values corresponding to the
 1409              syslog configuration, per host.
 1410 
 1411     CLI Example:
 1412 
 1413     .. code-block:: bash
 1414 
 1415         # Used for ESXi host connection information
 1416         salt '*' vsphere.get_syslog_config my.esxi.host root bad-password
 1417 
 1418         # Used for connecting to a vCenter Server
 1419         salt '*' vsphere.get_syslog_config my.vcenter.location root bad-password \
 1420             esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
 1421     """
 1422     cmd = "system syslog config get"
 1423 
 1424     ret = {}
 1425     if esxi_hosts:
 1426         if not isinstance(esxi_hosts, list):
 1427             raise CommandExecutionError("'esxi_hosts' must be a list.")
 1428 
 1429         for esxi_host in esxi_hosts:
 1430             response = salt.utils.vmware.esxcli(
 1431                 host,
 1432                 username,
 1433                 password,
 1434                 cmd,
 1435                 protocol=protocol,
 1436                 port=port,
 1437                 esxi_host=esxi_host,
 1438                 credstore=credstore,
 1439             )
 1440             # format the response stdout into something useful
 1441             ret.update({esxi_host: _format_syslog_config(response)})
 1442     else:
 1443         # Handles a single host or a vCenter connection when no esxi_hosts are provided.
 1444         response = salt.utils.vmware.esxcli(
 1445             host,
 1446             username,
 1447             password,
 1448             cmd,
 1449             protocol=protocol,
 1450             port=port,
 1451             credstore=credstore,
 1452         )
 1453         # format the response stdout into something useful
 1454         ret.update({host: _format_syslog_config(response)})
 1455 
 1456     return ret
 1457 
 1458 
 1459 @depends(HAS_ESX_CLI)
 1460 def reset_syslog_config(
 1461     host,
 1462     username,
 1463     password,
 1464     protocol=None,
 1465     port=None,
 1466     syslog_config=None,
 1467     esxi_hosts=None,
 1468     credstore=None,
 1469 ):
 1470     """
 1471     Reset the syslog service to its default settings.
 1472 
 1473     Valid syslog_config values are ``logdir``, ``loghost``, ``logdir-unique``,
 1474     ``default-rotate``, ``default-size``, ``default-timeout``,
 1475     or ``all`` for all of these.
 1476 
 1477     host
 1478         The location of the host.
 1479 
 1480     username
 1481         The username used to login to the host, such as ``root``.
 1482 
 1483     password
 1484         The password used to login to the host.
 1485 
 1486     protocol
 1487         Optionally set to alternate protocol if the host is not using the default
 1488         protocol. Default protocol is ``https``.
 1489 
 1490     port
 1491         Optionally set to alternate port if the host is not using the default
 1492         port. Default port is ``443``.
 1493 
 1494     syslog_config
 1495         List of parameters to reset, provided as a comma-delimited string, or 'all' to
 1496         reset all syslog configuration parameters. Required.
 1497 
 1498     esxi_hosts
 1499         If ``host`` is a vCenter host, then use esxi_hosts to execute this function
 1500         on a list of one or more ESXi machines.
 1501 
 1502     credstore
 1503         Optionally set to path to the credential store file.
 1504 
 1505     :return: Dictionary with a top-level key of 'success' which indicates
 1506              if all the parameters were reset, and individual keys
 1507              for each parameter indicating which succeeded or failed, per host.
 1508 
 1509     CLI Example:
 1510 
 1511     ``syslog_config`` can be passed as a quoted, comma-separated string, e.g.
 1512 
 1513     .. code-block:: bash
 1514 
 1515         # Used for ESXi host connection information
 1516         salt '*' vsphere.reset_syslog_config my.esxi.host root bad-password \
 1517             syslog_config='logdir,loghost'
 1518 
 1519         # Used for connecting to a vCenter Server
 1520         salt '*' vsphere.reset_syslog_config my.vcenter.location root bad-password \
 1521             syslog_config='logdir,loghost' esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
 1522     """
 1523     if not syslog_config:
 1524         raise CommandExecutionError(
 1525             "The 'reset_syslog_config' function requires a " "'syslog_config' setting."
 1526         )
 1527 
 1528     valid_resets = [
 1529         "logdir",
 1530         "loghost",
 1531         "default-rotate",
 1532         "default-size",
 1533         "default-timeout",
 1534         "logdir-unique",
 1535     ]
 1536     cmd = "system syslog config set --reset="
 1537     if "," in syslog_config:
 1538         resets = [ind_reset.strip() for ind_reset in syslog_config.split(",")]
 1539     elif syslog_config == "all":
 1540         resets = valid_resets
 1541     else:
 1542         resets = [syslog_config]
 1543 
 1544     ret = {}
 1545     if esxi_hosts:
 1546         if not isinstance(esxi_hosts, list):
 1547             raise CommandExecutionError("'esxi_hosts' must be a list.")
 1548 
 1549         for esxi_host in esxi_hosts:
 1550             response_dict = _reset_syslog_config_params(
 1551                 host,
 1552                 username,
 1553                 password,
 1554                 cmd,
 1555                 resets,
 1556                 valid_resets,
 1557                 protocol=protocol,
 1558                 port=port,
 1559                 esxi_host=esxi_host,
 1560                 credstore=credstore,
 1561             )
 1562             ret.update({esxi_host: response_dict})
 1563     else:
 1564         # Handles a single host or a vCenter connection when no esxi_hosts are provided.
 1565         response_dict = _reset_syslog_config_params(
 1566             host,
 1567             username,
 1568             password,
 1569             cmd,
 1570             resets,
 1571             valid_resets,
 1572             protocol=protocol,
 1573             port=port,
 1574             credstore=credstore,
 1575         )
 1576         ret.update({host: response_dict})
 1577 
 1578     return ret
 1579 
 1580 
 1581 @ignores_kwargs("credstore")
 1582 def upload_ssh_key(
 1583     host,
 1584     username,
 1585     password,
 1586     ssh_key=None,
 1587     ssh_key_file=None,
 1588     protocol=None,
 1589     port=None,
 1590     certificate_verify=False,
 1591 ):
 1592     """
 1593     Upload an ssh key for root to an ESXi host via http PUT.
 1594     This function only works for ESXi, not vCenter.
 1595     Only one ssh key can be uploaded for root.  Uploading a second key will
 1596     replace any existing key.
 1597 
 1598     :param host: The location of the ESXi Host
 1599     :param username: Username to connect as
 1600     :param password: Password for the ESXi web endpoint
 1601     :param ssh_key: Public SSH key, will be added to authorized_keys on ESXi
 1602     :param ssh_key_file: File containing the SSH key.  Use 'ssh_key' or
 1603                          ssh_key_file, but not both.
 1604     :param protocol: defaults to https, can be http if ssl is disabled on ESXi
 1605     :param port: defaults to 443 for https
 1606     :param certificate_verify: If true require that the SSL connection present
 1607                                a valid certificate
 1608     :return: Dictionary with a 'status' key, True if upload is successful.
 1609              If upload is unsuccessful, 'status' key will be False and
 1610              an 'Error' key will have an informative message.
 1611 
 1612     CLI Example:
 1613 
 1614     .. code-block:: bash
 1615 
 1616         salt '*' vsphere.upload_ssh_key my.esxi.host root bad-password ssh_key_file='/etc/salt/my_keys/my_key.pub'
 1617 
 1618     """
 1619     if protocol is None:
 1620         protocol = "https"
 1621     if port is None:
 1622         port = 443
 1623 
 1624     url = "{}://{}:{}/host/ssh_root_authorized_keys".format(protocol, host, port)
 1625     ret = {}
 1626     result = None
 1627     try:
 1628         if ssh_key:
 1629             result = salt.utils.http.query(
 1630                 url,
 1631                 status=True,
 1632                 text=True,
 1633                 method="PUT",
 1634                 username=username,
 1635                 password=password,
 1636                 data=ssh_key,
 1637                 verify_ssl=certificate_verify,
 1638             )
 1639         elif ssh_key_file:
 1640             result = salt.utils.http.query(
 1641                 url,
 1642                 status=True,
 1643                 text=True,
 1644                 method="PUT",
 1645                 username=username,
 1646                 password=password,
 1647                 data_file=ssh_key_file,
 1648                 data_render=False,
 1649                 verify_ssl=certificate_verify,
 1650             )
 1651         if result.get("status") == 200:
 1652             ret["status"] = True
 1653         else:
 1654             ret["status"] = False
 1655             ret["Error"] = result["error"]
 1656     except Exception as msg:  # pylint: disable=broad-except
 1657         ret["status"] = False
 1658         ret["Error"] = msg
 1659 
 1660     return ret
 1661 
 1662 
 1663 @ignores_kwargs("credstore")
 1664 def get_ssh_key(
 1665     host, username, password, protocol=None, port=None, certificate_verify=False
 1666 ):
 1667     """
 1668     Retrieve the authorized_keys entry for root.
 1669     This function only works for ESXi, not vCenter.
 1670 
 1671     :param host: The location of the ESXi Host
 1672     :param username: Username to connect as
 1673     :param password: Password for the ESXi web endpoint
 1674     :param protocol: defaults to https, can be http if ssl is disabled on ESXi
 1675     :param port: defaults to 443 for https
 1676     :param certificate_verify: If true require that the SSL connection present
 1677                                a valid certificate
 1678     :return: True if upload is successful
 1679 
 1680     CLI Example:
 1681 
 1682     .. code-block:: bash
 1683 
 1684         salt '*' vsphere.get_ssh_key my.esxi.host root bad-password certificate_verify=True
 1685 
 1686     """
 1687     if protocol is None:
 1688         protocol = "https"
 1689     if port is None:
 1690         port = 443
 1691 
 1692     url = "{}://{}:{}/host/ssh_root_authorized_keys".format(protocol, host, port)
 1693     ret = {}
 1694     try:
 1695         result = salt.utils.http.query(
 1696             url,
 1697             status=True,
 1698             text=True,
 1699             method="GET",
 1700             username=username,
 1701             password=password,
 1702             verify_ssl=certificate_verify,
 1703         )
 1704         if result.get("status") == 200:
 1705             ret["status"] = True
 1706             ret["key"] = result["text"]
 1707         else:
 1708             ret["status"] = False
 1709             ret["Error"] = result["error"]
 1710     except Exception as msg:  # pylint: disable=broad-except
 1711         ret["status"] = False
 1712         ret["Error"] = msg
 1713 
 1714     return ret
 1715 
 1716 
 1717 @depends(HAS_PYVMOMI)
 1718 @ignores_kwargs("credstore")
 1719 def get_host_datetime(
 1720     host, username, password, protocol=None, port=None, host_names=None
 1721 ):
 1722     """
 1723     Get the date/time information for a given host or list of host_names.
 1724 
 1725     host
 1726         The location of the host.
 1727 
 1728     username
 1729         The username used to login to the host, such as ``root``.
 1730 
 1731     password
 1732         The password used to login to the host.
 1733 
 1734     protocol
 1735         Optionally set to alternate protocol if the host is not using the default
 1736         protocol. Default protocol is ``https``.
 1737 
 1738     port
 1739         Optionally set to alternate port if the host is not using the default
 1740         port. Default port is ``443``.
 1741 
 1742     host_names
 1743         List of ESXi host names. When the host, username, and password credentials
 1744         are provided for a vCenter Server, the host_names argument is required to tell
 1745         vCenter the hosts for which to get date/time information.
 1746 
 1747         If host_names is not provided, the date/time information will be retrieved for the
 1748         ``host`` location instead. This is useful for when service instance connection
 1749         information is used for a single ESXi host.
 1750 
 1751     CLI Example:
 1752 
 1753     .. code-block:: bash
 1754 
 1755         # Used for single ESXi host connection information
 1756         salt '*' vsphere.get_host_datetime my.esxi.host root bad-password
 1757 
 1758         # Used for connecting to a vCenter Server
 1759         salt '*' vsphere.get_host_datetime my.vcenter.location root bad-password \
 1760         host_names='[esxi-1.host.com, esxi-2.host.com]'
 1761     """
 1762     service_instance = salt.utils.vmware.get_service_instance(
 1763         host=host, username=username, password=password, protocol=protocol, port=port
 1764     )
 1765     host_names = _check_hosts(service_instance, host, host_names)
 1766     ret = {}
 1767     for host_name in host_names:
 1768         host_ref = _get_host_ref(service_instance, host, host_name=host_name)
 1769         date_time_manager = _get_date_time_mgr(host_ref)
 1770         date_time = date_time_manager.QueryDateTime()
 1771         ret.update({host_name: date_time})
 1772 
 1773     return ret
 1774 
 1775 
 1776 @depends(HAS_PYVMOMI)
 1777 @ignores_kwargs("credstore")
 1778 def get_ntp_config(host, username, password, protocol=None, port=None, host_names=None):
 1779     """
 1780     Get the NTP configuration information for a given host or list of host_names.
 1781 
 1782     host
 1783         The location of the host.
 1784 
 1785     username
 1786         The username used to login to the host, such as ``root``.
 1787 
 1788     password
 1789         The password used to login to the host.
 1790 
 1791     protocol
 1792         Optionally set to alternate protocol if the host is not using the default
 1793         protocol. Default protocol is ``https``.
 1794 
 1795     port
 1796         Optionally set to alternate port if the host is not using the default
 1797         port. Default port is ``443``.
 1798 
 1799     host_names
 1800         List of ESXi host names. When the host, username, and password credentials
 1801         are provided for a vCenter Server, the host_names argument is required to tell
 1802         vCenter the hosts for which to get ntp configuration information.
 1803 
 1804         If host_names is not provided, the NTP configuration will be retrieved for the
 1805         ``host`` location instead. This is useful for when service instance connection
 1806         information is used for a single ESXi host.
 1807 
 1808     CLI Example:
 1809 
 1810     .. code-block:: bash
 1811 
 1812         # Used for single ESXi host connection information
 1813         salt '*' vsphere.get_ntp_config my.esxi.host root bad-password
 1814 
 1815         # Used for connecting to a vCenter Server
 1816         salt '*' vsphere.get_ntp_config my.vcenter.location root bad-password \
 1817         host_names='[esxi-1.host.com, esxi-2.host.com]'
 1818     """
 1819     service_instance = salt.utils.vmware.get_service_instance(
 1820         host=host, username=username, password=password, protocol=protocol, port=port
 1821     )
 1822     host_names = _check_hosts(service_instance, host, host_names)
 1823     ret = {}
 1824     for host_name in host_names:
 1825         host_ref = _get_host_ref(service_instance, host, host_name=host_name)
 1826         ntp_config = host_ref.configManager.dateTimeSystem.dateTimeInfo.ntpConfig.server
 1827         ret.update({host_name: ntp_config})
 1828 
 1829     return ret
 1830 
 1831 
 1832 @depends(HAS_PYVMOMI)
 1833 @ignores_kwargs("credstore")
 1834 def get_service_policy(
 1835     host, username, password, service_name, protocol=None, port=None, host_names=None
 1836 ):
 1837     """
 1838     Get the service name's policy for a given host or list of hosts.
 1839 
 1840     host
 1841         The location of the host.
 1842 
 1843     username
 1844         The username used to login to the host, such as ``root``.
 1845 
 1846     password
 1847         The password used to login to the host.
 1848 
 1849     service_name
 1850         The name of the service for which to retrieve the policy. Supported service names are:
 1851           - DCUI
 1852           - TSM
 1853           - SSH
 1854           - lbtd
 1855           - lsassd
 1856           - lwiod
 1857           - netlogond
 1858           - ntpd
 1859           - sfcbd-watchdog
 1860           - snmpd
 1861           - vprobed
 1862           - vpxa
 1863           - xorg
 1864 
 1865     protocol
 1866         Optionally set to alternate protocol if the host is not using the default
 1867         protocol. Default protocol is ``https``.
 1868 
 1869     port
 1870         Optionally set to alternate port if the host is not using the default
 1871         port. Default port is ``443``.
 1872 
 1873     host_names
 1874         List of ESXi host names. When the host, username, and password credentials
 1875         are provided for a vCenter Server, the host_names argument is required to tell
 1876         vCenter the hosts for which to get service policy information.
 1877 
 1878         If host_names is not provided, the service policy information will be retrieved
 1879         for the ``host`` location instead. This is useful for when service instance
 1880         connection information is used for a single ESXi host.
 1881 
 1882     CLI Example:
 1883 
 1884     .. code-block:: bash
 1885 
 1886         # Used for single ESXi host connection information
 1887         salt '*' vsphere.get_service_policy my.esxi.host root bad-password 'ssh'
 1888 
 1889         # Used for connecting to a vCenter Server
 1890         salt '*' vsphere.get_service_policy my.vcenter.location root bad-password 'ntpd' \
 1891         host_names='[esxi-1.host.com, esxi-2.host.com]'
 1892     """
 1893     service_instance = salt.utils.vmware.get_service_instance(
 1894         host=host, username=username, password=password, protocol=protocol, port=port
 1895     )
 1896     valid_services = [
 1897         "DCUI",
 1898         "TSM",
 1899         "SSH",
 1900         "ssh",
 1901         "lbtd",
 1902         "lsassd",
 1903         "lwiod",
 1904         "netlogond",
 1905         "ntpd",
 1906         "sfcbd-watchdog",
 1907         "snmpd",
 1908         "vprobed",
 1909         "vpxa",
 1910         "xorg",
 1911     ]
 1912     host_names = _check_hosts(service_instance, host, host_names)
 1913 
 1914     ret = {}
 1915     for host_name in host_names:
 1916         # Check if the service_name provided is a valid one.
 1917         # If we don't have a valid service, return. The service will be invalid for all hosts.
 1918         if service_name not in valid_services:
 1919             ret.update(
 1920                 {
 1921                     host_name: {
 1922                         "Error": "{} is not a valid service name.".format(service_name)
 1923                     }
 1924                 }
 1925             )
 1926             return ret
 1927 
 1928         host_ref = _get_host_ref(service_instance, host, host_name=host_name)
 1929         services = host_ref.configManager.serviceSystem.serviceInfo.service
 1930 
 1931         # Don't require users to know that VMware lists the ssh service as TSM-SSH
 1932         if service_name == "SSH" or service_name == "ssh":
 1933             temp_service_name = "TSM-SSH"
 1934         else:
 1935             temp_service_name = service_name
 1936 
 1937         # Loop through services until we find a matching name
 1938         for service in services:
 1939             if service.key == temp_service_name:
 1940                 ret.update({host_name: {service_name: service.policy}})
 1941                 # We've found a match - break out of the loop so we don't overwrite the
 1942                 # Updated host_name value with an error message.
 1943                 break
 1944             else:
 1945                 msg = "Could not find service '{}' for host '{}'.".format(
 1946                     service_name, host_name
 1947                 )
 1948                 ret.update({host_name: {"Error": msg}})
 1949 
 1950         # If we made it this far, something else has gone wrong.
 1951         if ret.get(host_name) is None:
 1952             msg = "'vsphere.get_service_policy' failed for host {}.".format(host_name)
 1953             log.debug(msg)
 1954             ret.update({host_name: {"Error": msg}})
 1955 
 1956     return ret
 1957 
 1958 
 1959 @depends(HAS_PYVMOMI)
 1960 @ignores_kwargs("credstore")
 1961 def get_service_running(
 1962     host, username, password, service_name, protocol=None, port=None, host_names=None
 1963 ):
 1964     """
 1965     Get the service name's running state for a given host or list of hosts.
 1966 
 1967     host
 1968         The location of the host.
 1969 
 1970     username
 1971         The username used to login to the host, such as ``root``.
 1972 
 1973     password
 1974         The password used to login to the host.
 1975 
 1976     service_name
 1977         The name of the service for which to retrieve the policy. Supported service names are:
 1978           - DCUI
 1979           - TSM
 1980           - SSH
 1981           - lbtd
 1982           - lsassd
 1983           - lwiod
 1984           - netlogond
 1985           - ntpd
 1986           - sfcbd-watchdog
 1987           - snmpd
 1988           - vprobed
 1989           - vpxa
 1990           - xorg
 1991 
 1992     protocol
 1993         Optionally set to alternate protocol if the host is not using the default
 1994         protocol. Default protocol is ``https``.
 1995 
 1996     port
 1997         Optionally set to alternate port if the host is not using the default
 1998         port. Default port is ``443``.
 1999 
 2000     host_names
 2001         List of ESXi host names. When the host, username, and password credentials
 2002         are provided for a vCenter Server, the host_names argument is required to tell
 2003         vCenter the hosts for which to get the service's running state.
 2004 
 2005         If host_names is not provided, the service's running state will be retrieved
 2006         for the ``host`` location instead. This is useful for when service instance
 2007         connection information is used for a single ESXi host.
 2008 
 2009     CLI Example:
 2010 
 2011     .. code-block:: bash
 2012 
 2013         # Used for single ESXi host connection information
 2014         salt '*' vsphere.get_service_running my.esxi.host root bad-password 'ssh'
 2015 
 2016         # Used for connecting to a vCenter Server
 2017         salt '*' vsphere.get_service_running my.vcenter.location root bad-password 'ntpd' \
 2018         host_names='[esxi-1.host.com, esxi-2.host.com]'
 2019     """
 2020     service_instance = salt.utils.vmware.get_service_instance(
 2021         host=host, username=username, password=password, protocol=protocol, port=port
 2022     )
 2023     valid_services = [
 2024         "DCUI",
 2025         "TSM",
 2026         "SSH",
 2027         "ssh",
 2028         "lbtd",
 2029         "lsassd",
 2030         "lwiod",
 2031         "netlogond",
 2032         "ntpd",
 2033         "sfcbd-watchdog",
 2034         "snmpd",
 2035         "vprobed",
 2036         "vpxa",
 2037         "xorg",
 2038     ]
 2039     host_names = _check_hosts(service_instance, host, host_names)
 2040 
 2041     ret = {}
 2042     for host_name in host_names:
 2043         # Check if the service_name provided is a valid one.
 2044         # If we don't have a valid service, return. The service will be invalid for all hosts.
 2045         if service_name not in valid_services:
 2046             ret.update(
 2047                 {
 2048                     host_name: {
 2049                         "Error": "{} is not a valid service name.".format(service_name)
 2050                     }
 2051                 }
 2052             )
 2053             return ret
 2054 
 2055         host_ref = _get_host_ref(service_instance, host, host_name=host_name)
 2056         services = host_ref.configManager.serviceSystem.serviceInfo.service
 2057 
 2058         # Don't require users to know that VMware lists the ssh service as TSM-SSH
 2059         if service_name == "SSH" or service_name == "ssh":
 2060             temp_service_name = "TSM-SSH"
 2061         else:
 2062             temp_service_name = service_name
 2063 
 2064         # Loop through services until we find a matching name
 2065         for service in services:
 2066             if service.key == temp_service_name:
 2067                 ret.update({host_name: {service_name: service.running}})
 2068                 # We've found a match - break out of the loop so we don't overwrite the
 2069                 # Updated host_name value with an error message.
 2070                 break
 2071             else:
 2072                 msg = "Could not find service '{}' for host '{}'.".format(
 2073                     service_name, host_name
 2074                 )
 2075                 ret.update({host_name: {"Error": msg}})
 2076 
 2077         # If we made it this far, something else has gone wrong.
 2078         if ret.get(host_name) is None:
 2079             msg = "'vsphere.get_service_running' failed for host {}.".format(host_name)
 2080             log.debug(msg)
 2081             ret.update({host_name: {"Error": msg}})
 2082 
 2083     return ret
 2084 
 2085 
 2086 @depends(HAS_PYVMOMI)
 2087 @ignores_kwargs("credstore")
 2088 def get_vmotion_enabled(
 2089     host, username, password, protocol=None, port=None, host_names=None
 2090 ):
 2091     """
 2092     Get the VMotion enabled status for a given host or a list of host_names. Returns ``True``
 2093     if VMotion is enabled, ``False`` if it is not enabled.
 2094 
 2095     host
 2096         The location of the host.
 2097 
 2098     username
 2099         The username used to login to the host, such as ``root``.
 2100 
 2101     password
 2102         The password used to login to the host.
 2103 
 2104     protocol
 2105         Optionally set to alternate protocol if the host is not using the default
 2106         protocol. Default protocol is ``https``.
 2107 
 2108     port
 2109         Optionally set to alternate port if the host is not using the default
 2110         port. Default port is ``443``.
 2111 
 2112     host_names
 2113         List of ESXi host names. When the host, username, and password credentials
 2114         are provided for a vCenter Server, the host_names argument is required to
 2115         tell vCenter which hosts to check if VMotion is enabled.
 2116 
 2117         If host_names is not provided, the VMotion status will be retrieved for the
 2118         ``host`` location instead. This is useful for when service instance
 2119         connection information is used for a single ESXi host.
 2120 
 2121     CLI Example:
 2122 
 2123     .. code-block:: bash
 2124 
 2125         # Used for single ESXi host connection information
 2126         salt '*' vsphere.get_vmotion_enabled my.esxi.host root bad-password
 2127 
 2128         # Used for connecting to a vCenter Server
 2129         salt '*' vsphere.get_vmotion_enabled my.vcenter.location root bad-password \
 2130         host_names='[esxi-1.host.com, esxi-2.host.com]'
 2131     """
 2132     service_instance = salt.utils.vmware.get_service_instance(
 2133         host=host, username=username, password=password, protocol=protocol, port=port
 2134     )
 2135     host_names = _check_hosts(service_instance, host, host_names)
 2136     ret = {}
 2137     for host_name in host_names:
 2138         host_ref = _get_host_ref(service_instance, host, host_name=host_name)
 2139         vmotion_vnic = host_ref.configManager.vmotionSystem.netConfig.selectedVnic
 2140         if vmotion_vnic:
 2141             ret.update({host_name: {"VMotion Enabled": True}})
 2142         else:
 2143             ret.update({host_name: {"VMotion Enabled": False}})
 2144 
 2145     return ret
 2146 
 2147 
 2148 @depends(HAS_PYVMOMI)
 2149 @ignores_kwargs("credstore")
 2150 def get_vsan_enabled(
 2151     host, username, password, protocol=None, port=None, host_names=None
 2152 ):
 2153     """
 2154     Get the VSAN enabled status for a given host or a list of host_names. Returns ``True``
 2155     if VSAN is enabled, ``False`` if it is not enabled, and ``None`` if a VSAN Host Config
 2156     is unset, per host.
 2157 
 2158     host
 2159         The location of the host.
 2160 
 2161     username
 2162         The username used to login to the host, such as ``root``.
 2163 
 2164     password
 2165         The password used to login to the host.
 2166 
 2167     protocol
 2168         Optionally set to alternate protocol if the host is not using the default
 2169         protocol. Default protocol is ``https``.
 2170 
 2171     port
 2172         Optionally set to alternate port if the host is not using the default
 2173         port. Default port is ``443``.
 2174 
 2175     host_names
 2176         List of ESXi host names. When the host, username, and password credentials
 2177         are provided for a vCenter Server, the host_names argument is required to
 2178         tell vCenter which hosts to check if VSAN enabled.
 2179 
 2180         If host_names is not provided, the VSAN status will be retrieved for the
 2181         ``host`` location instead. This is useful for when service instance
 2182         connection information is used for a single ESXi host.
 2183 
 2184     CLI Example:
 2185 
 2186     .. code-block:: bash
 2187 
 2188         # Used for single ESXi host connection information
 2189         salt '*' vsphere.get_vsan_enabled my.esxi.host root bad-password
 2190 
 2191         # Used for connecting to a vCenter Server
 2192         salt '*' vsphere.get_vsan_enabled my.vcenter.location root bad-password \
 2193         host_names='[esxi-1.host.com, esxi-2.host.com]'
 2194     """
 2195     service_instance = salt.utils.vmware.get_service_instance(
 2196         host=host, username=username, password=password, protocol=protocol, port=port
 2197     )
 2198     host_names = _check_hosts(service_instance, host, host_names)
 2199     ret = {}
 2200     for host_name in host_names:
 2201         host_ref = _get_host_ref(service_instance, host, host_name=host_name)
 2202         vsan_config = host_ref.config.vsanHostConfig
 2203 
 2204         # We must have a VSAN Config in place get information about VSAN state.
 2205         if vsan_config is None:
 2206             msg = "VSAN System Config Manager is unset for host '{}'.".format(host_name)
 2207             log.debug(msg)
 2208             ret.update({host_name: {"Error": msg}})
 2209         else:
 2210             ret.update({host_name: {"VSAN Enabled": vsan_config.enabled}})
 2211 
 2212     return ret
 2213 
 2214 
 2215 @depends(HAS_PYVMOMI)
 2216 @ignores_kwargs("credstore")
 2217 def get_vsan_eligible_disks(
 2218     host, username, password, protocol=None, port=None, host_names=None
 2219 ):
 2220     """
 2221     Returns a list of VSAN-eligible disks for a given host or list of host_names.
 2222 
 2223     host
 2224         The location of the host.
 2225 
 2226     username
 2227         The username used to login to the host, such as ``root``.
 2228 
 2229     password
 2230         The password used to login to the host.
 2231 
 2232     protocol
 2233         Optionally set to alternate protocol if the host is not using the default
 2234         protocol. Default protocol is ``https``.
 2235 
 2236     port
 2237         Optionally set to alternate port if the host is not using the default
 2238         port. Default port is ``443``.
 2239 
 2240     host_names
 2241         List of ESXi host names. When the host, username, and password credentials
 2242         are provided for a vCenter Server, the host_names argument is required to
 2243         tell vCenter which hosts to check if any VSAN-eligible disks are available.
 2244 
 2245         If host_names is not provided, the VSAN-eligible disks will be retrieved
 2246         for the ``host`` location instead. This is useful for when service instance
 2247         connection information is used for a single ESXi host.
 2248 
 2249     CLI Example:
 2250 
 2251     .. code-block:: bash
 2252 
 2253         # Used for single ESXi host connection information
 2254         salt '*' vsphere.get_vsan_eligible_disks my.esxi.host root bad-password
 2255 
 2256         # Used for connecting to a vCenter Server
 2257         salt '*' vsphere.get_vsan_eligible_disks my.vcenter.location root bad-password \
 2258         host_names='[esxi-1.host.com, esxi-2.host.com]'
 2259     """
 2260     service_instance = salt.utils.vmware.get_service_instance(
 2261         host=host, username=username, password=password, protocol=protocol, port=port
 2262     )
 2263     host_names = _check_hosts(service_instance, host, host_names)
 2264     response = _get_vsan_eligible_disks(service_instance, host, host_names)
 2265 
 2266     ret = {}
 2267     for host_name, value in response.items():
 2268         error = value.get("Error")
 2269         if error:
 2270             ret.update({host_name: {"Error": error}})
 2271             continue
 2272 
 2273         disks = value.get("Eligible")
 2274         # If we have eligible disks, it will be a list of disk objects
 2275         if disks and isinstance(disks, list):
 2276             disk_names = []
 2277             # We need to return ONLY the disk names, otherwise
 2278             # MessagePack can't deserialize the disk objects.
 2279             for disk in disks:
 2280                 disk_names.append(disk.canonicalName)
 2281             ret.update({host_name: {"Eligible": disk_names}})
 2282         else:
 2283             # If we have disks, but it's not a list, it's actually a
 2284             # string message that we're passing along.
 2285             ret.update({host_name: {"Eligible": disks}})
 2286 
 2287     return ret
 2288 
 2289 
 2290 @depends(HAS_PYVMOMI)
 2291 @supports_proxies("esxi", "esxcluster", "esxdatacenter", "vcenter", "esxvm")
 2292 @gets_service_instance_via_proxy
 2293 def test_vcenter_connection(service_instance=None):
 2294     """
 2295     Checks if a connection is to a vCenter
 2296 
 2297     CLI Example:
 2298 
 2299     .. code-block:: bash
 2300 
 2301         salt '*' vsphere.test_vcenter_connection
 2302     """
 2303     try:
 2304         if salt.utils.vmware.is_connection_to_a_vcenter(service_instance):
 2305             return True
 2306     except VMwareSaltError:
 2307         return False
 2308     return False
 2309 
 2310 
 2311 @depends(HAS_PYVMOMI)
 2312 @ignores_kwargs("credstore")
 2313 def system_info(host, username, password, protocol=None, port=None):
 2314     """
 2315     Return system information about a VMware environment.
 2316 
 2317     host
 2318         The location of the host.
 2319 
 2320     username
 2321         The username used to login to the host, such as ``root``.
 2322 
 2323     password
 2324         The password used to login to the host.
 2325 
 2326     protocol
 2327         Optionally set to alternate protocol if the host is not using the default
 2328         protocol. Default protocol is ``https``.
 2329 
 2330     port
 2331         Optionally set to alternate port if the host is not using the default
 2332         port. Default port is ``443``.
 2333 
 2334     CLI Example:
 2335 
 2336     .. code-block:: bash
 2337 
 2338         salt '*' vsphere.system_info 1.2.3.4 root bad-password
 2339     """
 2340     service_instance = salt.utils.vmware.get_service_instance(
 2341         host=host, username=username, password=password, protocol=protocol, port=port
 2342     )
 2343     ret = salt.utils.vmware.get_inventory(service_instance).about.__dict__
 2344     if "apiType" in ret:
 2345         if ret["apiType"] == "HostAgent":
 2346             ret = dictupdate.update(
 2347                 ret, salt.utils.vmware.get_hardware_grains(service_instance)
 2348             )
 2349     return ret
 2350 
 2351 
 2352 @depends(HAS_PYVMOMI)
 2353 @ignores_kwargs("credstore")
 2354 def list_datacenters(host, username, password, protocol=None, port=None):
 2355     """
 2356     Returns a list of datacenters for the specified host.
 2357 
 2358     host
 2359         The location of the host.
 2360 
 2361     username
 2362         The username used to login to the host, such as ``root``.
 2363 
 2364     password
 2365         The password used to login to the host.
 2366 
 2367     protocol
 2368         Optionally set to alternate protocol if the host is not using the default
 2369         protocol. Default protocol is ``https``.
 2370 
 2371     port
 2372         Optionally set to alternate port if the host is not using the default
 2373         port. Default port is ``443``.
 2374 
 2375     CLI Example:
 2376 
 2377     .. code-block:: bash
 2378 
 2379         salt '*' vsphere.list_datacenters 1.2.3.4 root bad-password
 2380 
 2381     """
 2382     service_instance = salt.utils.vmware.get_service_instance(
 2383         host=host, username=username, password=password, protocol=protocol, port=port
 2384     )
 2385     return salt.utils.vmware.list_datacenters(service_instance)
 2386 
 2387 
 2388 @depends(HAS_PYVMOMI)
 2389 @ignores_kwargs("credstore")
 2390 def list_clusters(host, username, password, protocol=None, port=None):
 2391     """
 2392     Returns a list of clusters for the specified host.
 2393 
 2394     host
 2395         The location of the host.
 2396 
 2397     username
 2398         The username used to login to the host, such as ``root``.
 2399 
 2400     password
 2401         The password used to login to the host.
 2402 
 2403     protocol
 2404         Optionally set to alternate protocol if the host is not using the default
 2405         protocol. Default protocol is ``https``.
 2406 
 2407     port
 2408         Optionally set to alternate port if the host is not using the default
 2409         port. Default port is ``443``.
 2410 
 2411     CLI Example:
 2412 
 2413     .. code-block:: bash
 2414 
 2415         salt '*' vsphere.list_clusters 1.2.3.4 root bad-password
 2416 
 2417     """
 2418     service_instance = salt.utils.vmware.get_service_instance(
 2419         host=host, username=username, password=password, protocol=protocol, port=port
 2420     )
 2421     return salt.utils.vmware.list_clusters(service_instance)
 2422 
 2423 
 2424 @depends(HAS_PYVMOMI)
 2425 @ignores_kwargs("credstore")
 2426 def list_datastore_clusters(host, username, password, protocol=None, port=None):
 2427     """
 2428     Returns a list of datastore clusters for the specified host.
 2429 
 2430     host
 2431         The location of the host.
 2432 
 2433     username
 2434         The username used to login to the host, such as ``root``.
 2435 
 2436     password
 2437         The password used to login to the host.
 2438 
 2439     protocol
 2440         Optionally set to alternate protocol if the host is not using the default
 2441         protocol. Default protocol is ``https``.
 2442 
 2443     port
 2444         Optionally set to alternate port if the host is not using the default
 2445         port. Default port is ``443``.
 2446 
 2447     CLI Example:
 2448 
 2449     .. code-block:: bash
 2450 
 2451         salt '*' vsphere.list_datastore_clusters 1.2.3.4 root bad-password
 2452     """
 2453     service_instance = salt.utils.vmware.get_service_instance(
 2454         host=host, username=username, password=password, protocol=protocol, port=port
 2455     )
 2456     return salt.utils.vmware.list_datastore_clusters(service_instance)
 2457 
 2458 
 2459 @depends(HAS_PYVMOMI)
 2460 @ignores_kwargs("credstore")
 2461 def list_datastores(host, username, password, protocol=None, port=None):
 2462     """
 2463     Returns a list of datastores for the specified host.
 2464 
 2465     host
 2466         The location of the host.
 2467 
 2468     username
 2469         The username used to login to the host, such as ``root``.
 2470 
 2471     password
 2472         The password used to login to the host.
 2473 
 2474     protocol
 2475         Optionally set to alternate protocol if the host is not using the default
 2476         protocol. Default protocol is ``https``.
 2477 
 2478     port
 2479         Optionally set to alternate port if the host is not using the default
 2480         port. Default port is ``443``.
 2481 
 2482     CLI Example:
 2483 
 2484     .. code-block:: bash
 2485 
 2486         salt '*' vsphere.list_datastores 1.2.3.4 root bad-password
 2487     """
 2488     service_instance = salt.utils.vmware.get_service_instance(
 2489         host=host, username=username, password=password, protocol=protocol, port=port
 2490     )
 2491     return salt.utils.vmware.list_datastores(service_instance)
 2492 
 2493 
 2494 @depends(HAS_PYVMOMI)
 2495 @ignores_kwargs("credstore")
 2496 def list_hosts(host, username, password, protocol=None, port=None):
 2497     """
 2498     Returns a list of hosts for the specified VMware environment.
 2499 
 2500     host
 2501         The location of the host.
 2502 
 2503     username
 2504         The username used to login to the host, such as ``root``.
 2505 
 2506     password
 2507         The password used to login to the host.
 2508 
 2509     protocol
 2510         Optionally set to alternate protocol if the host is not using the default
 2511         protocol. Default protocol is ``https``.
 2512 
 2513     port
 2514         Optionally set to alternate port if the host is not using the default
 2515         port. Default port is ``443``.
 2516 
 2517     CLI Example:
 2518 
 2519     .. code-block:: bash
 2520 
 2521         salt '*' vsphere.list_hosts 1.2.3.4 root bad-password
 2522     """
 2523     service_instance = salt.utils.vmware.get_service_instance(
 2524         host=host, username=username, password=password, protocol=protocol, port=port
 2525     )
 2526     return salt.utils.vmware.list_hosts(service_instance)
 2527 
 2528 
 2529 @depends(HAS_PYVMOMI)
 2530 @ignores_kwargs("credstore")
 2531 def list_resourcepools(host, username, password, protocol=None, port=None):
 2532     """
 2533     Returns a list of resource pools for the specified host.
 2534 
 2535     host
 2536         The location of the host.
 2537 
 2538     username
 2539         The username used to login to the host, such as ``root``.
 2540 
 2541     password
 2542         The password used to login to the host.
 2543 
 2544     protocol
 2545         Optionally set to alternate protocol if the host is not using the default
 2546         protocol. Default protocol is ``https``.
 2547 
 2548     port
 2549         Optionally set to alternate port if the host is not using the default
 2550         port. Default port is ``443``.
 2551 
 2552     CLI Example:
 2553 
 2554     .. code-block:: bash
 2555 
 2556         salt '*' vsphere.list_resourcepools 1.2.3.4 root bad-password
 2557     """
 2558     service_instance = salt.utils.vmware.get_service_instance(
 2559         host=host, username=username, password=password, protocol=protocol, port=port
 2560     )
 2561     return salt.utils.vmware.list_resourcepools(service_instance)
 2562 
 2563 
 2564 @depends(HAS_PYVMOMI)
 2565 @ignores_kwargs("credstore")
 2566 def list_networks(host, username, password, protocol=None, port=None):
 2567     """
 2568     Returns a list of networks for the specified host.
 2569 
 2570     host
 2571         The location of the host.
 2572 
 2573     username
 2574         The username used to login to the host, such as ``root``.
 2575 
 2576     password
 2577         The password used to login to the host.
 2578 
 2579     protocol
 2580         Optionally set to alternate protocol if the host is not using the default
 2581         protocol. Default protocol is ``https``.
 2582 
 2583     port
 2584         Optionally set to alternate port if the host is not using the default
 2585         port. Default port is ``443``.
 2586 
 2587     CLI Example:
 2588 
 2589     .. code-block:: bash
 2590 
 2591         salt '*' vsphere.list_networks 1.2.3.4 root bad-password
 2592     """
 2593     service_instance = salt.utils.vmware.get_service_instance(
 2594         host=host, username=username, password=password, protocol=protocol, port=port
 2595     )
 2596     return salt.utils.vmware.list_networks(service_instance)
 2597 
 2598 
 2599 @depends(HAS_PYVMOMI)
 2600 @ignores_kwargs("credstore")
 2601 def list_vms(host, username, password, protocol=None, port=None):
 2602     """
 2603     Returns a list of VMs for the specified host.
 2604 
 2605     host
 2606         The location of the host.
 2607 
 2608     username
 2609         The username used to login to the host, such as ``root``.
 2610 
 2611     password
 2612         The password used to login to the host.
 2613 
 2614     protocol
 2615         Optionally set to alternate protocol if the host is not using the default
 2616         protocol. Default protocol is ``https``.
 2617 
 2618     port
 2619         Optionally set to alternate port if the host is not using the default
 2620         port. Default port is ``443``.
 2621 
 2622     CLI Example:
 2623 
 2624     .. code-block:: bash
 2625 
 2626         salt '*' vsphere.list_vms 1.2.3.4 root bad-password
 2627     """
 2628     service_instance = salt.utils.vmware.get_service_instance(
 2629         host=host, username=username, password=password, protocol=protocol, port=port
 2630     )
 2631     return salt.utils.vmware.list_vms(service_instance)
 2632 
 2633 
 2634 @depends(HAS_PYVMOMI)
 2635 @ignores_kwargs("credstore")
 2636 def list_folders(host, username, password, protocol=None, port=None):
 2637     """
 2638     Returns a list of folders for the specified host.
 2639 
 2640     host
 2641         The location of the host.
 2642 
 2643     username
 2644         The username used to login to the host, such as ``root``.
 2645 
 2646     password
 2647         The password used to login to the host.
 2648 
 2649     protocol
 2650         Optionally set to alternate protocol if the host is not using the default
 2651         protocol. Default protocol is ``https``.
 2652 
 2653     port
 2654         Optionally set to alternate port if the host is not using the default
 2655         port. Default port is ``443``.
 2656 
 2657     CLI Example:
 2658 
 2659     .. code-block:: bash
 2660 
 2661         salt '*' vsphere.list_folders 1.2.3.4 root bad-password
 2662     """
 2663     service_instance = salt.utils.vmware.get_service_instance(
 2664         host=host, username=username, password=password, protocol=protocol, port=port
 2665     )
 2666     return salt.utils.vmware.list_folders(service_instance)
 2667 
 2668 
 2669 @depends(HAS_PYVMOMI)
 2670 @ignores_kwargs("credstore")
 2671 def list_dvs(host, username, password, protocol=None, port=None):
 2672     """
 2673     Returns a list of distributed virtual switches for the specified host.
 2674 
 2675     host
 2676         The location of the host.
 2677 
 2678     username
 2679         The username used to login to the host, such as ``root``.
 2680 
 2681     password
 2682         The password used to login to the host.
 2683 
 2684     protocol
 2685         Optionally set to alternate protocol if the host is not using the default
 2686         protocol. Default protocol is ``https``.
 2687 
 2688     port
 2689         Optionally set to alternate port if the host is not using the default
 2690         port. Default port is ``443``.
 2691 
 2692     CLI Example:
 2693 
 2694     .. code-block:: bash
 2695 
 2696         salt '*' vsphere.list_dvs 1.2.3.4 root bad-password
 2697     """
 2698     service_instance = salt.utils.vmware.get_service_instance(
 2699         host=host, username=username, password=password, protocol=protocol, port=port
 2700     )
 2701     return salt.utils.vmware.list_dvs(service_instance)
 2702 
 2703 
 2704 @depends(HAS_PYVMOMI)
 2705 @ignores_kwargs("credstore")
 2706 def list_vapps(host, username, password, protocol=None, port=None):
 2707     """
 2708     Returns a list of vApps for the specified host.
 2709 
 2710     host
 2711         The location of the host.
 2712 
 2713     username
 2714         The username used to login to the host, such as ``root``.
 2715 
 2716     password
 2717         The password used to login to the host.
 2718 
 2719     protocol
 2720         Optionally set to alternate protocol if the host is not using the default
 2721         protocol. Default protocol is ``https``.
 2722 
 2723     port
 2724         Optionally set to alternate port if the host is not using the default
 2725         port. Default port is ``443``.
 2726 
 2727     CLI Example:
 2728 
 2729     .. code-block:: bash
 2730 
 2731         # List vapps from all minions
 2732         salt '*' vsphere.list_vapps 1.2.3.4 root bad-password
 2733     """
 2734     service_instance = salt.utils.vmware.get_service_instance(
 2735         host=host, username=username, password=password, protocol=protocol, port=port
 2736     )
 2737     return salt.utils.vmware.list_vapps(service_instance)
 2738 
 2739 
 2740 @depends(HAS_PYVMOMI)
 2741 @ignores_kwargs("credstore")
 2742 def list_ssds(host, username, password, protocol=None, port=None, host_names=None):
 2743     """
 2744     Returns a list of SSDs for the given host or list of host_names.
 2745 
 2746     host
 2747         The location of the host.
 2748 
 2749     username
 2750         The username used to login to the host, such as ``root``.
 2751 
 2752     password
 2753         The password used to login to the host.
 2754 
 2755     protocol
 2756         Optionally set to alternate protocol if the host is not using the default
 2757         protocol. Default protocol is ``https``.
 2758 
 2759     port
 2760         Optionally set to alternate port if the host is not using the default
 2761         port. Default port is ``443``.
 2762 
 2763     host_names
 2764         List of ESXi host names. When the host, username, and password credentials
 2765         are provided for a vCenter Server, the host_names argument is required to
 2766         tell vCenter the hosts for which to retrieve SSDs.
 2767 
 2768         If host_names is not provided, SSDs will be retrieved for the
 2769         ``host`` location instead. This is useful for when service instance
 2770         connection information is used for a single ESXi host.
 2771 
 2772     CLI Example:
 2773 
 2774     .. code-block:: bash
 2775 
 2776         # Used for single ESXi host connection information
 2777         salt '*' vsphere.list_ssds my.esxi.host root bad-password
 2778 
 2779         # Used for connecting to a vCenter Server
 2780         salt '*' vsphere.list_ssds my.vcenter.location root bad-password \
 2781         host_names='[esxi-1.host.com, esxi-2.host.com]'
 2782     """
 2783     service_instance = salt.utils.vmware.get_service_instance(
 2784         host=host, username=username, password=password, protocol=protocol, port=port
 2785     )
 2786     host_names = _check_hosts(service_instance, host, host_names)
 2787     ret = {}
 2788     names = []
 2789     for host_name in host_names:
 2790         host_ref = _get_host_ref(service_instance, host, host_name=host_name)
 2791         disks = _get_host_ssds(host_ref)
 2792         for disk in disks:
 2793             names.append(disk.canonicalName)
 2794         ret.update({host_name: names})
 2795 
 2796     return ret
 2797 
 2798 
 2799 @depends(HAS_PYVMOMI)
 2800 @ignores_kwargs("credstore")
 2801 def list_non_ssds(host, username, password, protocol=None, port=None, host_names=None):
 2802     """
 2803     Returns a list of Non-SSD disks for the given host or list of host_names.
 2804 
 2805     .. note::
 2806 
 2807         In the pyVmomi StorageSystem, ScsiDisks may, or may not have an ``ssd`` attribute.
 2808         This attribute indicates if the ScsiDisk is SSD backed. As this option is optional,
 2809         if a relevant disk in the StorageSystem does not have ``ssd = true``, it will end
 2810         up in the ``non_ssds`` list here.
 2811 
 2812     host
 2813         The location of the host.
 2814 
 2815     username
 2816         The username used to login to the host, such as ``root``.
 2817 
 2818     password
 2819         The password used to login to the host.
 2820 
 2821     protocol
 2822         Optionally set to alternate protocol if the host is not using the default
 2823         protocol. Default protocol is ``https``.
 2824 
 2825     port
 2826         Optionally set to alternate port if the host is not using the default
 2827         port. Default port is ``443``.
 2828 
 2829     host_names
 2830         List of ESXi host names. When the host, username, and password credentials
 2831         are provided for a vCenter Server, the host_names argument is required to
 2832         tell vCenter the hosts for which to retrieve Non-SSD disks.
 2833 
 2834         If host_names is not provided, Non-SSD disks will be retrieved for the
 2835         ``host`` location instead. This is useful for when service instance
 2836         connection information is used for a single ESXi host.
 2837 
 2838     CLI Example:
 2839 
 2840     .. code-block:: bash
 2841 
 2842         # Used for single ESXi host connection information
 2843         salt '*' vsphere.list_non_ssds my.esxi.host root bad-password
 2844 
 2845         # Used for connecting to a vCenter Server
 2846         salt '*' vsphere.list_non_ssds my.vcenter.location root bad-password \
 2847         host_names='[esxi-1.host.com, esxi-2.host.com]'
 2848     """
 2849     service_instance = salt.utils.vmware.get_service_instance(
 2850         host=host, username=username, password=password, protocol=protocol, port=port
 2851     )
 2852     host_names = _check_hosts(service_instance, host, host_names)
 2853     ret = {}
 2854     names = []
 2855     for host_name in host_names:
 2856         host_ref = _get_host_ref(service_instance, host, host_name=host_name)
 2857         disks = _get_host_non_ssds(host_ref)
 2858         for disk in disks:
 2859             names.append(disk.canonicalName)
 2860         ret.update({host_name: names})
 2861 
 2862     return ret
 2863 
 2864 
 2865 @depends(HAS_PYVMOMI)
 2866 @ignores_kwargs("credstore")
 2867 def set_ntp_config(
 2868     host, username, password, ntp_servers, protocol=None, port=None, host_names=None
 2869 ):
 2870     """
 2871     Set NTP configuration for a given host of list of host_names.
 2872 
 2873     host
 2874         The location of the host.
 2875 
 2876     username
 2877         The username used to login to the host, such as ``root``.
 2878 
 2879     password
 2880         The password used to login to the host.
 2881 
 2882     ntp_servers
 2883         A list of servers that should be added to and configured for the specified
 2884         host's NTP configuration.
 2885 
 2886     protocol
 2887         Optionally set to alternate protocol if the host is not using the default
 2888         protocol. Default protocol is ``https``.
 2889 
 2890     port
 2891         Optionally set to alternate port if the host is not using the default
 2892         port. Default port is ``443``.
 2893 
 2894     host_names
 2895         List of ESXi host names. When the host, username, and password credentials
 2896         are provided for a vCenter Server, the host_names argument is required to tell
 2897         vCenter which hosts to configure ntp servers.
 2898 
 2899         If host_names is not provided, the NTP servers will be configured for the
 2900         ``host`` location instead. This is useful for when service instance connection
 2901         information is used for a single ESXi host.
 2902 
 2903     CLI Example:
 2904 
 2905     .. code-block:: bash
 2906 
 2907         # Used for single ESXi host connection information
 2908         salt '*' vsphere.ntp_configure my.esxi.host root bad-password '[192.174.1.100, 192.174.1.200]'
 2909 
 2910         # Used for connecting to a vCenter Server
 2911         salt '*' vsphere.ntp_configure my.vcenter.location root bad-password '[192.174.1.100, 192.174.1.200]' \
 2912         host_names='[esxi-1.host.com, esxi-2.host.com]'
 2913     """
 2914     service_instance = salt.utils.vmware.get_service_instance(
 2915         host=host, username=username, password=password, protocol=protocol, port=port
 2916     )
 2917     if not isinstance(ntp_servers, list):
 2918         raise CommandExecutionError("'ntp_servers' must be a list.")
 2919 
 2920     # Get NTP Config Object from ntp_servers
 2921     ntp_config = vim.HostNtpConfig(server=ntp_servers)
 2922 
 2923     # Get DateTimeConfig object from ntp_config
 2924     date_config = vim.HostDateTimeConfig(ntpConfig=ntp_config)
 2925 
 2926     host_names = _check_hosts(service_instance, host, host_names)
 2927     ret = {}
 2928     for host_name in host_names:
 2929         host_ref = _get_host_ref(service_instance, host, host_name=host_name)
 2930         date_time_manager = _get_date_time_mgr(host_ref)
 2931         log.debug(
 2932             "Configuring NTP Servers '{}' for host '{}'.".format(ntp_servers, host_name)
 2933         )
 2934 
 2935         try:
 2936             date_time_manager.UpdateDateTimeConfig(config=date_config)
 2937         except vim.fault.HostConfigFault as err:
 2938             msg = "vsphere.ntp_configure_servers failed: {}".format(err)
 2939             log.debug(msg)
 2940             ret.update({host_name: {"Error": msg}})
 2941             continue
 2942 
 2943         ret.update({host_name: {"NTP Servers": ntp_config}})
 2944     return ret
 2945 
 2946 
 2947 @depends(HAS_PYVMOMI)
 2948 @ignores_kwargs("credstore")
 2949 def service_start(
 2950     host, username, password, service_name, protocol=None, port=None, host_names=None
 2951 ):
 2952     """
 2953     Start the named service for the given host or list of hosts.
 2954 
 2955     host
 2956         The location of the host.
 2957 
 2958     username
 2959         The username used to login to the host, such as ``root``.
 2960 
 2961     password
 2962         The password used to login to the host.
 2963 
 2964     service_name
 2965         The name of the service for which to set the policy. Supported service names are:
 2966           - DCUI
 2967           - TSM
 2968           - SSH
 2969           - lbtd
 2970           - lsassd
 2971           - lwiod
 2972           - netlogond
 2973           - ntpd
 2974           - sfcbd-watchdog
 2975           - snmpd
 2976           - vprobed
 2977           - vpxa
 2978           - xorg
 2979 
 2980     protocol
 2981         Optionally set to alternate protocol if the host is not using the default
 2982         protocol. Default protocol is ``https``.
 2983 
 2984     port
 2985         Optionally set to alternate port if the host is not using the default
 2986         port. Default port is ``443``.
 2987 
 2988     host_names
 2989         List of ESXi host names. When the host, username, and password credentials
 2990         are provided for a vCenter Server, the host_names argument is required to tell
 2991         vCenter the hosts for which to start the service.
 2992 
 2993         If host_names is not provided, the service will be started for the ``host``
 2994         location instead. This is useful for when service instance connection information
 2995         is used for a single ESXi host.
 2996 
 2997     CLI Example:
 2998 
 2999     .. code-block:: bash
 3000 
 3001         # Used for single ESXi host connection information
 3002         salt '*' vsphere.service_start my.esxi.host root bad-password 'ntpd'
 3003 
 3004         # Used for connecting to a vCenter Server
 3005         salt '*' vsphere.service_start my.vcenter.location root bad-password 'ntpd' \
 3006         host_names='[esxi-1.host.com, esxi-2.host.com]'
 3007     """
 3008     service_instance = salt.utils.vmware.get_service_instance(
 3009         host=host, username=username, password=password, protocol=protocol, port=port
 3010     )
 3011     host_names = _check_hosts(service_instance, host, host_names)
 3012     valid_services = [
 3013         "DCUI",
 3014         "TSM",
 3015         "SSH",
 3016         "ssh",
 3017         "lbtd",
 3018         "lsassd",
 3019         "lwiod",
 3020         "netlogond",
 3021         "ntpd",
 3022         "sfcbd-watchdog",
 3023         "snmpd",
 3024         "vprobed",
 3025         "vpxa",
 3026         "xorg",
 3027     ]
 3028     ret = {}
 3029 
 3030     # Don't require users to know that VMware lists the ssh service as TSM-SSH
 3031     if service_name == "SSH" or service_name == "ssh":
 3032         temp_service_name = "TSM-SSH"
 3033     else:
 3034         temp_service_name = service_name
 3035 
 3036     for host_name in host_names:
 3037         # Check if the service_name provided is a valid one.
 3038         # If we don't have a valid service, return. The service will be invalid for all hosts.
 3039         if service_name not in valid_services:
 3040             ret.update(
 3041                 {
 3042                     host_name: {
 3043                         "Error": "{} is not a valid service name.".format(service_name)
 3044                     }
 3045                 }
 3046             )
 3047             return ret
 3048 
 3049         host_ref = _get_host_ref(service_instance, host, host_name=host_name)
 3050         service_manager = _get_service_manager(host_ref)
 3051         log.debug("Starting the '{}' service on {}.".format(service_name, host_name))
 3052 
 3053         # Start the service
 3054         try:
 3055             service_manager.StartService(id=temp_service_name)
 3056         except vim.fault.HostConfigFault as err:
 3057             msg = "'vsphere.service_start' failed for host {}: {}".format(
 3058                 host_name, err
 3059             )
 3060             log.debug(msg)
 3061             ret.update({host_name: {"Error": msg}})
 3062             continue
 3063         # Some services are restricted by the vSphere License Level.
 3064         except vim.fault.RestrictedVersion as err:
 3065             log.debug(err)
 3066             ret.update({host_name: {"Error": err}})
 3067             continue
 3068 
 3069         ret.update({host_name: {"Service Started": True}})
 3070 
 3071     return ret
 3072 
 3073 
 3074 @depends(HAS_PYVMOMI)
 3075 @ignores_kwargs("credstore")
 3076 def service_stop(
 3077     host, username, password, service_name, protocol=None, port=None, host_names=None
 3078 ):
 3079     """
 3080     Stop the named service for the given host or list of hosts.
 3081 
 3082     host
 3083         The location of the host.
 3084 
 3085     username
 3086         The username used to login to the host, such as ``root``.
 3087 
 3088     password
 3089         The password used to login to the host.
 3090 
 3091     service_name
 3092         The name of the service for which to set the policy. Supported service names are:
 3093           - DCUI
 3094           - TSM
 3095           - SSH
 3096           - lbtd
 3097           - lsassd
 3098           - lwiod
 3099           - netlogond
 3100           - ntpd
 3101           - sfcbd-watchdog
 3102           - snmpd
 3103           - vprobed
 3104           - vpxa
 3105           - xorg
 3106 
 3107     protocol
 3108         Optionally set to alternate protocol if the host is not using the default
 3109         protocol. Default protocol is ``https``.
 3110 
 3111     port
 3112         Optionally set to alternate port if the host is not using the default
 3113         port. Default port is ``443``.
 3114 
 3115     host_names
 3116         List of ESXi host names. When the host, username, and password credentials
 3117         are provided for a vCenter Server, the host_names argument is required to tell
 3118         vCenter the hosts for which to stop the service.
 3119 
 3120         If host_names is not provided, the service will be stopped for the ``host``
 3121         location instead. This is useful for when service instance connection information
 3122         is used for a single ESXi host.
 3123 
 3124     CLI Example:
 3125 
 3126     .. code-block:: bash
 3127 
 3128         # Used for single ESXi host connection information
 3129         salt '*' vsphere.service_stop my.esxi.host root bad-password 'ssh'
 3130 
 3131         # Used for connecting to a vCenter Server
 3132         salt '*' vsphere.service_stop my.vcenter.location root bad-password 'ssh' \
 3133         host_names='[esxi-1.host.com, esxi-2.host.com]'
 3134     """
 3135     service_instance = salt.utils.vmware.get_service_instance(
 3136         host=host, username=username, password=password, protocol=protocol, port=port
 3137     )
 3138     host_names = _check_hosts(service_instance, host, host_names)
 3139     valid_services = [
 3140         "DCUI",
 3141         "TSM",
 3142         "SSH",
 3143         "ssh",
 3144         "lbtd",
 3145         "lsassd",
 3146         "lwiod",
 3147         "netlogond",
 3148         "ntpd",
 3149         "sfcbd-watchdog",
 3150         "snmpd",
 3151         "vprobed",
 3152         "vpxa",
 3153         "xorg",
 3154     ]
 3155     ret = {}
 3156 
 3157     # Don't require users to know that VMware lists the ssh service as TSM-SSH
 3158     if service_name == "SSH" or service_name == "ssh":
 3159         temp_service_name = "TSM-SSH"
 3160     else:
 3161         temp_service_name = service_name
 3162 
 3163     for host_name in host_names:
 3164         # Check if the service_name provided is a valid one.
 3165         # If we don't have a valid service, return. The service will be invalid for all hosts.
 3166         if service_name not in valid_services:
 3167             ret.update(
 3168                 {
 3169                     host_name: {
 3170                         "Error": "{} is not a valid service name.".format(service_name)
 3171                     }
 3172                 }
 3173             )
 3174             return ret
 3175 
 3176         host_ref = _get_host_ref(service_instance, host, host_name=host_name)
 3177         service_manager = _get_service_manager(host_ref)
 3178         log.debug("Stopping the '{}' service on {}.".format(service_name, host_name))
 3179 
 3180         # Stop the service.
 3181         try:
 3182             service_manager.StopService(id=temp_service_name)
 3183         except vim.fault.HostConfigFault as err:
 3184             msg = "'vsphere.service_stop' failed for host {}: {}".format(host_name, err)
 3185             log.debug(msg)
 3186             ret.update({host_name: {"Error": msg}})
 3187             continue
 3188         # Some services are restricted by the vSphere License Level.
 3189         except vim.fault.RestrictedVersion as err:
 3190             log.debug(err)
 3191             ret.update({host_name: {"Error": err}})
 3192             continue
 3193 
 3194         ret.update({host_name: {"Service Stopped": True}})
 3195 
 3196     return ret
 3197 
 3198 
 3199 @depends(HAS_PYVMOMI)
 3200 @ignores_kwargs("credstore")
 3201 def service_restart(
 3202     host, username, password, service_name, protocol=None, port=None, host_names=None
 3203 ):
 3204     """
 3205     Restart the named service for the given host or list of hosts.
 3206 
 3207     host
 3208         The location of the host.
 3209 
 3210     username
 3211         The username used to login to the host, such as ``root``.
 3212 
 3213     password
 3214         The password used to login to the host.
 3215 
 3216     service_name
 3217         The name of the service for which to set the policy. Supported service names are:
 3218           - DCUI
 3219           - TSM
 3220           - SSH
 3221           - lbtd
 3222           - lsassd
 3223           - lwiod
 3224           - netlogond
 3225           - ntpd
 3226           - sfcbd-watchdog
 3227           - snmpd
 3228           - vprobed
 3229           - vpxa
 3230           - xorg
 3231 
 3232     protocol
 3233         Optionally set to alternate protocol if the host is not using the default
 3234         protocol. Default protocol is ``https``.
 3235 
 3236     port
 3237         Optionally set to alternate port if the host is not using the default
 3238         port. Default port is ``443``.
 3239 
 3240     host_names
 3241         List of ESXi host names. When the host, username, and password credentials
 3242         are provided for a vCenter Server, the host_names argument is required to tell
 3243         vCenter the hosts for which to restart the service.
 3244 
 3245         If host_names is not provided, the service will be restarted for the ``host``
 3246         location instead. This is useful for when service instance connection information
 3247         is used for a single ESXi host.
 3248 
 3249     CLI Example:
 3250 
 3251     .. code-block:: bash
 3252 
 3253         # Used for single ESXi host connection information
 3254         salt '*' vsphere.service_restart my.esxi.host root bad-password 'ntpd'
 3255 
 3256         # Used for connecting to a vCenter Server
 3257         salt '*' vsphere.service_restart my.vcenter.location root bad-password 'ntpd' \
 3258         host_names='[esxi-1.host.com, esxi-2.host.com]'
 3259     """
 3260     service_instance = salt.utils.vmware.get_service_instance(
 3261         host=host, username=username, password=password, protocol=protocol, port=port
 3262     )
 3263     host_names = _check_hosts(service_instance, host, host_names)
 3264     valid_services = [
 3265         "DCUI",
 3266         "TSM",
 3267         "SSH",
 3268         "ssh",
 3269         "lbtd",
 3270         "lsassd",
 3271         "lwiod",
 3272         "netlogond",
 3273         "ntpd",
 3274         "sfcbd-watchdog",
 3275         "snmpd",
 3276         "vprobed",
 3277         "vpxa",
 3278         "xorg",
 3279     ]
 3280     ret = {}
 3281 
 3282     # Don't require users to know that VMware lists the ssh service as TSM-SSH
 3283     if service_name == "SSH" or service_name == "ssh":
 3284         temp_service_name = "TSM-SSH"
 3285     else:
 3286         temp_service_name = service_name
 3287 
 3288     for host_name in host_names:
 3289         # Check if the service_name provided is a valid one.
 3290         # If we don't have a valid service, return. The service will be invalid for all hosts.
 3291         if service_name not in valid_services:
 3292             ret.update(
 3293                 {
 3294                     host_name: {
 3295                         "Error": "{} is not a valid service name.".format(service_name)
 3296                     }
 3297                 }
 3298             )
 3299             return ret
 3300 
 3301         host_ref = _get_host_ref(service_instance, host, host_name=host_name)
 3302         service_manager = _get_service_manager(host_ref)
 3303         log.debug("Restarting the '{}' service on {}.".format(service_name, host_name))
 3304 
 3305         # Restart the service.
 3306         try:
 3307             service_manager.RestartService(id=temp_service_name)
 3308         except vim.fault.HostConfigFault as err:
 3309             msg = "'vsphere.service_restart' failed for host {}: {}".format(
 3310                 host_name, err
 3311             )
 3312             log.debug(msg)
 3313             ret.update({host_name: {"Error": msg}})
 3314             continue
 3315         # Some services are restricted by the vSphere License Level.
 3316         except vim.fault.RestrictedVersion as err:
 3317             log.debug(err)
 3318             ret.update({host_name: {"Error": err}})
 3319             continue
 3320 
 3321         ret.update({host_name: {"Service Restarted": True}})
 3322 
 3323     return ret
 3324 
 3325 
 3326 @depends(HAS_PYVMOMI)
 3327 @ignores_kwargs("credstore")
 3328 def set_service_policy(
 3329     host,
 3330     username,
 3331     password,
 3332     service_name,
 3333     service_policy,
 3334     protocol=None,
 3335     port=None,
 3336     host_names=None,
 3337 ):
 3338     """
 3339     Set the service name's policy for a given host or list of hosts.
 3340 
 3341     host
 3342         The location of the host.
 3343 
 3344     username
 3345         The username used to login to the host, such as ``root``.
 3346 
 3347     password
 3348         The password used to login to the host.
 3349 
 3350     service_name
 3351         The name of the service for which to set the policy. Supported service names are:
 3352           - DCUI
 3353           - TSM
 3354           - SSH
 3355           - lbtd
 3356           - lsassd
 3357           - lwiod
 3358           - netlogond
 3359           - ntpd
 3360           - sfcbd-watchdog
 3361           - snmpd
 3362           - vprobed
 3363           - vpxa
 3364           - xorg
 3365 
 3366     service_policy
 3367         The policy to set for the service. For example, 'automatic'.
 3368 
 3369     protocol
 3370         Optionally set to alternate protocol if the host is not using the default
 3371         protocol. Default protocol is ``https``.
 3372 
 3373     port
 3374         Optionally set to alternate port if the host is not using the default
 3375         port. Default port is ``443``.
 3376 
 3377     host_names
 3378         List of ESXi host names. When the host, username, and password credentials
 3379         are provided for a vCenter Server, the host_names argument is required to tell
 3380         vCenter the hosts for which to set the service policy.
 3381 
 3382         If host_names is not provided, the service policy information will be retrieved
 3383         for the ``host`` location instead. This is useful for when service instance
 3384         connection information is used for a single ESXi host.
 3385 
 3386     CLI Example:
 3387 
 3388     .. code-block:: bash
 3389 
 3390         # Used for single ESXi host connection information
 3391         salt '*' vsphere.set_service_policy my.esxi.host root bad-password 'ntpd' 'automatic'
 3392 
 3393         # Used for connecting to a vCenter Server
 3394         salt '*' vsphere.set_service_policy my.vcenter.location root bad-password 'ntpd' 'automatic' \
 3395         host_names='[esxi-1.host.com, esxi-2.host.com]'
 3396     """
 3397     service_instance = salt.utils.vmware.get_service_instance(
 3398         host=host, username=username, password=password, protocol=protocol, port=port
 3399     )
 3400     host_names = _check_hosts(service_instance, host, host_names)
 3401     valid_services = [
 3402         "DCUI",
 3403         "TSM",
 3404         "SSH",
 3405         "ssh",
 3406         "lbtd",
 3407         "lsassd",
 3408         "lwiod",
 3409         "netlogond",
 3410         "ntpd",
 3411         "sfcbd-watchdog",
 3412         "snmpd",
 3413         "vprobed",
 3414         "vpxa",
 3415         "xorg",
 3416     ]
 3417     ret = {}
 3418 
 3419     for host_name in host_names:
 3420         # Check if the service_name provided is a valid one.
 3421         # If we don't have a valid service, return. The service will be invalid for all hosts.
 3422         if service_name not in valid_services:
 3423             ret.update(
 3424                 {
 3425                     host_name: {
 3426                         "Error": "{} is not a valid service name.".format(service_name)
 3427                     }
 3428                 }
 3429             )
 3430             return ret
 3431 
 3432         host_ref = _get_host_ref(service_instance, host, host_name=host_name)
 3433         service_manager = _get_service_manager(host_ref)
 3434         services = host_ref.configManager.serviceSystem.serviceInfo.service
 3435 
 3436         # Services are stored in a general list - we need loop through the list and find
 3437         # service key that matches our service name.
 3438         for service in services:
 3439             service_key = None
 3440 
 3441             # Find the service key based on the given service_name
 3442             if service.key == service_name:
 3443                 service_key = service.key
 3444             elif service_name == "ssh" or service_name == "SSH":
 3445                 if service.key == "TSM-SSH":
 3446                     service_key = "TSM-SSH"
 3447 
 3448             # If we have a service_key, we've found a match. Update the policy.
 3449             if service_key:
 3450                 try:
 3451                     service_manager.UpdateServicePolicy(
 3452                         id=service_key, policy=service_policy
 3453                     )
 3454                 except vim.fault.NotFound:
 3455                     msg = "The service name '{}' was not found.".format(service_name)
 3456                     log.debug(msg)
 3457                     ret.update({host_name: {"Error": msg}})
 3458                     continue
 3459                 # Some services are restricted by the vSphere License Level.
 3460                 except vim.fault.HostConfigFault as err:
 3461                     msg = "'vsphere.set_service_policy' failed for host {}: {}".format(
 3462                         host_name, err
 3463                     )
 3464                     log.debug(msg)
 3465                     ret.update({host_name: {"Error": msg}})
 3466                     continue
 3467 
 3468                 ret.update({host_name: True})
 3469 
 3470             # If we made it this far, something else has gone wrong.
 3471             if ret.get(host_name) is None:
 3472                 msg = "Could not find service '{}' for host '{}'.".format(
 3473                     service_name, host_name
 3474                 )
 3475                 log.debug(msg)
 3476                 ret.update({host_name: {"Error": msg}})
 3477 
 3478     return ret
 3479 
 3480 
 3481 @depends(HAS_PYVMOMI)
 3482 @ignores_kwargs("credstore")
 3483 def update_host_datetime(
 3484     host, username, password, protocol=None, port=None, host_names=None
 3485 ):
 3486     """
 3487     Update the date/time on the given host or list of host_names. This function should be
 3488     used with caution since network delays and execution delays can result in time skews.
 3489 
 3490     host
 3491         The location of the host.
 3492 
 3493     username
 3494         The username used to login to the host, such as ``root``.
 3495 
 3496     password
 3497         The password used to login to the host.
 3498 
 3499     protocol
 3500         Optionally set to alternate protocol if the host is not using the default
 3501         protocol. Default protocol is ``https``.
 3502 
 3503     port
 3504         Optionally set to alternate port if the host is not using the default
 3505         port. Default port is ``443``.
 3506 
 3507     host_names
 3508         List of ESXi host names. When the host, username, and password credentials
 3509         are provided for a vCenter Server, the host_names argument is required to
 3510         tell vCenter which hosts should update their date/time.
 3511 
 3512         If host_names is not provided, the date/time will be updated for the ``host``
 3513         location instead. This is useful for when service instance connection
 3514         information is used for a single ESXi host.
 3515 
 3516     CLI Example:
 3517 
 3518     .. code-block:: bash
 3519 
 3520         # Used for single ESXi host connection information
 3521         salt '*' vsphere.update_date_time my.esxi.host root bad-password
 3522 
 3523         # Used for connecting to a vCenter Server
 3524         salt '*' vsphere.update_date_time my.vcenter.location root bad-password \
 3525         host_names='[esxi-1.host.com, esxi-2.host.com]'
 3526     """
 3527     service_instance = salt.utils.vmware.get_service_instance(
 3528         host=host, username=username, password=password, protocol=protocol, port=port
 3529     )
 3530     host_names = _check_hosts(service_instance, host, host_names)
 3531     ret = {}
 3532     for host_name in host_names:
 3533         host_ref = _get_host_ref(service_instance, host, host_name=host_name)
 3534         date_time_manager = _get_date_time_mgr(host_ref)
 3535         try:
 3536             date_time_manager.UpdateDateTime(datetime.datetime.utcnow())
 3537         except vim.fault.HostConfigFault as err:
 3538             msg = "'vsphere.update_date_time' failed for host {}: {}".format(
 3539                 host_name, err
 3540             )
 3541             log.debug(msg)
 3542             ret.update({host_name: {"Error": msg}})
 3543             continue
 3544 
 3545         ret.update({host_name: {"Datetime Updated": True}})
 3546 
 3547     return ret
 3548 
 3549 
 3550 @depends(HAS_PYVMOMI)
 3551 @ignores_kwargs("credstore")
 3552 def update_host_password(
 3553     host, username, password, new_password, protocol=None, port=None
 3554 ):
 3555     """
 3556     Update the password for a given host.
 3557 
 3558     .. note:: Currently only works with connections to ESXi hosts. Does not work with vCenter servers.
 3559 
 3560     host
 3561         The location of the ESXi host.
 3562 
 3563     username
 3564         The username used to login to the ESXi host, such as ``root``.
 3565 
 3566     password
 3567         The password used to login to the ESXi host.
 3568 
 3569     new_password
 3570         The new password that will be updated for the provided username on the ESXi host.
 3571 
 3572     protocol
 3573         Optionally set to alternate protocol if the host is not using the default
 3574         protocol. Default protocol is ``https``.
 3575 
 3576     port
 3577         Optionally set to alternate port if the host is not using the default
 3578         port. Default port is ``443``.
 3579 
 3580     CLI Example:
 3581 
 3582     .. code-block:: bash
 3583 
 3584         salt '*' vsphere.update_host_password my.esxi.host root original-bad-password new-bad-password
 3585 
 3586     """
 3587     service_instance = salt.utils.vmware.get_service_instance(
 3588         host=host, username=username, password=password, protocol=protocol, port=port
 3589     )
 3590     # Get LocalAccountManager object
 3591     account_manager = salt.utils.vmware.get_inventory(service_instance).accountManager
 3592 
 3593     # Create user account specification object and assign id and password attributes
 3594     user_account = vim.host.LocalAccountManager.AccountSpecification()
 3595     user_account.id = username
 3596     user_account.password = new_password
 3597 
 3598     # Update the password
 3599     try:
 3600         account_manager.UpdateUser(user_account)
 3601     except vmodl.fault.SystemError as err:
 3602         raise CommandExecutionError(err.msg)
 3603     except vim.fault.UserNotFound:
 3604         raise CommandExecutionError(
 3605             "'vsphere.update_host_password' failed for host {}: "
 3606             "User was not found.".format(host)
 3607         )
 3608     # If the username and password already exist, we don't need to do anything.
 3609     except vim.fault.AlreadyExists:
 3610         pass
 3611 
 3612     return True
 3613 
 3614 
 3615 @depends(HAS_PYVMOMI)
 3616 @ignores_kwargs("credstore")
 3617 def vmotion_disable(
 3618     host, username, password, protocol=None, port=None, host_names=None
 3619 ):
 3620     """
 3621     Disable vMotion for a given host or list of host_names.
 3622 
 3623     host
 3624         The location of the host.
 3625 
 3626     username
 3627         The username used to login to the host, such as ``root``.
 3628 
 3629     password
 3630         The password used to login to the host.
 3631 
 3632     protocol
 3633         Optionally set to alternate protocol if the host is not using the default
 3634         protocol. Default protocol is ``https``.
 3635 
 3636     port
 3637         Optionally set to alternate port if the host is not using the default
 3638         port. Default port is ``443``.
 3639 
 3640     host_names
 3641         List of ESXi host names. When the host, username, and password credentials
 3642         are provided for a vCenter Server, the host_names argument is required to
 3643         tell vCenter which hosts should disable VMotion.
 3644 
 3645         If host_names is not provided, VMotion will be disabled for the ``host``
 3646         location instead. This is useful for when service instance connection
 3647         information is used for a single ESXi host.
 3648 
 3649     CLI Example:
 3650 
 3651     .. code-block:: bash
 3652 
 3653         # Used for single ESXi host connection information
 3654         salt '*' vsphere.vmotion_disable my.esxi.host root bad-password
 3655 
 3656         # Used for connecting to a vCenter Server
 3657         salt '*' vsphere.vmotion_disable my.vcenter.location root bad-password \
 3658         host_names='[esxi-1.host.com, esxi-2.host.com]'
 3659     """
 3660     service_instance = salt.utils.vmware.get_service_instance(
 3661         host=host, username=username, password=password, protocol=protocol, port=port
 3662     )
 3663     host_names = _check_hosts(service_instance, host, host_names)
 3664     ret = {}
 3665     for host_name in host_names:
 3666         host_ref = _get_host_ref(service_instance, host, host_name=host_name)
 3667         vmotion_system = host_ref.configManager.vmotionSystem
 3668 
 3669         # Disable VMotion for the host by removing the VNic selected to use for VMotion.
 3670         try:
 3671             vmotion_system.DeselectVnic()
 3672         except vim.fault.HostConfigFault as err:
 3673             msg = "vsphere.vmotion_disable failed: {}".format(err)
 3674             log.debug(msg)
 3675             ret.update({host_name: {"Error": msg, "VMotion Disabled": False}})
 3676             continue
 3677 
 3678         ret.update({host_name: {"VMotion Disabled": True}})
 3679 
 3680     return ret
 3681 
 3682 
 3683 @depends(HAS_PYVMOMI)
 3684 @ignores_kwargs("credstore")
 3685 def vmotion_enable(
 3686     host, username, password, protocol=None, port=None, host_names=None, device="vmk0"
 3687 ):
 3688     """
 3689     Enable vMotion for a given host or list of host_names.
 3690 
 3691     host
 3692         The location of the host.
 3693 
 3694     username
 3695         The username used to login to the host, such as ``root``.
 3696 
 3697     password
 3698         The password used to login to the host.
 3699 
 3700     protocol
 3701         Optionally set to alternate protocol if the host is not using the default
 3702         protocol. Default protocol is ``https``.
 3703 
 3704     port
 3705         Optionally set to alternate port if the host is not using the default
 3706         port. Default port is ``443``.
 3707 
 3708     host_names
 3709         List of ESXi host names. When the host, username, and password credentials
 3710         are provided for a vCenter Server, the host_names argument is required to
 3711         tell vCenter which hosts should enable VMotion.
 3712 
 3713         If host_names is not provided, VMotion will be enabled for the ``host``
 3714         location instead. This is useful for when service instance connection
 3715         information is used for a single ESXi host.
 3716 
 3717     device
 3718         The device that uniquely identifies the VirtualNic that will be used for
 3719         VMotion for each host. Defaults to ``vmk0``.
 3720 
 3721     CLI Example:
 3722 
 3723     .. code-block:: bash
 3724 
 3725         # Used for single ESXi host connection information
 3726         salt '*' vsphere.vmotion_enable my.esxi.host root bad-password
 3727 
 3728         # Used for connecting to a vCenter Server
 3729         salt '*' vsphere.vmotion_enable my.vcenter.location root bad-password \
 3730         host_names='[esxi-1.host.com, esxi-2.host.com]'
 3731     """
 3732     service_instance = salt.utils.vmware.get_service_instance(
 3733         host=host, username=username, password=password, protocol=protocol, port=port
 3734     )
 3735     host_names = _check_hosts(service_instance, host, host_names)
 3736     ret = {}
 3737     for host_name in host_names:
 3738         host_ref = _get_host_ref(service_instance, host, host_name=host_name)
 3739         vmotion_system = host_ref.configManager.vmotionSystem
 3740 
 3741         # Enable VMotion for the host by setting the given device to provide the VNic to use for VMotion.
 3742         try:
 3743             vmotion_system.SelectVnic(device)
 3744         except vim.fault.HostConfigFault as err:
 3745             msg = "vsphere.vmotion_disable failed: {}".format(err)
 3746             log.debug(msg)
 3747             ret.update({host_name: {"Error": msg, "VMotion Enabled": False}})
 3748             continue
 3749 
 3750         ret.update({host_name: {"VMotion Enabled": True}})
 3751 
 3752     return ret
 3753 
 3754 
 3755 @depends(HAS_PYVMOMI)
 3756 @ignores_kwargs("credstore")
 3757 def vsan_add_disks(host, username, password, protocol=None, port=None, host_names=None):
 3758     """
 3759     Add any VSAN-eligible disks to the VSAN System for the given host or list of host_names.
 3760 
 3761     host
 3762         The location of the host.
 3763 
 3764     username
 3765         The username used to login to the host, such as ``root``.
 3766 
 3767     password
 3768         The password used to login to the host.
 3769 
 3770     protocol
 3771         Optionally set to alternate protocol if the host is not using the default
 3772         protocol. Default protocol is ``https``.
 3773 
 3774     port
 3775         Optionally set to alternate port if the host is not using the default
 3776         port. Default port is ``443``.
 3777 
 3778     host_names
 3779         List of ESXi host names. When the host, username, and password credentials
 3780         are provided for a vCenter Server, the host_names argument is required to
 3781         tell vCenter which hosts need to add any VSAN-eligible disks to the host's
 3782         VSAN system.
 3783 
 3784         If host_names is not provided, VSAN-eligible disks will be added to the hosts's
 3785         VSAN system for the ``host`` location instead. This is useful for when service
 3786         instance connection information is used for a single ESXi host.
 3787 
 3788     CLI Example:
 3789 
 3790     .. code-block:: bash
 3791 
 3792         # Used for single ESXi host connection information
 3793         salt '*' vsphere.vsan_add_disks my.esxi.host root bad-password
 3794 
 3795         # Used for connecting to a vCenter Server
 3796         salt '*' vsphere.vsan_add_disks my.vcenter.location root bad-password \
 3797         host_names='[esxi-1.host.com, esxi-2.host.com]'
 3798     """
 3799     service_instance = salt.utils.vmware.get_service_instance(
 3800         host=host, username=username, password=password, protocol=protocol, port=port
 3801     )
 3802     host_names = _check_hosts(service_instance, host, host_names)
 3803     response = _get_vsan_eligible_disks(service_instance, host, host_names)
 3804 
 3805     ret = {}
 3806     for host_name, value in response.items():
 3807         host_ref = _get_host_ref(service_instance, host, host_name=host_name)
 3808         vsan_system = host_ref.configManager.vsanSystem
 3809 
 3810         # We must have a VSAN Config in place before we can manipulate it.
 3811         if vsan_system is None:
 3812             msg = (
 3813                 "VSAN System Config Manager is unset for host '{}'. "
 3814                 "VSAN configuration cannot be changed without a configured "
 3815                 "VSAN System.".format(host_name)
 3816             )
 3817             log.debug(msg)
 3818             ret.update({host_name: {"Error": msg}})
 3819         else:
 3820             eligible = value.get("Eligible")
 3821             error = value.get("Error")
 3822 
 3823             if eligible and isinstance(eligible, list):
 3824                 # If we have eligible, matching disks, add them to VSAN.
 3825                 try:
 3826                     task = vsan_system.AddDisks(eligible)
 3827                     salt.utils.vmware.wait_for_task(
 3828                         task, host_name, "Adding disks to VSAN", sleep_seconds=3
 3829                     )
 3830                 except vim.fault.InsufficientDisks as err:
 3831                     log.debug(err.msg)
 3832                     ret.update({host_name: {"Error": err.msg}})
 3833                     continue
 3834                 except Exception as err:  # pylint: disable=broad-except
 3835                     msg = "'vsphere.vsan_add_disks' failed for host {}: {}".format(
 3836                         host_name, err
 3837                     )
 3838                     log.debug(msg)
 3839                     ret.update({host_name: {"Error": msg}})
 3840                     continue
 3841 
 3842                 log.debug(
 3843                     "Successfully added disks to the VSAN system for host '{}'.".format(
 3844                         host_name
 3845                     )
 3846                 )
 3847                 # We need to return ONLY the disk names, otherwise Message Pack can't deserialize the disk objects.
 3848                 disk_names = []
 3849                 for disk in eligible:
 3850                     disk_names.append(disk.canonicalName)
 3851                 ret.update({host_name: {"Disks Added": disk_names}})
 3852             elif eligible and isinstance(eligible, str):
 3853                 # If we have a string type in the eligible value, we don't
 3854                 # have any VSAN-eligible disks. Pull the message through.
 3855                 ret.update({host_name: {"Disks Added": eligible}})
 3856             elif error:
 3857                 # If we hit an error, populate the Error return dict for state functions.
 3858                 ret.update({host_name: {"Error": error}})
 3859             else:
 3860                 # If we made it this far, we somehow have eligible disks, but they didn't
 3861                 # match the disk list and just got an empty list of matching disks.
 3862                 ret.update(
 3863                     {
 3864                         host_name: {
 3865                             "Disks Added": "No new VSAN-eligible disks were found to add."
 3866                         }
 3867                     }
 3868                 )
 3869 
 3870     return ret
 3871 
 3872 
 3873 @depends(HAS_PYVMOMI)
 3874 @ignores_kwargs("credstore")
 3875 def vsan_disable(host, username, password, protocol=None, port=None, host_names=None):
 3876     """
 3877     Disable VSAN for a given host or list of host_names.
 3878 
 3879     host
 3880         The location of the host.
 3881 
 3882     username
 3883         The username used to login to the host, such as ``root``.
 3884 
 3885     password
 3886         The password used to login to the host.
 3887 
 3888     protocol
 3889         Optionally set to alternate protocol if the host is not using the default
 3890         protocol. Default protocol is ``https``.
 3891 
 3892     port
 3893         Optionally set to alternate port if the host is not using the default
 3894         port. Default port is ``443``.
 3895 
 3896     host_names
 3897         List of ESXi host names. When the host, username, and password credentials
 3898         are provided for a vCenter Server, the host_names argument is required to
 3899         tell vCenter which hosts should disable VSAN.
 3900 
 3901         If host_names is not provided, VSAN will be disabled for the ``host``
 3902         location instead. This is useful for when service instance connection
 3903         information is used for a single ESXi host.
 3904 
 3905     CLI Example:
 3906 
 3907     .. code-block:: bash
 3908 
 3909         # Used for single ESXi host connection information
 3910         salt '*' vsphere.vsan_disable my.esxi.host root bad-password
 3911 
 3912         # Used for connecting to a vCenter Server
 3913         salt '*' vsphere.vsan_disable my.vcenter.location root bad-password \
 3914         host_names='[esxi-1.host.com, esxi-2.host.com]'
 3915     """
 3916     service_instance = salt.utils.vmware.get_service_instance(
 3917         host=host, username=username, password=password, protocol=protocol, port=port
 3918     )
 3919     # Create a VSAN Configuration Object and set the enabled attribute to True
 3920     vsan_config = vim.vsan.host.ConfigInfo()
 3921     vsan_config.enabled = False
 3922 
 3923     host_names = _check_hosts(service_instance, host, host_names)
 3924     ret = {}
 3925     for host_name in host_names:
 3926         host_ref = _get_host_ref(service_instance, host, host_name=host_name)
 3927         vsan_system = host_ref.configManager.vsanSystem
 3928 
 3929         # We must have a VSAN Config in place before we can manipulate it.
 3930         if vsan_system is None:
 3931             msg = (
 3932                 "VSAN System Config Manager is unset for host '{}'. "
 3933                 "VSAN configuration cannot be changed without a configured "
 3934                 "VSAN System.".format(host_name)
 3935             )
 3936             log.debug(msg)
 3937             ret.update({host_name: {"Error": msg}})
 3938         else:
 3939             try:
 3940                 # Disable vsan on the host
 3941                 task = vsan_system.UpdateVsan_Task(vsan_config)
 3942                 salt.utils.vmware.wait_for_task(
 3943                     task, host_name, "Disabling VSAN", sleep_seconds=3
 3944                 )
 3945             except vmodl.fault.SystemError as err:
 3946                 log.debug(err.msg)
 3947                 ret.update({host_name: {"Error": err.msg}})
 3948                 continue
 3949             except Exception as err:  # pylint: disable=broad-except
 3950                 msg = "'vsphere.vsan_disable' failed for host {}: {}".format(
 3951                     host_name, err
 3952                 )
 3953                 log.debug(msg)
 3954                 ret.update({host_name: {"Error": msg}})
 3955                 continue
 3956 
 3957             ret.update({host_name: {"VSAN Disabled": True}})
 3958 
 3959     return ret
 3960 
 3961 
 3962 @depends(HAS_PYVMOMI)
 3963 @ignores_kwargs("credstore")
 3964 def vsan_enable(host, username, password, protocol=None, port=None, host_names=None):
 3965     """
 3966     Enable VSAN for a given host or list of host_names.
 3967 
 3968     host
 3969         The location of the host.
 3970 
 3971     username
 3972         The username used to login to the host, such as ``root``.
 3973 
 3974     password
 3975         The password used to login to the host.
 3976 
 3977     protocol
 3978         Optionally set to alternate protocol if the host is not using the default
 3979         protocol. Default protocol is ``https``.
 3980 
 3981     port
 3982         Optionally set to alternate port if the host is not using the default
 3983         port. Default port is ``443``.
 3984 
 3985     host_names
 3986         List of ESXi host names. When the host, username, and password credentials
 3987         are provided for a vCenter Server, the host_names argument is required to
 3988         tell vCenter which hosts should enable VSAN.
 3989 
 3990         If host_names is not provided, VSAN will be enabled for the ``host``
 3991         location instead. This is useful for when service instance connection
 3992         information is used for a single ESXi host.
 3993 
 3994     CLI Example:
 3995 
 3996     .. code-block:: bash
 3997 
 3998         # Used for single ESXi host connection information
 3999         salt '*' vsphere.vsan_enable my.esxi.host root bad-password
 4000 
 4001         # Used for connecting to a vCenter Server
 4002         salt '*' vsphere.vsan_enable my.vcenter.location root bad-password \
 4003         host_names='[esxi-1.host.com, esxi-2.host.com]'
 4004     """
 4005     service_instance = salt.utils.vmware.get_service_instance(
 4006         host=host, username=username, password=password, protocol=protocol, port=port
 4007     )
 4008     # Create a VSAN Configuration Object and set the enabled attribute to True
 4009     vsan_config = vim.vsan.host.ConfigInfo()
 4010     vsan_config.enabled = True
 4011 
 4012     host_names = _check_hosts(service_instance, host, host_names)
 4013     ret = {}
 4014     for host_name in host_names:
 4015         host_ref = _get_host_ref(service_instance, host, host_name=host_name)
 4016         vsan_system = host_ref.configManager.vsanSystem
 4017 
 4018         # We must have a VSAN Config in place before we can manipulate it.
 4019         if vsan_system is None:
 4020             msg = (
 4021                 "VSAN System Config Manager is unset for host '{}'. "
 4022                 "VSAN configuration cannot be changed without a configured "
 4023                 "VSAN System.".format(host_name)
 4024             )
 4025             log.debug(msg)
 4026             ret.update({host_name: {"Error": msg}})
 4027         else:
 4028             try:
 4029                 # Enable vsan on the host
 4030                 task = vsan_system.UpdateVsan_Task(vsan_config)
 4031                 salt.utils.vmware.wait_for_task(
 4032                     task, host_name, "Enabling VSAN", sleep_seconds=3
 4033                 )
 4034             except vmodl.fault.SystemError as err:
 4035                 log.debug(err.msg)
 4036                 ret.update({host_name: {"Error": err.msg}})
 4037                 continue
 4038             except vim.fault.VsanFault as err:
 4039                 msg = "'vsphere.vsan_enable' failed for host {}: {}".format(
 4040                     host_name, err
 4041                 )
 4042                 log.debug(msg)
 4043                 ret.update({host_name: {"Error": msg}})
 4044                 continue
 4045 
 4046             ret.update({host_name: {"VSAN Enabled": True}})
 4047 
 4048     return ret
 4049 
 4050 
 4051 def _get_dvs_config_dict(dvs_name, dvs_config):
 4052     """
 4053     Returns the dict representation of the DVS config
 4054 
 4055     dvs_name
 4056         The name of the DVS
 4057 
 4058     dvs_config
 4059         The DVS config
 4060     """
 4061     log.trace("Building the dict of the DVS '{}' config".format(dvs_name))
 4062     conf_dict = {
 4063         "name": dvs_name,
 4064         "contact_email": dvs_config.contact.contact,
 4065         "contact_name": dvs_config.contact.name,
 4066         "description": dvs_config.description,
 4067         "lacp_api_version": dvs_config.lacpApiVersion,
 4068         "network_resource_control_version": dvs_config.networkResourceControlVersion,
 4069         "network_resource_management_enabled": dvs_config.networkResourceManagementEnabled,
 4070         "max_mtu": dvs_config.maxMtu,
 4071     }
 4072     if isinstance(dvs_config.uplinkPortPolicy, vim.DVSNameArrayUplinkPortPolicy):
 4073         conf_dict.update({"uplink_names": dvs_config.uplinkPortPolicy.uplinkPortName})
 4074     return conf_dict
 4075 
 4076 
 4077 def _get_dvs_link_discovery_protocol(dvs_name, dvs_link_disc_protocol):
 4078     """
 4079     Returns the dict representation of the DVS link discovery protocol
 4080 
 4081     dvs_name
 4082         The name of the DVS
 4083 
 4084     dvs_link_disc_protocl
 4085         The DVS link discovery protocol
 4086     """
 4087     log.trace(
 4088         "Building the dict of the DVS '{}' link discovery " "protocol".format(dvs_name)
 4089     )
 4090     return {
 4091         "operation": dvs_link_disc_protocol.operation,
 4092         "protocol": dvs_link_disc_protocol.protocol,
 4093     }
 4094 
 4095 
 4096 def _get_dvs_product_info(dvs_name, dvs_product_info):
 4097     """
 4098     Returns the dict representation of the DVS product_info
 4099 
 4100     dvs_name
 4101         The name of the DVS
 4102 
 4103     dvs_product_info
 4104         The DVS product info
 4105     """
 4106     log.trace("Building the dict of the DVS '{}' product " "info".format(dvs_name))
 4107     return {
 4108         "name": dvs_product_info.name,
 4109         "vendor": dvs_product_info.vendor,
 4110         "version": dvs_product_info.version,
 4111     }
 4112 
 4113 
 4114 def _get_dvs_capability(dvs_name, dvs_capability):
 4115     """
 4116     Returns the dict representation of the DVS product_info
 4117 
 4118     dvs_name
 4119         The name of the DVS
 4120 
 4121     dvs_capability
 4122         The DVS capability
 4123     """
 4124     log.trace("Building the dict of the DVS '{}' capability" "".format(dvs_name))
 4125     return {
 4126         "operation_supported": dvs_capability.dvsOperationSupported,
 4127         "portgroup_operation_supported": dvs_capability.dvPortGroupOperationSupported,
 4128         "port_operation_supported": dvs_capability.dvPortOperationSupported,
 4129     }
 4130 
 4131 
 4132 def _get_dvs_infrastructure_traffic_resources(dvs_name, dvs_infra_traffic_ress):
 4133     """
 4134     Returns a list of dict representations of the DVS infrastructure traffic
 4135     resource
 4136 
 4137     dvs_name
 4138         The name of the DVS
 4139 
 4140     dvs_infra_traffic_ress
 4141         The DVS infrastructure traffic resources
 4142     """
 4143     log.trace(
 4144         "Building the dicts of the DVS '{}' infrastructure traffic "
 4145         "resources".format(dvs_name)
 4146     )
 4147     res_dicts = []
 4148     for res in dvs_infra_traffic_ress:
 4149         res_dict = {
 4150             "key": res.key,
 4151             "limit": res.allocationInfo.limit,
 4152             "reservation": res.allocationInfo.reservation,
 4153         }
 4154         if res.allocationInfo.shares:
 4155             res_dict.update(
 4156                 {
 4157                     "num_shares": res.allocationInfo.shares.shares,
 4158                     "share_level": res.allocationInfo.shares.level,
 4159                 }
 4160             )
 4161         res_dicts.append(res_dict)
 4162     return res_dicts
 4163 
 4164 
 4165 @depends(HAS_PYVMOMI)
 4166 @supports_proxies("esxdatacenter", "esxcluster")
 4167 @gets_service_instance_via_proxy
 4168 def list_dvss(datacenter=None, dvs_names=None, service_instance=None):
 4169     """
 4170     Returns a list of distributed virtual switches (DVSs).
 4171     The list can be filtered by the datacenter or DVS names.
 4172 
 4173     datacenter
 4174         The datacenter to look for DVSs in.
 4175         Default value is None.
 4176 
 4177     dvs_names
 4178         List of DVS names to look for. If None, all DVSs are returned.
 4179         Default value is None.
 4180 
 4181     .. code-block:: bash
 4182 
 4183         salt '*' vsphere.list_dvss
 4184 
 4185         salt '*' vsphere.list_dvss dvs_names=[dvs1,dvs2]
 4186     """
 4187     ret_list = []
 4188     proxy_type = get_proxy_type()
 4189     if proxy_type == "esxdatacenter":
 4190         datacenter = __salt__["esxdatacenter.get_details"]()["datacenter"]
 4191         dc_ref = _get_proxy_target(service_instance)
 4192     elif proxy_type == "esxcluster":
 4193         datacenter = __salt__["esxcluster.get_details"]()["datacenter"]
 4194         dc_ref = salt.utils.vmware.get_datacenter(service_instance, datacenter)
 4195 
 4196     for dvs in salt.utils.vmware.get_dvss(dc_ref, dvs_names, (not dvs_names)):
 4197         dvs_dict = {}
 4198         # XXX: Because of how VMware did DVS object inheritance we can\'t
 4199         # be more restrictive when retrieving the dvs config, we have to
 4200         # retrieve the entire object
 4201         props = salt.utils.vmware.get_properties_of_managed_object(
 4202             dvs, ["name", "config", "capability", "networkResourcePool"]
 4203         )
 4204         dvs_dict = _get_dvs_config_dict(props["name"], props["config"])
 4205         # Product info
 4206         dvs_dict.update(
 4207             {
 4208                 "product_info": _get_dvs_product_info(
 4209                     props["name"], props["config"].productInfo
 4210                 )
 4211             }
 4212         )
 4213         # Link Discovery Protocol
 4214         if props["config"].linkDiscoveryProtocolConfig:
 4215             dvs_dict.update(
 4216                 {
 4217                     "link_discovery_protocol": _get_dvs_link_discovery_protocol(
 4218                         props["name"], props["config"].linkDiscoveryProtocolConfig
 4219                     )
 4220                 }
 4221             )
 4222         # Capability
 4223         dvs_dict.update(
 4224             {"capability": _get_dvs_capability(props["name"], props["capability"])}
 4225         )
 4226         # InfrastructureTrafficResourceConfig - available with vSphere 6.0
 4227         if hasattr(props["config"], "infrastructureTrafficResourceConfig"):
 4228             dvs_dict.update(
 4229                 {
 4230                     "infrastructure_traffic_resource_pools": _get_dvs_infrastructure_traffic_resources(
 4231                         props["name"],
 4232                         props["config"].infrastructureTrafficResourceConfig,
 4233                     )
 4234                 }
 4235             )
 4236         ret_list.append(dvs_dict)
 4237     return ret_list
 4238 
 4239 
 4240 def _apply_dvs_config(config_spec, config_dict):
 4241     """
 4242     Applies the values of the config dict dictionary to a config spec
 4243     (vim.VMwareDVSConfigSpec)
 4244     """
 4245     if config_dict.get("name"):
 4246         config_spec.name = config_dict["name"]
 4247     if config_dict.get("contact_email") or config_dict.get("contact_name"):
 4248         if not config_spec.contact:
 4249             config_spec.contact = vim.DVSContactInfo()
 4250         config_spec.contact.contact = config_dict.get("contact_email")
 4251         config_spec.contact.name = config_dict.get("contact_name")
 4252     if config_dict.get("description"):
 4253         config_spec.description = config_dict.get("description")
 4254     if config_dict.get("max_mtu"):
 4255         config_spec.maxMtu = config_dict.get("max_mtu")
 4256     if config_dict.get("lacp_api_version"):
 4257         config_spec.lacpApiVersion = config_dict.get("lacp_api_version")
 4258     if config_dict.get("network_resource_control_version"):
 4259         config_spec.networkResourceControlVersion = config_dict.get(
 4260             "network_resource_control_version"
 4261         )
 4262     if config_dict.get("uplink_names"):
 4263         if not config_spec.uplinkPortPolicy or not isinstance(
 4264             config_spec.uplinkPortPolicy, vim.DVSNameArrayUplinkPortPolicy
 4265         ):
 4266 
 4267             config_spec.uplinkPortPolicy = vim.DVSNameArrayUplinkPortPolicy()
 4268         config_spec.uplinkPortPolicy.uplinkPortName = config_dict["uplink_names"]
 4269 
 4270 
 4271 def _apply_dvs_link_discovery_protocol(disc_prot_config, disc_prot_dict):
 4272     """
 4273     Applies the values of the disc_prot_dict dictionary to a link discovery
 4274     protocol config object (vim.LinkDiscoveryProtocolConfig)
 4275     """
 4276     disc_prot_config.operation = disc_prot_dict["operation"]
 4277     disc_prot_config.protocol = disc_prot_dict["protocol"]
 4278 
 4279 
 4280 def _apply_dvs_product_info(product_info_spec, product_info_dict):
 4281     """
 4282     Applies the values of the product_info_dict dictionary to a product info
 4283     spec (vim.DistributedVirtualSwitchProductSpec)
 4284     """
 4285     if product_info_dict.get("name"):
 4286         product_info_spec.name = product_info_dict["name"]
 4287     if product_info_dict.get("vendor"):
 4288         product_info_spec.vendor = product_info_dict["vendor"]
 4289     if product_info_dict.get("version"):
 4290         product_info_spec.version = product_info_dict["version"]
 4291 
 4292 
 4293 def _apply_dvs_capability(capability_spec, capability_dict):
 4294     """
 4295     Applies the values of the capability_dict dictionary to a DVS capability
 4296     object (vim.vim.DVSCapability)
 4297     """
 4298     if "operation_supported" in capability_dict:
 4299         capability_spec.dvsOperationSupported = capability_dict["operation_supported"]
 4300     if "port_operation_supported" in capability_dict:
 4301         capability_spec.dvPortOperationSupported = capability_dict[
 4302             "port_operation_supported"
 4303         ]
 4304     if "portgroup_operation_supported" in capability_dict:
 4305         capability_spec.dvPortGroupOperationSupported = capability_dict[
 4306             "portgroup_operation_supported"
 4307         ]
 4308 
 4309 
 4310 def _apply_dvs_infrastructure_traffic_resources(
 4311     infra_traffic_resources, resource_dicts
 4312 ):
 4313     """
 4314     Applies the values of the resource dictionaries to infra traffic resources,
 4315     creating the infra traffic resource if required
 4316     (vim.DistributedVirtualSwitchProductSpec)
 4317     """
 4318     for res_dict in resource_dicts:
 4319         filtered_traffic_resources = [
 4320             r for r in infra_traffic_resources if r.key == res_dict["key"]
 4321         ]
 4322         if filtered_traffic_resources:
 4323             traffic_res = filtered_traffic_resources[0]
 4324         else:
 4325             traffic_res = vim.DvsHostInfrastructureTrafficResource()
 4326             traffic_res.key = res_dict["key"]
 4327             traffic_res.allocationInfo = (
 4328                 vim.DvsHostInfrastructureTrafficResourceAllocation()
 4329             )
 4330             infra_traffic_resources.append(traffic_res)
 4331         if res_dict.get("limit"):
 4332             traffic_res.allocationInfo.limit = res_dict["limit"]
 4333         if res_dict.get("reservation"):
 4334             traffic_res.allocationInfo.reservation = res_dict["reservation"]
 4335         if res_dict.get("num_shares") or res_dict.get("share_level"):
 4336             if not traffic_res.allocationInfo.shares:
 4337                 traffic_res.allocationInfo.shares = vim.SharesInfo()
 4338         if res_dict.get("share_level"):
 4339             traffic_res.allocationInfo.shares.level = vim.SharesLevel(
 4340                 res_dict["share_level"]
 4341             )
 4342         if res_dict.get("num_shares"):
 4343             # XXX Even though we always set the number of shares if provided,
 4344             # the vCenter will ignore it unless the share level is 'custom'.
 4345             traffic_res.allocationInfo.shares.shares = res_dict["num_shares"]
 4346 
 4347 
 4348 def _apply_dvs_network_resource_pools(network_resource_pools, resource_dicts):
 4349     """
 4350     Applies the values of the resource dictionaries to network resource pools,
 4351     creating the resource pools if required
 4352     (vim.DVSNetworkResourcePoolConfigSpec)
 4353     """
 4354     for res_dict in resource_dicts:
 4355         ress = [r for r in network_resource_pools if r.key == res_dict["key"]]
 4356         if ress:
 4357             res = ress[0]
 4358         else:
 4359             res = vim.DVSNetworkResourcePoolConfigSpec()
 4360             res.key = res_dict["key"]
 4361             res.allocationInfo = vim.DVSNetworkResourcePoolAllocationInfo()
 4362             network_resource_pools.append(res)
 4363         if res_dict.get("limit"):
 4364             res.allocationInfo.limit = res_dict["limit"]
 4365         if res_dict.get("num_shares") and res_dict.get("share_level"):
 4366             if not res.allocationInfo.shares:
 4367                 res.allocationInfo.shares = vim.SharesInfo()
 4368             res.allocationInfo.shares.shares = res_dict["num_shares"]
 4369             res.allocationInfo.shares.level = vim.SharesLevel(res_dict["share_level"])
 4370 
 4371 
 4372 @depends(HAS_PYVMOMI)
 4373 @supports_proxies("esxdatacenter", "esxcluster")
 4374 @gets_service_instance_via_proxy
 4375 def create_dvs(dvs_dict, dvs_name, service_instance=None):
 4376     """
 4377     Creates a distributed virtual switch (DVS).
 4378 
 4379     Note: The ``dvs_name`` param will override any name set in ``dvs_dict``.
 4380 
 4381     dvs_dict
 4382         Dict representation of the new DVS (example in salt.states.dvs)
 4383 
 4384     dvs_name
 4385         Name of the DVS to be created.
 4386 
 4387     service_instance
 4388         Service instance (vim.ServiceInstance) of the vCenter.
 4389         Default is None.
 4390 
 4391     .. code-block:: bash
 4392 
 4393         salt '*' vsphere.create_dvs dvs dict=$dvs_dict dvs_name=dvs_name
 4394     """
 4395     log.trace("Creating dvs '{}' with dict = {}".format(dvs_name, dvs_dict))
 4396     proxy_type = get_proxy_type()
 4397     if proxy_type == "esxdatacenter":
 4398         datacenter = __salt__["esxdatacenter.get_details"]()["datacenter"]
 4399         dc_ref = _get_proxy_target(service_instance)
 4400     elif proxy_type == "esxcluster":
 4401         datacenter = __salt__["esxcluster.get_details"]()["datacenter"]
 4402         dc_ref = salt.utils.vmware.get_datacenter(service_instance, datacenter)
 4403     # Make the name of the DVS consistent with the call
 4404     dvs_dict["name"] = dvs_name
 4405     # Build the config spec from the input
 4406     dvs_create_spec = vim.DVSCreateSpec()
 4407     dvs_create_spec.configSpec = vim.VMwareDVSConfigSpec()
 4408     _apply_dvs_config(dvs_create_spec.configSpec, dvs_dict)
 4409     if dvs_dict.get("product_info"):
 4410         dvs_create_spec.productInfo = vim.DistributedVirtualSwitchProductSpec()
 4411         _apply_dvs_product_info(dvs_create_spec.productInfo, dvs_dict["product_info"])
 4412     if dvs_dict.get("capability"):
 4413         dvs_create_spec.capability = vim.DVSCapability()
 4414         _apply_dvs_capability(dvs_create_spec.capability, dvs_dict["capability"])
 4415     if dvs_dict.get("link_discovery_protocol"):
 4416         dvs_create_spec.configSpec.linkDiscoveryProtocolConfig = (
 4417             vim.LinkDiscoveryProtocolConfig()
 4418         )
 4419         _apply_dvs_link_discovery_protocol(
 4420             dvs_create_spec.configSpec.linkDiscoveryProtocolConfig,
 4421             dvs_dict["link_discovery_protocol"],
 4422         )
 4423     if dvs_dict.get("infrastructure_traffic_resource_pools"):
 4424         dvs_create_spec.configSpec.infrastructureTrafficResourceConfig = []
 4425         _apply_dvs_infrastructure_traffic_resources(
 4426             dvs_create_spec.configSpec.infrastructureTrafficResourceConfig,
 4427             dvs_dict["infrastructure_traffic_resource_pools"],
 4428         )
 4429     log.trace("dvs_create_spec = {}".format(dvs_create_spec))
 4430     salt.utils.vmware.create_dvs(dc_ref, dvs_name, dvs_create_spec)
 4431     if "network_resource_management_enabled" in dvs_dict:
 4432         dvs_refs = salt.utils.vmware.get_dvss(dc_ref, dvs_names=[dvs_name])
 4433         if not dvs_refs:
 4434             raise VMwareObjectRetrievalError(
 4435                 "DVS '{}' wasn't found in datacenter '{}'"
 4436                 "".format(dvs_name, datacenter)
 4437             )
 4438         dvs_ref = dvs_refs[0]
 4439         salt.utils.vmware.set_dvs_network_resource_management_enabled(
 4440             dvs_ref, dvs_dict["network_resource_management_enabled"]
 4441         )
 4442     return True
 4443 
 4444 
 4445 @depends(HAS_PYVMOMI)
 4446 @supports_proxies("esxdatacenter", "esxcluster")
 4447 @gets_service_instance_via_proxy
 4448 def update_dvs(dvs_dict, dvs, service_instance=None):
 4449     """
 4450     Updates a distributed virtual switch (DVS).
 4451 
 4452     Note: Updating the product info, capability, uplinks of a DVS is not
 4453           supported so the corresponding entries in ``dvs_dict`` will be
 4454           ignored.
 4455 
 4456     dvs_dict
 4457         Dictionary with the values the DVS should be update with
 4458         (example in salt.states.dvs)
 4459 
 4460     dvs
 4461         Name of the DVS to be updated.
 4462 
 4463     service_instance
 4464         Service instance (vim.ServiceInstance) of the vCenter.
 4465         Default is None.
 4466 
 4467     .. code-block:: bash
 4468 
 4469         salt '*' vsphere.update_dvs dvs_dict=$dvs_dict dvs=dvs1
 4470     """
 4471     # Remove ignored properties
 4472     log.trace("Updating dvs '{}' with dict = {}".format(dvs, dvs_dict))
 4473     for prop in ["product_info", "capability", "uplink_names", "name"]:
 4474         if prop in dvs_dict:
 4475             del dvs_dict[prop]
 4476     proxy_type = get_proxy_type()
 4477     if proxy_type == "esxdatacenter":
 4478         datacenter = __salt__["esxdatacenter.get_details"]()["datacenter"]
 4479         dc_ref = _get_proxy_target(service_instance)
 4480     elif proxy_type == "esxcluster":
 4481         datacenter = __salt__["esxcluster.get_details"]()["datacenter"]
 4482         dc_ref = salt.utils.vmware.get_datacenter(service_instance, datacenter)
 4483     dvs_refs = salt.utils.vmware.get_dvss(dc_ref, dvs_names=[dvs])
 4484     if not dvs_refs:
 4485         raise VMwareObjectRetrievalError(
 4486             "DVS '{}' wasn't found in " "datacenter '{}'" "".format(dvs, datacenter)
 4487         )
 4488     dvs_ref = dvs_refs[0]
 4489     # Build the config spec from the input
 4490     dvs_props = salt.utils.vmware.get_properties_of_managed_object(
 4491         dvs_ref, ["config", "capability"]
 4492     )
 4493     dvs_config = vim.VMwareDVSConfigSpec()
 4494     # Copy all of the properties in the config of the of the DVS to a
 4495     # DvsConfigSpec
 4496     skipped_properties = ["host"]
 4497     for prop in dvs_config.__dict__.keys():
 4498         if prop in skipped_properties:
 4499             continue
 4500         if hasattr(dvs_props["config"], prop):
 4501             setattr(dvs_config, prop, getattr(dvs_props["config"], prop))
 4502     _apply_dvs_config(dvs_config, dvs_dict)
 4503     if dvs_dict.get("link_discovery_protocol"):
 4504         if not dvs_config.linkDiscoveryProtocolConfig:
 4505             dvs_config.linkDiscoveryProtocolConfig = vim.LinkDiscoveryProtocolConfig()
 4506         _apply_dvs_link_discovery_protocol(
 4507             dvs_config.linkDiscoveryProtocolConfig, dvs_dict["link_discovery_protocol"]
 4508         )
 4509     if dvs_dict.get("infrastructure_traffic_resource_pools"):
 4510         if not dvs_config.infrastructureTrafficResourceConfig:
 4511             dvs_config.infrastructureTrafficResourceConfig = []
 4512         _apply_dvs_infrastructure_traffic_resources(
 4513             dvs_config.infrastructureTrafficResourceConfig,
 4514             dvs_dict["infrastructure_traffic_resource_pools"],
 4515         )
 4516     log.trace("dvs_config= {}".format(dvs_config))
 4517     salt.utils.vmware.update_dvs(dvs_ref, dvs_config_spec=dvs_config)
 4518     if "network_resource_management_enabled" in dvs_dict:
 4519         salt.utils.vmware.set_dvs_network_resource_management_enabled(
 4520             dvs_ref, dvs_dict["network_resource_management_enabled"]
 4521         )
 4522     return True
 4523 
 4524 
 4525 def _get_dvportgroup_out_shaping(pg_name, pg_default_port_config):
 4526     """
 4527     Returns the out shaping policy of a distributed virtual portgroup
 4528 
 4529     pg_name
 4530         The name of the portgroup
 4531 
 4532     pg_default_port_config
 4533         The dafault port config of the portgroup
 4534     """
 4535     log.trace("Retrieving portgroup's '{}' out shaping " "config".format(pg_name))
 4536     out_shaping_policy = pg_default_port_config.outShapingPolicy
 4537     if not out_shaping_policy:
 4538         return {}
 4539     return {
 4540         "average_bandwidth": out_shaping_policy.averageBandwidth.value,
 4541         "burst_size": out_shaping_policy.burstSize.value,
 4542         "enabled": out_shaping_policy.enabled.value,
 4543         "peak_bandwidth": out_shaping_policy.peakBandwidth.value,
 4544     }
 4545 
 4546 
 4547 def _get_dvportgroup_security_policy(pg_name, pg_default_port_config):
 4548     """
 4549     Returns the security policy of a distributed virtual portgroup
 4550 
 4551     pg_name
 4552         The name of the portgroup
 4553 
 4554     pg_default_port_config
 4555         The dafault port config of the portgroup
 4556     """
 4557     log.trace("Retrieving portgroup's '{}' security policy " "config".format(pg_name))
 4558     sec_policy = pg_default_port_config.securityPolicy
 4559     if not sec_policy:
 4560         return {}
 4561     return {
 4562         "allow_promiscuous": sec_policy.allowPromiscuous.value,
 4563         "forged_transmits": sec_policy.forgedTransmits.value,
 4564         "mac_changes": sec_policy.macChanges.value,
 4565     }
 4566 
 4567 
 4568 def _get_dvportgroup_teaming(pg_name, pg_default_port_config):
 4569     """
 4570     Returns the teaming of a distributed virtual portgroup
 4571 
 4572     pg_name
 4573         The name of the portgroup
 4574 
 4575     pg_default_port_config
 4576         The dafault port config of the portgroup
 4577     """
 4578     log.trace("Retrieving portgroup's '{}' teaming" "config".format(pg_name))
 4579     teaming_policy = pg_default_port_config.uplinkTeamingPolicy
 4580     if not teaming_policy:
 4581         return {}
 4582     ret_dict = {
 4583         "notify_switches": teaming_policy.notifySwitches.value,
 4584         "policy": teaming_policy.policy.value,
 4585         "reverse_policy": teaming_policy.reversePolicy.value,
 4586         "rolling_order": teaming_policy.rollingOrder.value,
 4587     }
 4588     if teaming_policy.failureCriteria:
 4589         failure_criteria = teaming_policy.failureCriteria
 4590         ret_dict.update(
 4591             {
 4592                 "failure_criteria": {
 4593                     "check_beacon": failure_criteria.checkBeacon.value,
 4594                     "check_duplex": failure_criteria.checkDuplex.value,
 4595                     "check_error_percent": failure_criteria.checkErrorPercent.value,
 4596                     "check_speed": failure_criteria.checkSpeed.value,
 4597                     "full_duplex": failure_criteria.fullDuplex.value,
 4598                     "percentage": failure_criteria.percentage.value,
 4599                     "speed": failure_criteria.speed.value,
 4600                 }
 4601             }
 4602         )
 4603     if teaming_policy.uplinkPortOrder:
 4604         uplink_order = teaming_policy.uplinkPortOrder
 4605         ret_dict.update(
 4606             {
 4607                 "port_order": {
 4608                     "active": uplink_order.activeUplinkPort,
 4609                     "standby": uplink_order.standbyUplinkPort,
 4610                 }
 4611             }
 4612         )
 4613     return ret_dict
 4614 
 4615 
 4616 def _get_dvportgroup_dict(pg_ref):
 4617     """
 4618     Returns a dictionary with a distributed virtual portgroup data
 4619 
 4620 
 4621     pg_ref
 4622         Portgroup reference
 4623     """
 4624     props = salt.utils.vmware.get_properties_of_managed_object(
 4625         pg_ref,
 4626         [
 4627             "name",
 4628             "config.description",
 4629             "config.numPorts",
 4630             "config.type",
 4631             "config.defaultPortConfig",
 4632         ],
 4633     )
 4634     pg_dict = {
 4635         "name": props["name"],
 4636         "description": props.get("config.description"),
 4637         "num_ports": props["config.numPorts"],
 4638         "type": props["config.type"],
 4639     }
 4640     if props["config.defaultPortConfig"]:
 4641         dpg = props["config.defaultPortConfig"]
 4642         if dpg.vlan and isinstance(
 4643             dpg.vlan, vim.VmwareDistributedVirtualSwitchVlanIdSpec
 4644         ):
 4645 
 4646             pg_dict.update({"vlan_id": dpg.vlan.vlanId})
 4647         pg_dict.update(
 4648             {
 4649                 "out_shaping": _get_dvportgroup_out_shaping(
 4650                     props["name"], props["config.defaultPortConfig"]
 4651                 )
 4652             }
 4653         )
 4654         pg_dict.update(
 4655             {
 4656                 "security_policy": _get_dvportgroup_security_policy(
 4657                     props["name"], props["config.defaultPortConfig"]
 4658                 )
 4659             }
 4660         )
 4661         pg_dict.update(
 4662             {
 4663                 "teaming": _get_dvportgroup_teaming(
 4664                     props["name"], props["config.defaultPortConfig"]
 4665                 )
 4666             }
 4667         )
 4668     return pg_dict
 4669 
 4670 
 4671 @depends(HAS_PYVMOMI)
 4672 @supports_proxies("esxdatacenter", "esxcluster")
 4673 @gets_service_instance_via_proxy
 4674 def list_dvportgroups(dvs=None, portgroup_names=None, service_instance=None):
 4675     """
 4676     Returns a list of distributed virtual switch portgroups.
 4677     The list can be filtered by the portgroup names or by the DVS.
 4678 
 4679     dvs
 4680         Name of the DVS containing the portgroups.
 4681         Default value is None.
 4682 
 4683     portgroup_names
 4684         List of portgroup names to look for. If None, all portgroups are
 4685         returned.
 4686         Default value is None
 4687 
 4688     service_instance
 4689         Service instance (vim.ServiceInstance) of the vCenter.
 4690         Default is None.
 4691 
 4692     .. code-block:: bash
 4693 
 4694         salt '*' vsphere.list_dvporgroups
 4695 
 4696         salt '*' vsphere.list_dvportgroups dvs=dvs1
 4697 
 4698         salt '*' vsphere.list_dvportgroups portgroup_names=[pg1]
 4699 
 4700         salt '*' vsphere.list_dvportgroups dvs=dvs1 portgroup_names=[pg1]
 4701     """
 4702     ret_dict = []
 4703     proxy_type = get_proxy_type()
 4704     if proxy_type == "esxdatacenter":
 4705         datacenter = __salt__["esxdatacenter.get_details"]()["datacenter"]
 4706         dc_ref = _get_proxy_target(service_instance)
 4707     elif proxy_type == "esxcluster":
 4708         datacenter = __salt__["esxcluster.get_details"]()["datacenter"]
 4709         dc_ref = salt.utils.vmware.get_datacenter(service_instance, datacenter)
 4710     if dvs:
 4711         dvs_refs = salt.utils.vmware.get_dvss(dc_ref, dvs_names=[dvs])
 4712         if not dvs_refs:
 4713             raise VMwareObjectRetrievalError(
 4714                 "DVS '{}' was not " "retrieved".format(dvs)
 4715             )
 4716         dvs_ref = dvs_refs[0]
 4717     get_all_portgroups = True if not portgroup_names else False
 4718     for pg_ref in salt.utils.vmware.get_dvportgroups(
 4719         parent_ref=dvs_ref if dvs else dc_ref,
 4720         portgroup_names=portgroup_names,
 4721         get_all_portgroups=get_all_portgroups,
 4722     ):
 4723 
 4724         ret_dict.append(_get_dvportgroup_dict(pg_ref))
 4725     return ret_dict
 4726 
 4727 
 4728 @depends(HAS_PYVMOMI)
 4729 @supports_proxies("esxdatacenter", "esxcluster")
 4730 @gets_service_instance_via_proxy
 4731 def list_uplink_dvportgroup(dvs, service_instance=None):
 4732     """
 4733     Returns the uplink portgroup of a distributed virtual switch.
 4734 
 4735     dvs
 4736         Name of the DVS containing the portgroup.
 4737 
 4738     service_instance
 4739         Service instance (vim.ServiceInstance) of the vCenter.
 4740         Default is None.
 4741 
 4742     .. code-block:: bash
 4743 
 4744         salt '*' vsphere.list_uplink_dvportgroup dvs=dvs_name
 4745     """
 4746     proxy_type = get_proxy_type()
 4747     if proxy_type == "esxdatacenter":
 4748         datacenter = __salt__["esxdatacenter.get_details"]()["datacenter"]
 4749         dc_ref = _get_proxy_target(service_instance)
 4750     elif proxy_type == "esxcluster":
 4751         datacenter = __salt__["esxcluster.get_details"]()["datacenter"]
 4752         dc_ref = salt.utils.vmware.get_datacenter(service_instance, datacenter)
 4753     dvs_refs = salt.utils.vmware.get_dvss(dc_ref, dvs_names=[dvs])
 4754     if not dvs_refs:
 4755         raise VMwareObjectRetrievalError("DVS '{}' was not " "retrieved".format(dvs))
 4756     uplink_pg_ref = salt.utils.vmware.get_uplink_dvportgroup(dvs_refs[0])
 4757     return _get_dvportgroup_dict(uplink_pg_ref)
 4758 
 4759 
 4760 def _apply_dvportgroup_out_shaping(pg_name, out_shaping, out_shaping_conf):
 4761     """
 4762     Applies the values in out_shaping_conf to an out_shaping object
 4763 
 4764     pg_name
 4765         The name of the portgroup
 4766 
 4767     out_shaping
 4768         The vim.DVSTrafficShapingPolicy to apply the config to
 4769 
 4770     out_shaping_conf
 4771         The out shaping config
 4772     """
 4773     log.trace("Building portgroup's '{}' out shaping " "policy".format(pg_name))
 4774     if out_shaping_conf.get("average_bandwidth"):
 4775         out_shaping.averageBandwidth = vim.LongPolicy()
 4776         out_shaping.averageBandwidth.value = out_shaping_conf["average_bandwidth"]
 4777     if out_shaping_conf.get("burst_size"):
 4778         out_shaping.burstSize = vim.LongPolicy()
 4779         out_shaping.burstSize.value = out_shaping_conf["burst_size"]
 4780     if "enabled" in out_shaping_conf:
 4781         out_shaping.enabled = vim.BoolPolicy()
 4782         out_shaping.enabled.value = out_shaping_conf["enabled"]
 4783     if out_shaping_conf.get("peak_bandwidth"):
 4784         out_shaping.peakBandwidth = vim.LongPolicy()
 4785         out_shaping.peakBandwidth.value = out_shaping_conf["peak_bandwidth"]
 4786 
 4787 
 4788 def _apply_dvportgroup_security_policy(pg_name, sec_policy, sec_policy_conf):
 4789     """
 4790     Applies the values in sec_policy_conf to a security policy object
 4791 
 4792     pg_name
 4793         The name of the portgroup
 4794 
 4795     sec_policy
 4796         The vim.DVSTrafficShapingPolicy to apply the config to
 4797 
 4798     sec_policy_conf
 4799         The out shaping config
 4800     """
 4801     log.trace("Building portgroup's '{}' security policy ".format(pg_name))
 4802     if "allow_promiscuous" in sec_policy_conf:
 4803         sec_policy.allowPromiscuous = vim.BoolPolicy()
 4804         sec_policy.allowPromiscuous.value = sec_policy_conf["allow_promiscuous"]
 4805     if "forged_transmits" in sec_policy_conf:
 4806         sec_policy.forgedTransmits = vim.BoolPolicy()
 4807         sec_policy.forgedTransmits.value = sec_policy_conf["forged_transmits"]
 4808     if "mac_changes" in sec_policy_conf:
 4809         sec_policy.macChanges = vim.BoolPolicy()
 4810         sec_policy.macChanges.value = sec_policy_conf["mac_changes"]
 4811 
 4812 
 4813 def _apply_dvportgroup_teaming(pg_name, teaming, teaming_conf):
 4814     """
 4815     Applies the values in teaming_conf to a teaming policy object
 4816 
 4817     pg_name
 4818         The name of the portgroup
 4819 
 4820     teaming
 4821         The vim.VmwareUplinkPortTeamingPolicy to apply the config to
 4822 
 4823     teaming_conf
 4824         The teaming config
 4825     """
 4826     log.trace("Building portgroup's '{}' teaming".format(pg_name))
 4827     if "notify_switches" in teaming_conf:
 4828         teaming.notifySwitches = vim.BoolPolicy()
 4829         teaming.notifySwitches.value = teaming_conf["notify_switches"]
 4830     if "policy" in teaming_conf:
 4831         teaming.policy = vim.StringPolicy()
 4832         teaming.policy.value = teaming_conf["policy"]
 4833     if "reverse_policy" in teaming_conf:
 4834         teaming.reversePolicy = vim.BoolPolicy()
 4835         teaming.reversePolicy.value = teaming_conf["reverse_policy"]
 4836     if "rolling_order" in teaming_conf:
 4837         teaming.rollingOrder = vim.BoolPolicy()
 4838         teaming.rollingOrder.value = teaming_conf["rolling_order"]
 4839     if "failure_criteria" in teaming_conf:
 4840         if not teaming.failureCriteria:
 4841             teaming.failureCriteria = vim.DVSFailureCriteria()
 4842         failure_criteria_conf = teaming_conf["failure_criteria"]
 4843         if "check_beacon" in failure_criteria_conf:
 4844             teaming.failureCriteria.checkBeacon = vim.BoolPolicy()
 4845             teaming.failureCriteria.checkBeacon.value = failure_criteria_conf[
 4846                 "check_beacon"
 4847             ]
 4848         if "check_duplex" in failure_criteria_conf:
 4849             teaming.failureCriteria.checkDuplex = vim.BoolPolicy()
 4850             teaming.failureCriteria.checkDuplex.value = failure_criteria_conf[
 4851                 "check_duplex"
 4852             ]
 4853         if "check_error_percent" in failure_criteria_conf:
 4854             teaming.failureCriteria.checkErrorPercent = vim.BoolPolicy()
 4855             teaming.failureCriteria.checkErrorPercent.value = failure_criteria_conf[
 4856                 "check_error_percent"
 4857             ]
 4858         if "check_speed" in failure_criteria_conf:
 4859             teaming.failureCriteria.checkSpeed = vim.StringPolicy()
 4860             teaming.failureCriteria.checkSpeed.value = failure_criteria_conf[
 4861                 "check_speed"
 4862             ]
 4863         if "full_duplex" in failure_criteria_conf:
 4864             teaming.failureCriteria.fullDuplex = vim.BoolPolicy()
 4865             teaming.failureCriteria.fullDuplex.value = failure_criteria_conf[
 4866                 "full_duplex"
 4867             ]
 4868         if "percentage" in failure_criteria_conf:
 4869             teaming.failureCriteria.percentage = vim.IntPolicy()
 4870             teaming.failureCriteria.percentage.value = failure_criteria_conf[
 4871                 "percentage"
 4872             ]
 4873         if "speed" in failure_criteria_conf:
 4874             teaming.failureCriteria.speed = vim.IntPolicy()
 4875             teaming.failureCriteria.speed.value = failure_criteria_conf["speed"]
 4876     if "port_order" in teaming_conf:
 4877         if not teaming.uplinkPortOrder:
 4878             teaming.uplinkPortOrder = vim.VMwareUplinkPortOrderPolicy()
 4879         if "active" in teaming_conf["port_order"]:
 4880             teaming.uplinkPortOrder.activeUplinkPort = teaming_conf["port_order"][
 4881                 "active"
 4882             ]
 4883         if "standby" in teaming_conf["port_order"]:
 4884             teaming.uplinkPortOrder.standbyUplinkPort = teaming_conf["port_order"][
 4885                 "standby"
 4886             ]
 4887 
 4888 
 4889 def _apply_dvportgroup_config(pg_name, pg_spec, pg_conf):
 4890     """
 4891     Applies the values in conf to a distributed portgroup spec
 4892 
 4893     pg_name
 4894         The name of the portgroup
 4895 
 4896     pg_spec
 4897         The vim.DVPortgroupConfigSpec to apply the config to
 4898 
 4899     pg_conf
 4900         The portgroup config
 4901     """
 4902     log.trace("Building portgroup's '{}' spec".format(pg_name))
 4903     if "name" in pg_conf:
 4904         pg_spec.name = pg_conf["name"]
 4905     if "description" in pg_conf:
 4906         pg_spec.description = pg_conf["description"]
 4907     if "num_ports" in pg_conf:
 4908         pg_spec.numPorts = pg_conf["num_ports"]
 4909     if "type" in pg_conf:
 4910         pg_spec.type = pg_conf["type"]
 4911 
 4912     if not pg_spec.defaultPortConfig:
 4913         for prop in ["vlan_id", "out_shaping", "security_policy", "teaming"]:
 4914             if prop in pg_conf:
 4915                 pg_spec.defaultPortConfig = vim.VMwareDVSPortSetting()
 4916     if "vlan_id" in pg_conf:
 4917         pg_spec.defaultPortConfig.vlan = vim.VmwareDistributedVirtualSwitchVlanIdSpec()
 4918         pg_spec.defaultPortConfig.vlan.vlanId = pg_conf["vlan_id"]
 4919     if "out_shaping" in pg_conf:
 4920         if not pg_spec.defaultPortConfig.outShapingPolicy:
 4921             pg_spec.defaultPortConfig.outShapingPolicy = vim.DVSTrafficShapingPolicy()
 4922         _apply_dvportgroup_out_shaping(
 4923             pg_name, pg_spec.defaultPortConfig.outShapingPolicy, pg_conf["out_shaping"]
 4924         )
 4925     if "security_policy" in pg_conf:
 4926         if not pg_spec.defaultPortConfig.securityPolicy:
 4927             pg_spec.defaultPortConfig.securityPolicy = vim.DVSSecurityPolicy()
 4928         _apply_dvportgroup_security_policy(
 4929             pg_name,
 4930             pg_spec.defaultPortConfig.securityPolicy,
 4931             pg_conf["security_policy"],
 4932         )
 4933     if "teaming" in pg_conf:
 4934         if not pg_spec.defaultPortConfig.uplinkTeamingPolicy:
 4935             pg_spec.defaultPortConfig.uplinkTeamingPolicy = (
 4936                 vim.VmwareUplinkPortTeamingPolicy()
 4937             )
 4938         _apply_dvportgroup_teaming(
 4939             pg_name, pg_spec.defaultPortConfig.uplinkTeamingPolicy, pg_conf["teaming"]
 4940         )
 4941 
 4942 
 4943 @depends(HAS_PYVMOMI)
 4944 @supports_proxies("esxdatacenter", "esxcluster")
 4945 @gets_service_instance_via_proxy
 4946 def create_dvportgroup(portgroup_dict, portgroup_name, dvs, service_instance=None):
 4947     """
 4948     Creates a distributed virtual portgroup.
 4949 
 4950     Note: The ``portgroup_name`` param will override any name already set
 4951     in ``portgroup_dict``.
 4952 
 4953     portgroup_dict
 4954         Dictionary with the config values the portgroup should be created with
 4955         (example in salt.states.dvs).
 4956 
 4957     portgroup_name
 4958         Name of the portgroup to be created.
 4959 
 4960     dvs
 4961         Name of the DVS that will contain the portgroup.
 4962 
 4963     service_instance
 4964         Service instance (vim.ServiceInstance) of the vCenter.
 4965         Default is None.
 4966 
 4967     .. code-block:: bash
 4968 
 4969         salt '*' vsphere.create_dvportgroup portgroup_dict=<dict>
 4970             portgroup_name=pg1 dvs=dvs1
 4971     """
 4972     log.trace(
 4973         "Creating portgroup'{}' in dvs '{}' "
 4974         "with dict = {}".format(portgroup_name, dvs, portgroup_dict)
 4975     )
 4976     proxy_type = get_proxy_type()
 4977     if proxy_type == "esxdatacenter":
 4978         datacenter = __salt__["esxdatacenter.get_details"]()["datacenter"]
 4979         dc_ref = _get_proxy_target(service_instance)
 4980     elif proxy_type == "esxcluster":
 4981         datacenter = __salt__["esxcluster.get_details"]()["datacenter"]
 4982         dc_ref = salt.utils.vmware.get_datacenter(service_instance, datacenter)
 4983     dvs_refs = salt.utils.vmware.get_dvss(dc_ref, dvs_names=[dvs])
 4984     if not dvs_refs:
 4985         raise VMwareObjectRetrievalError("DVS '{}' was not " "retrieved".format(dvs))
 4986     # Make the name of the dvportgroup consistent with the parameter
 4987     portgroup_dict["name"] = portgroup_name
 4988     spec = vim.DVPortgroupConfigSpec()
 4989     _apply_dvportgroup_config(portgroup_name, spec, portgroup_dict)
 4990     salt.utils.vmware.create_dvportgroup(dvs_refs[0], spec)
 4991     return True
 4992 
 4993 
 4994 @depends(HAS_PYVMOMI)
 4995 @supports_proxies("esxdatacenter", "esxcluster")
 4996 @gets_service_instance_via_proxy
 4997 def update_dvportgroup(portgroup_dict, portgroup, dvs, service_instance=True):
 4998     """
 4999     Updates a distributed virtual portgroup.
 5000 
 5001     portgroup_dict
 5002         Dictionary with the values the portgroup should be update with
 5003         (example in salt.states.dvs).
 5004 
 5005     portgroup
 5006         Name of the portgroup to be updated.
 5007 
 5008     dvs
 5009         Name of the DVS containing the portgroups.
 5010 
 5011     service_instance
 5012         Service instance (vim.ServiceInstance) of the vCenter.
 5013         Default is None.
 5014 
 5015     .. code-block:: bash
 5016 
 5017         salt '*' vsphere.update_dvportgroup portgroup_dict=<dict>
 5018             portgroup=pg1
 5019 
 5020         salt '*' vsphere.update_dvportgroup portgroup_dict=<dict>
 5021             portgroup=pg1 dvs=dvs1
 5022     """
 5023     log.trace(
 5024         "Updating portgroup'{}' in dvs '{}' "
 5025         "with dict = {}".format(portgroup, dvs, portgroup_dict)
 5026     )
 5027     proxy_type = get_proxy_type()
 5028     if proxy_type == "esxdatacenter":
 5029         datacenter = __salt__["esxdatacenter.get_details"]()["datacenter"]
 5030         dc_ref = _get_proxy_target(service_instance)
 5031     elif proxy_type == "esxcluster":
 5032         datacenter = __salt__["esxcluster.get_details"]()["datacenter"]
 5033         dc_ref = salt.utils.vmware.get_datacenter(service_instance, datacenter)
 5034     dvs_refs = salt.utils.vmware.get_dvss(dc_ref, dvs_names=[dvs])
 5035     if not dvs_refs:
 5036         raise VMwareObjectRetrievalError("DVS '{}' was not " "retrieved".format(dvs))
 5037     pg_refs = salt.utils.vmware.get_dvportgroups(
 5038         dvs_refs[0], portgroup_names=[portgroup]
 5039     )
 5040     if not pg_refs:
 5041         raise VMwareObjectRetrievalError(
 5042             "Portgroup '{}' was not " "retrieved".format(portgroup)
 5043         )
 5044     pg_props = salt.utils.vmware.get_properties_of_managed_object(
 5045         pg_refs[0], ["config"]
 5046     )
 5047     spec = vim.DVPortgroupConfigSpec()
 5048     # Copy existing properties in spec
 5049     for prop in [
 5050         "autoExpand",
 5051         "configVersion",
 5052         "defaultPortConfig",
 5053         "description",
 5054         "name",
 5055         "numPorts",
 5056         "policy",
 5057         "portNameFormat",
 5058         "scope",
 5059         "type",
 5060         "vendorSpecificConfig",
 5061     ]:
 5062         setattr(spec, prop, getattr(pg_props["config"], prop))
 5063     _apply_dvportgroup_config(portgroup, spec, portgroup_dict)
 5064     salt.utils.vmware.update_dvportgroup(pg_refs[0], spec)
 5065     return True
 5066 
 5067 
 5068 @depends(HAS_PYVMOMI)
 5069 @supports_proxies("esxdatacenter", "esxcluster")
 5070 @gets_service_instance_via_proxy
 5071 def remove_dvportgroup(portgroup, dvs, service_instance=None):
 5072     """
 5073     Removes a distributed virtual portgroup.
 5074 
 5075     portgroup
 5076         Name of the portgroup to be removed.
 5077 
 5078     dvs
 5079         Name of the DVS containing the portgroups.
 5080 
 5081     service_instance
 5082         Service instance (vim.ServiceInstance) of the vCenter.
 5083         Default is None.
 5084 
 5085     .. code-block:: bash
 5086 
 5087         salt '*' vsphere.remove_dvportgroup portgroup=pg1 dvs=dvs1
 5088     """
 5089     log.trace("Removing portgroup'{}' in dvs '{}' " "".format(portgroup, dvs))
 5090     proxy_type = get_proxy_type()
 5091     if proxy_type == "esxdatacenter":
 5092         datacenter = __salt__["esxdatacenter.get_details"]()["datacenter"]
 5093         dc_ref = _get_proxy_target(service_instance)
 5094     elif proxy_type == "esxcluster":
 5095         datacenter = __salt__["esxcluster.get_details"]()["datacenter"]
 5096         dc_ref = salt.utils.vmware.get_datacenter(service_instance, datacenter)
 5097     dvs_refs = salt.utils.vmware.get_dvss(dc_ref, dvs_names=[dvs])
 5098     if not dvs_refs:
 5099         raise VMwareObjectRetrievalError("DVS '{}' was not " "retrieved".format(dvs))
 5100     pg_refs = salt.utils.vmware.get_dvportgroups(
 5101         dvs_refs[0], portgroup_names=[portgroup]
 5102     )
 5103     if not pg_refs:
 5104         raise VMwareObjectRetrievalError(
 5105             "Portgroup '{}' was not " "retrieved".format(portgroup)
 5106         )
 5107     salt.utils.vmware.remove_dvportgroup(pg_refs[0])
 5108     return True
 5109 
 5110 
 5111 def _get_policy_dict(policy):
 5112     """Returns a dictionary representation of a policy"""
 5113     profile_dict = {
 5114         "name": policy.name,
 5115         "description": policy.description,
 5116         "resource_type": policy.resourceType.resourceType,
 5117     }
 5118     subprofile_dicts = []
 5119     if isinstance(policy, pbm.profile.CapabilityBasedProfile) and isinstance(
 5120         policy.constraints, pbm.profile.SubProfileCapabilityConstraints
 5121     ):
 5122 
 5123         for subprofile in policy.constraints.subProfiles:
 5124             subprofile_dict = {
 5125                 "name": subprofile.name,
 5126                 "force_provision": subprofile.forceProvision,
 5127             }
 5128             cap_dicts = []
 5129             for cap in subprofile.capability:
 5130                 cap_dict = {"namespace": cap.id.namespace, "id": cap.id.id}
 5131                 # We assume there is one constraint with one value set
 5132                 val = cap.constraint[0].propertyInstance[0].value
 5133                 if isinstance(val, pbm.capability.types.Range):
 5134                     val_dict = {"type": "range", "min": val.min, "max": val.max}
 5135                 elif isinstance(val, pbm.capability.types.DiscreteSet):
 5136                     val_dict = {"type": "set", "values": val.values}
 5137                 else:
 5138                     val_dict = {"type": "scalar", "value": val}
 5139                 cap_dict["setting"] = val_dict
 5140                 cap_dicts.append(cap_dict)
 5141             subprofile_dict["capabilities"] = cap_dicts
 5142             subprofile_dicts.append(subprofile_dict)
 5143     profile_dict["subprofiles"] = subprofile_dicts
 5144     return profile_dict
 5145 
 5146 
 5147 @depends(HAS_PYVMOMI)
 5148 @supports_proxies("esxdatacenter", "vcenter")
 5149 @gets_service_instance_via_proxy
 5150 def list_storage_policies(policy_names=None, service_instance=None):
 5151     """
 5152     Returns a list of storage policies.
 5153 
 5154     policy_names
 5155         Names of policies to list. If None, all policies are listed.
 5156         Default is None.
 5157 
 5158     service_instance
 5159         Service instance (vim.ServiceInstance) of the vCenter.
 5160         Default is None.
 5161 
 5162     .. code-block:: bash
 5163 
 5164         salt '*' vsphere.list_storage_policies
 5165 
 5166         salt '*' vsphere.list_storage_policy policy_names=[policy_name]
 5167     """
 5168     profile_manager = salt.utils.pbm.get_profile_manager(service_instance)
 5169     if not policy_names:
 5170         policies = salt.utils.pbm.get_storage_policies(
 5171             profile_manager, get_all_policies=True
 5172         )
 5173     else:
 5174         policies = salt.utils.pbm.get_storage_policies(profile_manager, policy_names)
 5175     return [_get_policy_dict(p) for p in policies]
 5176 
 5177 
 5178 @depends(HAS_PYVMOMI)
 5179 @supports_proxies("esxdatacenter", "vcenter")
 5180 @gets_service_instance_via_proxy
 5181 def list_default_vsan_policy(service_instance=None):
 5182     """
 5183     Returns the default vsan storage policy.
 5184 
 5185     service_instance
 5186         Service instance (vim.ServiceInstance) of the vCenter.
 5187         Default is None.
 5188 
 5189     .. code-block:: bash
 5190 
 5191         salt '*' vsphere.list_storage_policies
 5192 
 5193         salt '*' vsphere.list_storage_policy policy_names=[policy_name]
 5194     """
 5195     profile_manager = salt.utils.pbm.get_profile_manager(service_instance)
 5196     policies = salt.utils.pbm.get_storage_policies(
 5197         profile_manager, get_all_policies=True
 5198     )
 5199     def_policies = [
 5200         p for p in policies if p.systemCreatedProfileType == "VsanDefaultProfile"
 5201     ]
 5202     if not def_policies:
 5203         raise VMwareObjectRetrievalError("Default VSAN policy was not " "retrieved")
 5204     return _get_policy_dict(def_policies[0])
 5205 
 5206 
 5207 def _get_capability_definition_dict(cap_metadata):
 5208     # We assume each capability definition has one property with the same id
 5209     # as the capability so we display its type as belonging to the capability
 5210     # The object model permits multiple properties
 5211     return {
 5212         "namespace": cap_metadata.id.namespace,
 5213         "id": cap_metadata.id.id,
 5214         "mandatory": cap_metadata.mandatory,
 5215         "description": cap_metadata.summary.summary,
 5216         "type": cap_metadata.propertyMetadata[0].type.typeName,
 5217     }
 5218 
 5219 
 5220 @depends(HAS_PYVMOMI)
 5221 @supports_proxies("esxdatacenter", "vcenter")
 5222 @gets_service_instance_via_proxy
 5223 def list_capability_definitions(service_instance=None):
 5224     """
 5225     Returns a list of the metadata of all capabilities in the vCenter.
 5226 
 5227     service_instance
 5228         Service instance (vim.ServiceInstance) of the vCenter.
 5229         Default is None.
 5230 
 5231     .. code-block:: bash
 5232 
 5233         salt '*' vsphere.list_capabilities
 5234     """
 5235     profile_manager = salt.utils.pbm.get_profile_manager(service_instance)
 5236     ret_list = [
 5237         _get_capability_definition_dict(c)
 5238         for c in salt.utils.pbm.get_capability_definitions(profile_manager)
 5239     ]
 5240     return ret_list
 5241 
 5242 
 5243 def _apply_policy_config(policy_spec, policy_dict):
 5244     """Applies a policy dictionary to a policy spec"""
 5245     log.trace("policy_dict = {}".format(policy_dict))
 5246     if policy_dict.get("name"):
 5247         policy_spec.name = policy_dict["name"]
 5248     if policy_dict.get("description"):
 5249         policy_spec.description = policy_dict["description"]
 5250     if policy_dict.get("subprofiles"):
 5251         # Incremental changes to subprofiles and capabilities are not
 5252         # supported because they would complicate updates too much
 5253         # The whole configuration of all sub-profiles is expected and applied
 5254         policy_spec.constraints = pbm.profile.SubProfileCapabilityConstraints()
 5255         subprofiles = []
 5256         for subprofile_dict in policy_dict["subprofiles"]:
 5257             subprofile_spec = pbm.profile.SubProfileCapabilityConstraints.SubProfile(
 5258                 name=subprofile_dict["name"]
 5259             )
 5260             cap_specs = []
 5261             if subprofile_dict.get("force_provision"):
 5262                 subprofile_spec.forceProvision = subprofile_dict["force_provision"]
 5263             for cap_dict in subprofile_dict["capabilities"]:
 5264                 prop_inst_spec = pbm.capability.PropertyInstance(id=cap_dict["id"])
 5265                 setting_type = cap_dict["setting"]["type"]
 5266                 if setting_type == "set":
 5267                     prop_inst_spec.value = pbm.capability.types.DiscreteSet()
 5268                     prop_inst_spec.value.values = cap_dict["setting"]["values"]
 5269                 elif setting_type == "range":
 5270                     prop_inst_spec.value = pbm.capability.types.Range()
 5271                     prop_inst_spec.value.max = cap_dict["setting"]["max"]
 5272                     prop_inst_spec.value.min = cap_dict["setting"]["min"]
 5273                 elif setting_type == "scalar":
 5274                     prop_inst_spec.value = cap_dict["setting"]["value"]
 5275                 cap_spec = pbm.capability.CapabilityInstance(
 5276                     id=pbm.capability.CapabilityMetadata.UniqueId(
 5277                         id=cap_dict["id"], namespace=cap_dict["namespace"]
 5278                     ),
 5279                     constraint=[
 5280                         pbm.capability.ConstraintInstance(
 5281                             propertyInstance=[prop_inst_spec]
 5282                         )
 5283                     ],
 5284                 )
 5285                 cap_specs.append(cap_spec)
 5286             subprofile_spec.capability = cap_specs
 5287             subprofiles.append(subprofile_spec)
 5288         policy_spec.constraints.subProfiles = subprofiles
 5289     log.trace("updated policy_spec = {}".format(policy_spec))
 5290     return policy_spec
 5291 
 5292 
 5293 @depends(HAS_PYVMOMI)
 5294 @supports_proxies("esxdatacenter", "vcenter")
 5295 @gets_service_instance_via_proxy
 5296 def create_storage_policy(policy_name, policy_dict, service_instance=None):
 5297     """
 5298     Creates a storage policy.
 5299 
 5300     Supported capability types: scalar, set, range.
 5301 
 5302     policy_name
 5303         Name of the policy to create.
 5304         The value of the argument will override any existing name in
 5305         ``policy_dict``.
 5306 
 5307     policy_dict
 5308         Dictionary containing the changes to apply to the policy.
 5309         (example in salt.states.pbm)
 5310 
 5311     service_instance
 5312         Service instance (vim.ServiceInstance) of the vCenter.
 5313         Default is None.
 5314 
 5315     .. code-block:: bash
 5316 
 5317         salt '*' vsphere.create_storage_policy policy_name='policy name'
 5318             policy_dict="$policy_dict"
 5319     """
 5320     log.trace(
 5321         "create storage policy '{}', dict = {}" "".format(policy_name, policy_dict)
 5322     )
 5323     profile_manager = salt.utils.pbm.get_profile_manager(service_instance)
 5324     policy_create_spec = pbm.profile.CapabilityBasedProfileCreateSpec()
 5325     # Hardcode the storage profile resource type
 5326     policy_create_spec.resourceType = pbm.profile.ResourceType(
 5327         resourceType=pbm.profile.ResourceTypeEnum.STORAGE
 5328     )
 5329     # Set name argument
 5330     policy_dict["name"] = policy_name
 5331     log.trace("Setting policy values in policy_update_spec")
 5332     _apply_policy_config(policy_create_spec, policy_dict)
 5333     salt.utils.pbm.create_storage_policy(profile_manager, policy_create_spec)
 5334     return {"create_storage_policy": True}
 5335 
 5336 
 5337 @depends(HAS_PYVMOMI)
 5338 @supports_proxies("esxdatacenter", "vcenter")
 5339 @gets_service_instance_via_proxy
 5340 def update_storage_policy(policy, policy_dict, service_instance=None):
 5341     """
 5342     Updates a storage policy.
 5343 
 5344     Supported capability types: scalar, set, range.
 5345 
 5346     policy
 5347         Name of the policy to update.
 5348 
 5349     policy_dict
 5350         Dictionary containing the changes to apply to the policy.
 5351         (example in salt.states.pbm)
 5352 
 5353     service_instance
 5354         Service instance (vim.ServiceInstance) of the vCenter.
 5355         Default is None.
 5356 
 5357     .. code-block:: bash
 5358 
 5359         salt '*' vsphere.update_storage_policy policy='policy name'
 5360             policy_dict="$policy_dict"
 5361     """
 5362     log.trace("updating storage policy, dict = {}".format(policy_dict))
 5363     profile_manager = salt.utils.pbm.get_profile_manager(service_instance)
 5364     policies = salt.utils.pbm.get_storage_policies(profile_manager, [policy])
 5365     if not policies:
 5366         raise VMwareObjectRetrievalError("Policy '{}' was not found" "".format(policy))
 5367     policy_ref = policies[0]
 5368     policy_update_spec = pbm.profile.CapabilityBasedProfileUpdateSpec()
 5369     log.trace("Setting policy values in policy_update_spec")
 5370     for prop in ["description", "constraints"]:
 5371         setattr(policy_update_spec, prop, getattr(policy_ref, prop))
 5372     _apply_policy_config(policy_update_spec, policy_dict)
 5373     salt.utils.pbm.update_storage_policy(
 5374         profile_manager, policy_ref, policy_update_spec
 5375     )
 5376     return {"update_storage_policy": True}
 5377 
 5378 
 5379 @depends(HAS_PYVMOMI)
 5380 @supports_proxies("esxcluster", "esxdatacenter", "vcenter")
 5381 @gets_service_instance_via_proxy
 5382 def list_default_storage_policy_of_datastore(datastore, service_instance=None):
 5383     """
 5384     Returns a list of datastores assign the storage policies.
 5385 
 5386     datastore
 5387         Name of the datastore to assign.
 5388         The datastore needs to be visible to the VMware entity the proxy
 5389         points to.
 5390 
 5391     service_instance
 5392         Service instance (vim.ServiceInstance) of the vCenter.
 5393         Default is None.
 5394 
 5395     .. code-block:: bash
 5396 
 5397         salt '*' vsphere.list_default_storage_policy_of_datastore datastore=ds1
 5398     """
 5399     log.trace(
 5400         "Listing the default storage policy of datastore '{}'" "".format(datastore)
 5401     )
 5402     # Find datastore
 5403     target_ref = _get_proxy_target(service_instance)
 5404     ds_refs = salt.utils.vmware.get_datastores(
 5405         service_instance, target_ref, datastore_names=[datastore]
 5406     )
 5407     if not ds_refs:
 5408         raise VMwareObjectRetrievalError(
 5409             "Datastore '{}' was not " "found".format(datastore)
 5410         )
 5411     profile_manager = salt.utils.pbm.get_profile_manager(service_instance)
 5412     policy = salt.utils.pbm.get_default_storage_policy_of_datastore(
 5413         profile_manager, ds_refs[0]
 5414     )
 5415     return _get_policy_dict(policy)
 5416 
 5417 
 5418 @depends(HAS_PYVMOMI)
 5419 @supports_proxies("esxcluster", "esxdatacenter", "vcenter")
 5420 @gets_service_instance_via_proxy
 5421 def assign_default_storage_policy_to_datastore(
 5422     policy, datastore, service_instance=None
 5423 ):
 5424     """
 5425     Assigns a storage policy as the default policy to a datastore.
 5426 
 5427     policy
 5428         Name of the policy to assign.
 5429 
 5430     datastore
 5431         Name of the datastore to assign.
 5432         The datastore needs to be visible to the VMware entity the proxy
 5433         points to.
 5434 
 5435     service_instance
 5436         Service instance (vim.ServiceInstance) of the vCenter.
 5437         Default is None.
 5438 
 5439     .. code-block:: bash
 5440 
 5441         salt '*' vsphere.assign_storage_policy_to_datastore
 5442             policy='policy name' datastore=ds1
 5443     """
 5444     log.trace("Assigning policy {} to datastore {}" "".format(policy, datastore))
 5445     profile_manager = salt.utils.pbm.get_profile_manager(service_instance)
 5446     # Find policy
 5447     policies = salt.utils.pbm.get_storage_policies(profile_manager, [policy])
 5448     if not policies:
 5449         raise VMwareObjectRetrievalError("Policy '{}' was not found" "".format(policy))
 5450     policy_ref = policies[0]
 5451     # Find datastore
 5452     target_ref = _get_proxy_target(service_instance)
 5453     ds_refs = salt.utils.vmware.get_datastores(
 5454         service_instance, target_ref, datastore_names=[datastore]
 5455     )
 5456     if not ds_refs:
 5457         raise VMwareObjectRetrievalError(
 5458             "Datastore '{}' was not " "found".format(datastore)
 5459         )
 5460     ds_ref = ds_refs[0]
 5461     salt.utils.pbm.assign_default_storage_policy_to_datastore(
 5462         profile_manager, policy_ref, ds_ref
 5463     )
 5464     return True
 5465 
 5466 
 5467 @depends(HAS_PYVMOMI)
 5468 @supports_proxies("esxdatacenter", "esxcluster", "vcenter", "esxvm")
 5469 @gets_service_instance_via_proxy
 5470 def list_datacenters_via_proxy(datacenter_names=None, service_instance=None):
 5471     """
 5472     Returns a list of dict representations of VMware datacenters.
 5473     Connection is done via the proxy details.
 5474 
 5475     Supported proxies: esxdatacenter
 5476 
 5477     datacenter_names
 5478         List of datacenter names.
 5479         Default is None.
 5480 
 5481     service_instance
 5482         Service instance (vim.ServiceInstance) of the vCenter.
 5483         Default is None.
 5484 
 5485     .. code-block:: bash
 5486 
 5487         salt '*' vsphere.list_datacenters_via_proxy
 5488 
 5489         salt '*' vsphere.list_datacenters_via_proxy dc1
 5490 
 5491         salt '*' vsphere.list_datacenters_via_proxy dc1,dc2
 5492 
 5493         salt '*' vsphere.list_datacenters_via_proxy datacenter_names=[dc1, dc2]
 5494     """
 5495     if not datacenter_names:
 5496         dc_refs = salt.utils.vmware.get_datacenters(
 5497             service_instance, get_all_datacenters=True
 5498         )
 5499     else:
 5500         dc_refs = salt.utils.vmware.get_datacenters(service_instance, datacenter_names)
 5501 
 5502     return [
 5503         {"name": salt.utils.vmware.get_managed_object_name(dc_ref)}
 5504         for dc_ref in dc_refs
 5505     ]
 5506 
 5507 
 5508 @depends(HAS_PYVMOMI)
 5509 @supports_proxies("esxdatacenter", "vcenter")
 5510 @gets_service_instance_via_proxy
 5511 def create_datacenter(datacenter_name, service_instance=None):
 5512     """
 5513     Creates a datacenter.
 5514 
 5515     Supported proxies: esxdatacenter
 5516 
 5517     datacenter_name
 5518         The datacenter name
 5519 
 5520     service_instance
 5521         Service instance (vim.ServiceInstance) of the vCenter.
 5522         Default is None.
 5523 
 5524     .. code-block:: bash
 5525 
 5526         salt '*' vsphere.create_datacenter dc1
 5527     """
 5528     salt.utils.vmware.create_datacenter(service_instance, datacenter_name)
 5529     return {"create_datacenter": True}
 5530 
 5531 
 5532 def _get_cluster_dict(cluster_name, cluster_ref):
 5533     """
 5534     Returns a cluster dict representation from
 5535     a vim.ClusterComputeResource object.
 5536 
 5537     cluster_name
 5538         Name of the cluster
 5539 
 5540     cluster_ref
 5541         Reference to the cluster
 5542     """
 5543 
 5544     log.trace(
 5545         "Building a dictionary representation of cluster " "'{}'".format(cluster_name)
 5546     )
 5547     props = salt.utils.vmware.get_properties_of_managed_object(
 5548         cluster_ref, properties=["configurationEx"]
 5549     )
 5550     res = {
 5551         "ha": {"enabled": props["configurationEx"].dasConfig.enabled},
 5552         "drs": {"enabled": props["configurationEx"].drsConfig.enabled},
 5553     }
 5554     # Convert HA properties of interest
 5555     ha_conf = props["configurationEx"].dasConfig
 5556     log.trace("ha_conf = {}".format(ha_conf))
 5557     res["ha"]["admission_control_enabled"] = ha_conf.admissionControlEnabled
 5558     if ha_conf.admissionControlPolicy and isinstance(
 5559         ha_conf.admissionControlPolicy,
 5560         vim.ClusterFailoverResourcesAdmissionControlPolicy,
 5561     ):
 5562         pol = ha_conf.admissionControlPolicy
 5563         res["ha"]["admission_control_policy"] = {
 5564             "cpu_failover_percent": pol.cpuFailoverResourcesPercent,
 5565             "memory_failover_percent": pol.memoryFailoverResourcesPercent,
 5566         }
 5567     if ha_conf.defaultVmSettings:
 5568         def_vm_set = ha_conf.defaultVmSettings
 5569         res["ha"]["default_vm_settings"] = {
 5570             "isolation_response": def_vm_set.isolationResponse,
 5571             "restart_priority": def_vm_set.restartPriority,
 5572         }
 5573     res["ha"]["hb_ds_candidate_policy"] = ha_conf.hBDatastoreCandidatePolicy
 5574     if ha_conf.hostMonitoring:
 5575         res["ha"]["host_monitoring"] = ha_conf.hostMonitoring
 5576     if ha_conf.option:
 5577         res["ha"]["options"] = [
 5578             {"key": o.key, "value": o.value} for o in ha_conf.option
 5579         ]
 5580     res["ha"]["vm_monitoring"] = ha_conf.vmMonitoring
 5581     # Convert DRS properties
 5582     drs_conf = props["configurationEx"].drsConfig
 5583     log.trace("drs_conf = {}".format(drs_conf))
 5584     res["drs"]["vmotion_rate"] = 6 - drs_conf.vmotionRate
 5585     res["drs"]["default_vm_behavior"] = drs_conf.defaultVmBehavior
 5586     # vm_swap_placement
 5587     res["vm_swap_placement"] = props["configurationEx"].vmSwapPlacement
 5588     # Convert VSAN properties
 5589     si = salt.utils.vmware.get_service_instance_from_managed_object(cluster_ref)
 5590 
 5591     if salt.utils.vsan.vsan_supported(si):
 5592         # XXX The correct way of retrieving the VSAN data (on the if branch)
 5593         #  is not supported before 60u2 vcenter
 5594         vcenter_info = salt.utils.vmware.get_service_info(si)
 5595         if int(vcenter_info.build) >= 3634794:  # 60u2
 5596             # VSAN API is fully supported by the VC starting with 60u2
 5597             vsan_conf = salt.utils.vsan.get_cluster_vsan_info(cluster_ref)
 5598             log.trace("vsan_conf = {}".format(vsan_conf))
 5599             res["vsan"] = {
 5600                 "enabled": vsan_conf.enabled,
 5601                 "auto_claim_storage": vsan_conf.defaultConfig.autoClaimStorage,
 5602             }
 5603             if vsan_conf.dataEfficiencyConfig:
 5604                 data_eff = vsan_conf.dataEfficiencyConfig
 5605                 res["vsan"].update(
 5606                     {
 5607                         # We force compression_enabled to be True/False
 5608                         "compression_enabled": data_eff.compressionEnabled or False,
 5609                         "dedup_enabled": data_eff.dedupEnabled,
 5610                     }
 5611                 )
 5612         else:  # before 60u2 (no advanced vsan info)
 5613             if props["configurationEx"].vsanConfigInfo:
 5614                 default_config = props["configurationEx"].vsanConfigInfo.defaultConfig
 5615                 res["vsan"] = {
 5616                     "enabled": props["configurationEx"].vsanConfigInfo.enabled,
 5617                     "auto_claim_storage": default_config.autoClaimStorage,
 5618                 }
 5619     return res
 5620 
 5621 
 5622 @depends(HAS_PYVMOMI)
 5623 @supports_proxies("esxcluster", "esxdatacenter")
 5624 @gets_service_instance_via_proxy
 5625 def list_cluster(datacenter=None, cluster=None, service_instance=None):
 5626     """
 5627     Returns a dict representation of an ESX cluster.
 5628 
 5629     datacenter
 5630         Name of datacenter containing the cluster.
 5631         Ignored if already contained by proxy details.
 5632         Default value is None.
 5633 
 5634     cluster
 5635         Name of cluster.
 5636         Ignored if already contained by proxy details.
 5637         Default value is None.
 5638 
 5639     service_instance
 5640         Service instance (vim.ServiceInstance) of the vCenter.
 5641         Default is None.
 5642 
 5643     .. code-block:: bash
 5644 
 5645         # vcenter proxy
 5646         salt '*' vsphere.list_cluster datacenter=dc1 cluster=cl1
 5647 
 5648         # esxdatacenter proxy
 5649         salt '*' vsphere.list_cluster cluster=cl1
 5650 
 5651         # esxcluster proxy
 5652         salt '*' vsphere.list_cluster
 5653     """
 5654     proxy_type = get_proxy_type()
 5655     if proxy_type == "esxdatacenter":
 5656         dc_ref = _get_proxy_target(service_instance)
 5657         if not cluster:
 5658             raise ArgumentValueError("'cluster' needs to be specified")
 5659         cluster_ref = salt.utils.vmware.get_cluster(dc_ref, cluster)
 5660     elif proxy_type == "esxcluster":
 5661         cluster_ref = _get_proxy_target(service_instance)
 5662         cluster = __salt__["esxcluster.get_details"]()["cluster"]
 5663     log.trace(
 5664         "Retrieving representation of cluster '{}' in a "
 5665         "{} proxy".format(cluster, proxy_type)
 5666     )
 5667     return _get_cluster_dict(cluster, cluster_ref)
 5668 
 5669 
 5670 def _apply_cluster_dict(cluster_spec, cluster_dict, vsan_spec=None, vsan_61=True):
 5671     """
 5672     Applies the values of cluster_dict dictionary to a cluster spec
 5673     (vim.ClusterConfigSpecEx).
 5674 
 5675     All vsan values (cluster_dict['vsan']) will be applied to
 5676     vsan_spec (vim.vsan.cluster.ConfigInfoEx). Can be not omitted
 5677     if not required.
 5678 
 5679     VSAN 6.1 config needs to be applied differently than the post VSAN 6.1 way.
 5680     The type of configuration desired is dictated by the flag vsan_61.
 5681     """
 5682     log.trace("Applying cluster dict {}".format(cluster_dict))
 5683     if cluster_dict.get("ha"):
 5684         ha_dict = cluster_dict["ha"]
 5685         if not cluster_spec.dasConfig:
 5686             cluster_spec.dasConfig = vim.ClusterDasConfigInfo()
 5687         das_config = cluster_spec.dasConfig
 5688         if "enabled" in ha_dict:
 5689             das_config.enabled = ha_dict["enabled"]
 5690             if ha_dict["enabled"]:
 5691                 # Default values when ha is enabled
 5692                 das_config.failoverLevel = 1
 5693         if "admission_control_enabled" in ha_dict:
 5694             das_config.admissionControlEnabled = ha_dict["admission_control_enabled"]
 5695         if "admission_control_policy" in ha_dict:
 5696             adm_pol_dict = ha_dict["admission_control_policy"]
 5697             if not das_config.admissionControlPolicy or not isinstance(
 5698                 das_config.admissionControlPolicy,
 5699                 vim.ClusterFailoverResourcesAdmissionControlPolicy,
 5700             ):
 5701 
 5702                 das_config.admissionControlPolicy = vim.ClusterFailoverResourcesAdmissionControlPolicy(
 5703                     cpuFailoverResourcesPercent=adm_pol_dict["cpu_failover_percent"],
 5704                     memoryFailoverResourcesPercent=adm_pol_dict[
 5705                         "memory_failover_percent"
 5706                     ],
 5707                 )
 5708         if "default_vm_settings" in ha_dict:
 5709             vm_set_dict = ha_dict["default_vm_settings"]
 5710             if not das_config.defaultVmSettings:
 5711                 das_config.defaultVmSettings = vim.ClusterDasVmSettings()
 5712             if "isolation_response" in vm_set_dict:
 5713                 das_config.defaultVmSettings.isolationResponse = vm_set_dict[
 5714                     "isolation_response"
 5715                 ]
 5716             if "restart_priority" in vm_set_dict:
 5717                 das_config.defaultVmSettings.restartPriority = vm_set_dict[
 5718                     "restart_priority"
 5719                 ]
 5720         if "hb_ds_candidate_policy" in ha_dict:
 5721             das_config.hBDatastoreCandidatePolicy = ha_dict["hb_ds_candidate_policy"]
 5722         if "host_monitoring" in ha_dict:
 5723             das_config.hostMonitoring = ha_dict["host_monitoring"]
 5724         if "options" in ha_dict:
 5725             das_config.option = []
 5726             for opt_dict in ha_dict["options"]:
 5727                 das_config.option.append(vim.OptionValue(key=opt_dict["key"]))
 5728                 if "value" in opt_dict:
 5729                     das_config.option[-1].value = opt_dict["value"]
 5730         if "vm_monitoring" in ha_dict:
 5731             das_config.vmMonitoring = ha_dict["vm_monitoring"]
 5732         cluster_spec.dasConfig = das_config
 5733     if cluster_dict.get("drs"):
 5734         drs_dict = cluster_dict["drs"]
 5735         drs_config = vim.ClusterDrsConfigInfo()
 5736         if "enabled" in drs_dict:
 5737             drs_config.enabled = drs_dict["enabled"]
 5738         if "vmotion_rate" in drs_dict:
 5739             drs_config.vmotionRate = 6 - drs_dict["vmotion_rate"]
 5740         if "default_vm_behavior" in drs_dict:
 5741             drs_config.defaultVmBehavior = vim.DrsBehavior(
 5742                 drs_dict["default_vm_behavior"]
 5743             )
 5744         cluster_spec.drsConfig = drs_config
 5745     if cluster_dict.get("vm_swap_placement"):
 5746         cluster_spec.vmSwapPlacement = cluster_dict["vm_swap_placement"]
 5747     if cluster_dict.get("vsan"):
 5748         vsan_dict = cluster_dict["vsan"]
 5749         if not vsan_61:  # VSAN is 6.2 and above
 5750             if "enabled" in vsan_dict:
 5751                 if not vsan_spec.vsanClusterConfig:
 5752                     vsan_spec.vsanClusterConfig = vim.vsan.cluster.ConfigInfo()
 5753                 vsan_spec.vsanClusterConfig.enabled = vsan_dict["enabled"]
 5754             if "auto_claim_storage" in vsan_dict:
 5755                 if not vsan_spec.vsanClusterConfig:
 5756                     vsan_spec.vsanClusterConfig = vim.vsan.cluster.ConfigInfo()
 5757                 if not vsan_spec.vsanClusterConfig.defaultConfig:
 5758                     vsan_spec.vsanClusterConfig.defaultConfig = (
 5759                         vim.VsanClusterConfigInfoHostDefaultInfo()
 5760                     )
 5761                 elif vsan_spec.vsanClusterConfig.defaultConfig.uuid:
 5762                     # If this remains set it caused an error
 5763                     vsan_spec.vsanClusterConfig.defaultConfig.uuid = None
 5764                 vsan_spec.vsanClusterConfig.defaultConfig.autoClaimStorage = vsan_dict[
 5765                     "auto_claim_storage"
 5766                 ]
 5767             if "compression_enabled" in vsan_dict:
 5768                 if not vsan_spec.dataEfficiencyConfig:
 5769                     vsan_spec.dataEfficiencyConfig = vim.vsan.DataEfficiencyConfig()
 5770                 vsan_spec.dataEfficiencyConfig.compressionEnabled = vsan_dict[
 5771                     "compression_enabled"
 5772                 ]
 5773             if "dedup_enabled" in vsan_dict:
 5774                 if not vsan_spec.dataEfficiencyConfig:
 5775                     vsan_spec.dataEfficiencyConfig = vim.vsan.DataEfficiencyConfig()
 5776                 vsan_spec.dataEfficiencyConfig.dedupEnabled = vsan_dict["dedup_enabled"]
 5777         # In all cases we need to configure the vsan on the cluster
 5778         # directly so not to have a mismatch between vsan_spec and
 5779         # cluster_spec
 5780         if not cluster_spec.vsanConfig:
 5781             cluster_spec.vsanConfig = vim.VsanClusterConfigInfo()
 5782         vsan_config = cluster_spec.vsanConfig
 5783         if "enabled" in vsan_dict:
 5784             vsan_config.enabled = vsan_dict["enabled"]
 5785         if "auto_claim_storage" in vsan_dict:
 5786             if not vsan_config.defaultConfig:
 5787                 vsan_config.defaultConfig = vim.VsanClusterConfigInfoHostDefaultInfo()
 5788             elif vsan_config.defaultConfig.uuid:
 5789                 # If this remains set it caused an error
 5790                 vsan_config.defaultConfig.uuid = None
 5791             vsan_config.defaultConfig.autoClaimStorage = vsan_dict["auto_claim_storage"]
 5792     log.trace("cluster_spec = {}".format(cluster_spec))
 5793 
 5794 
 5795 @depends(HAS_PYVMOMI)
 5796 @depends(HAS_JSONSCHEMA)
 5797 @supports_proxies("esxcluster", "esxdatacenter")
 5798 @gets_service_instance_via_proxy
 5799 def create_cluster(cluster_dict, datacenter=None, cluster=None, service_instance=None):
 5800     """
 5801     Creates a cluster.
 5802 
 5803     Note: cluster_dict['name'] will be overridden by the cluster param value
 5804 
 5805     config_dict
 5806         Dictionary with the config values of the new cluster.
 5807 
 5808     datacenter
 5809         Name of datacenter containing the cluster.
 5810         Ignored if already contained by proxy details.
 5811         Default value is None.
 5812 
 5813     cluster
 5814         Name of cluster.
 5815         Ignored if already contained by proxy details.
 5816         Default value is None.
 5817 
 5818     service_instance
 5819         Service instance (vim.ServiceInstance) of the vCenter.
 5820         Default is None.
 5821 
 5822     .. code-block:: bash
 5823 
 5824         # esxdatacenter proxy
 5825         salt '*' vsphere.create_cluster cluster_dict=$cluster_dict cluster=cl1
 5826 
 5827         # esxcluster proxy
 5828         salt '*' vsphere.create_cluster cluster_dict=$cluster_dict
 5829     """
 5830     # Validate cluster dictionary
 5831     schema = ESXClusterConfigSchema.serialize()
 5832     try:
 5833         jsonschema.validate(cluster_dict, schema)
 5834     except jsonschema.exceptions.ValidationError as exc:
 5835         raise InvalidConfigError(exc)
 5836     # Get required details from the proxy
 5837     proxy_type = get_proxy_type()
 5838     if proxy_type == "esxdatacenter":
 5839         datacenter = __salt__["esxdatacenter.get_details"]()["datacenter"]
 5840         dc_ref = _get_proxy_target(service_instance)
 5841         if not cluster:
 5842             raise ArgumentValueError("'cluster' needs to be specified")
 5843     elif proxy_type == "esxcluster":
 5844         datacenter = __salt__["esxcluster.get_details"]()["datacenter"]
 5845         dc_ref = salt.utils.vmware.get_datacenter(service_instance, datacenter)
 5846         cluster = __salt__["esxcluster.get_details"]()["cluster"]
 5847 
 5848     if cluster_dict.get("vsan") and not salt.utils.vsan.vsan_supported(
 5849         service_instance
 5850     ):
 5851 
 5852         raise VMwareApiError("VSAN operations are not supported")
 5853     si = service_instance
 5854     cluster_spec = vim.ClusterConfigSpecEx()
 5855     vsan_spec = None
 5856     ha_config = None
 5857     vsan_61 = None
 5858     if cluster_dict.get("vsan"):
 5859         # XXX The correct way of retrieving the VSAN data (on the if branch)
 5860         #  is not supported before 60u2 vcenter
 5861         vcenter_info = salt.utils.vmware.get_service_info(si)
 5862         if (
 5863             float(vcenter_info.apiVersion) >= 6.0 and int(vcenter_info.build) >= 3634794
 5864         ):  # 60u2
 5865             vsan_spec = vim.vsan.ReconfigSpec(modify=True)
 5866             vsan_61 = False
 5867             # We need to keep HA disabled and enable it afterwards
 5868             if cluster_dict.get("ha", {}).get("enabled"):
 5869                 enable_ha = True
 5870                 ha_config = cluster_dict["ha"]
 5871                 del cluster_dict["ha"]
 5872         else:
 5873             vsan_61 = True
 5874     # If VSAN is 6.1 the configuration of VSAN happens when configuring the
 5875     # cluster via the regular endpoint
 5876     _apply_cluster_dict(cluster_spec, cluster_dict, vsan_spec, vsan_61)
 5877     salt.utils.vmware.create_cluster(dc_ref, cluster, cluster_spec)
 5878     if not vsan_61:
 5879         # Only available after VSAN 61
 5880         if vsan_spec:
 5881             cluster_ref = salt.utils.vmware.get_cluster(dc_ref, cluster)
 5882             salt.utils.vsan.reconfigure_cluster_vsan(cluster_ref, vsan_spec)
 5883         if enable_ha:
 5884             # Set HA after VSAN has been configured
 5885             _apply_cluster_dict(cluster_spec, {"ha": ha_config})
 5886             salt.utils.vmware.update_cluster(cluster_ref, cluster_spec)
 5887             # Set HA back on the object
 5888             cluster_dict["ha"] = ha_config
 5889     return {"create_cluster": True}
 5890 
 5891 
 5892 @depends(HAS_PYVMOMI)
 5893 @depends(HAS_JSONSCHEMA)
 5894 @supports_proxies("esxcluster", "esxdatacenter")
 5895 @gets_service_instance_via_proxy
 5896 def update_cluster(cluster_dict, datacenter=None, cluster=None, service_instance=None):
 5897     """
 5898     Updates a cluster.
 5899 
 5900     config_dict
 5901         Dictionary with the config values of the new cluster.
 5902 
 5903     datacenter
 5904         Name of datacenter containing the cluster.
 5905         Ignored if already contained by proxy details.
 5906         Default value is None.
 5907 
 5908     cluster
 5909         Name of cluster.
 5910         Ignored if already contained by proxy details.
 5911         Default value is None.
 5912 
 5913     service_instance
 5914         Service instance (vim.ServiceInstance) of the vCenter.
 5915         Default is None.
 5916 
 5917     .. code-block:: bash
 5918 
 5919         # esxdatacenter proxy
 5920         salt '*' vsphere.update_cluster cluster_dict=$cluster_dict cluster=cl1
 5921 
 5922         # esxcluster proxy
 5923         salt '*' vsphere.update_cluster cluster_dict=$cluster_dict
 5924 
 5925     """
 5926     # Validate cluster dictionary
 5927     schema = ESXClusterConfigSchema.serialize()
 5928     try:
 5929         jsonschema.validate(cluster_dict, schema)
 5930     except jsonschema.exceptions.ValidationError as exc:
 5931         raise InvalidConfigError(exc)
 5932     # Get required details from the proxy
 5933     proxy_type = get_proxy_type()
 5934     if proxy_type == "esxdatacenter":
 5935         datacenter = __salt__["esxdatacenter.get_details"]()["datacenter"]
 5936         dc_ref = _get_proxy_target(service_instance)
 5937         if not cluster:
 5938             raise ArgumentValueError("'cluster' needs to be specified")
 5939     elif proxy_type == "esxcluster":
 5940         datacenter = __salt__["esxcluster.get_details"]()["datacenter"]
 5941         dc_ref = salt.utils.vmware.get_datacenter(service_instance, datacenter)
 5942         cluster = __salt__["esxcluster.get_details"]()["cluster"]
 5943 
 5944     if cluster_dict.get("vsan") and not salt.utils.vsan.vsan_supported(
 5945         service_instance
 5946     ):
 5947 
 5948         raise VMwareApiError("VSAN operations are not supported")
 5949 
 5950     cluster_ref = salt.utils.vmware.get_cluster(dc_ref, cluster)
 5951     cluster_spec = vim.ClusterConfigSpecEx()
 5952     props = salt.utils.vmware.get_properties_of_managed_object(
 5953         cluster_ref, properties=["configurationEx"]
 5954     )
 5955     # Copy elements we want to update to spec
 5956     for p in ["dasConfig", "drsConfig"]:
 5957         setattr(cluster_spec, p, getattr(props["configurationEx"], p))
 5958     if props["configurationEx"].vsanConfigInfo:
 5959         cluster_spec.vsanConfig = props["configurationEx"].vsanConfigInfo
 5960     vsan_spec = None
 5961     vsan_61 = None
 5962     if cluster_dict.get("vsan"):
 5963         # XXX The correct way of retrieving the VSAN data (on the if branch)
 5964         #  is not supported before 60u2 vcenter
 5965         vcenter_info = salt.utils.vmware.get_service_info(service_instance)
 5966         if (
 5967             float(vcenter_info.apiVersion) >= 6.0 and int(vcenter_info.build) >= 3634794
 5968         ):  # 60u2
 5969             vsan_61 = False
 5970             vsan_info = salt.utils.vsan.get_cluster_vsan_info(cluster_ref)
 5971             vsan_spec = vim.vsan.ReconfigSpec(modify=True)
 5972             # Only interested in the vsanClusterConfig and the
 5973             # dataEfficiencyConfig
 5974             # vsan_spec.vsanClusterConfig = vsan_info
 5975             vsan_spec.dataEfficiencyConfig = vsan_info.dataEfficiencyConfig
 5976             vsan_info.dataEfficiencyConfig = None
 5977         else:
 5978             vsan_61 = True
 5979 
 5980     _apply_cluster_dict(cluster_spec, cluster_dict, vsan_spec, vsan_61)
 5981     # We try to reconfigure vsan first as it fails if HA is enabled so the
 5982     # command will abort not having any side-effects
 5983     # also if HA was previously disabled it can be enabled automatically if
 5984     # desired
 5985     if vsan_spec:
 5986         log.trace("vsan_spec = {}".format(vsan_spec))
 5987         salt.utils.vsan.reconfigure_cluster_vsan(cluster_ref, vsan_spec)
 5988 
 5989         # We need to retrieve again the properties and reapply them
 5990         # As the VSAN configuration has changed
 5991         cluster_spec = vim.ClusterConfigSpecEx()
 5992         props = salt.utils.vmware.get_properties_of_managed_object(
 5993             cluster_ref, properties=["configurationEx"]
 5994         )
 5995         # Copy elements we want to update to spec
 5996         for p in ["dasConfig", "drsConfig"]:
 5997             setattr(cluster_spec, p, getattr(props["configurationEx"], p))
 5998         if props["configurationEx"].vsanConfigInfo:
 5999             cluster_spec.vsanConfig = props["configurationEx"].vsanConfigInfo
 6000         # We only need to configure the cluster_spec, as if it were a vsan_61
 6001         # cluster
 6002         _apply_cluster_dict(cluster_spec, cluster_dict)
 6003     salt.utils.vmware.update_cluster(cluster_ref, cluster_spec)
 6004     return {"update_cluster": True}
 6005 
 6006 
 6007 @depends(HAS_PYVMOMI)
 6008 @supports_proxies("esxi", "esxcluster", "esxdatacenter")