/salt/modules/vsphere.py
Python | 4206 lines | 3448 code | 158 blank | 600 comment | 173 complexity | 15c137cf6ced75e692d988162a92f3ee MD5 | raw file
Possible License(s): Apache-2.0
- # -*- coding: utf-8 -*-
- '''
- Manage VMware vCenter servers and ESXi hosts.
- .. versionadded:: 2015.8.4
- :codeauthor: :email:`Alexandru Bleotu <alexandru.bleotu@morganstaley.com>`
- Dependencies
- ============
- - pyVmomi Python Module
- - ESXCLI
- pyVmomi
- -------
- PyVmomi can be installed via pip:
- .. code-block:: bash
- pip install pyVmomi
- .. note::
- Version 6.0 of pyVmomi has some problems with SSL error handling on certain
- versions of Python. If using version 6.0 of pyVmomi, Python 2.6,
- Python 2.7.9, or newer must be present. This is due to an upstream dependency
- in pyVmomi 6.0 that is not supported in Python versions 2.7 to 2.7.8. If the
- version of Python is not in the supported range, you will need to install an
- earlier version of pyVmomi. See `Issue #29537`_ for more information.
- .. _Issue #29537: https://github.com/saltstack/salt/issues/29537
- Based on the note above, to install an earlier version of pyVmomi than the
- version currently listed in PyPi, run the following:
- .. code-block:: bash
- pip install pyVmomi==5.5.0.2014.1.1
- The 5.5.0.2014.1.1 is a known stable version that this original vSphere Execution
- Module was developed against.
- ESXCLI
- ------
- Currently, about a third of the functions used in the vSphere Execution Module require
- the ESXCLI package be installed on the machine running the Proxy Minion process.
- The ESXCLI package is also referred to as the VMware vSphere CLI, or vCLI. VMware
- provides vCLI package installation instructions for `vSphere 5.5`_ and
- `vSphere 6.0`_.
- .. _vSphere 5.5: http://pubs.vmware.com/vsphere-55/index.jsp#com.vmware.vcli.getstart.doc/cli_install.4.2.html
- .. _vSphere 6.0: http://pubs.vmware.com/vsphere-60/index.jsp#com.vmware.vcli.getstart.doc/cli_install.4.2.html
- Once all of the required dependencies are in place and the vCLI package is
- installed, you can check to see if you can connect to your ESXi host or vCenter
- server by running the following command:
- .. code-block:: bash
- esxcli -s <host-location> -u <username> -p <password> system syslog config get
- If the connection was successful, ESXCLI was successfully installed on your system.
- You should see output related to the ESXi host's syslog configuration.
- .. note::
- Be aware that some functionality in this execution module may depend on the
- type of license attached to a vCenter Server or ESXi host(s).
- For example, certain services are only available to manipulate service state
- or policies with a VMware vSphere Enterprise or Enterprise Plus license, while
- others are available with a Standard license. The ``ntpd`` service is restricted
- to an Enterprise Plus license, while ``ssh`` is available via the Standard
- license.
- Please see the `vSphere Comparison`_ page for more information.
- .. _vSphere Comparison: https://www.vmware.com/products/vsphere/compare
- About
- =====
- This execution module was designed to be able to handle connections both to a
- vCenter Server, as well as to an ESXi host. It utilizes the pyVmomi Python
- library and the ESXCLI package to run remote execution functions against either
- the defined vCenter server or the ESXi host.
- Whether or not the function runs against a vCenter Server or an ESXi host depends
- entirely upon the arguments passed into the function. Each function requires a
- ``host`` location, ``username``, and ``password``. If the credentials provided
- apply to a vCenter Server, then the function will be run against the vCenter
- Server. For example, when listing hosts using vCenter credentials, you'll get a
- list of hosts associated with that vCenter Server:
- .. code-block:: bash
- # salt my-minion vsphere.list_hosts <vcenter-ip> <vcenter-user> <vcenter-password>
- my-minion:
- - esxi-1.example.com
- - esxi-2.example.com
- However, some functions should be used against ESXi hosts, not vCenter Servers.
- Functionality such as getting a host's coredump network configuration should be
- performed against a host and not a vCenter server. If the authentication information
- you're using is against a vCenter server and not an ESXi host, you can provide the
- host name that is associated with the vCenter server in the command, as a list, using
- the ``host_names`` or ``esxi_host`` kwarg. For example:
- .. code-block:: bash
- # salt my-minion vsphere.get_coredump_network_config <vcenter-ip> <vcenter-user> \
- <vcenter-password> esxi_hosts='[esxi-1.example.com, esxi-2.example.com]'
- my-minion:
- ----------
- esxi-1.example.com:
- ----------
- Coredump Config:
- ----------
- enabled:
- False
- esxi-2.example.com:
- ----------
- Coredump Config:
- ----------
- enabled:
- True
- host_vnic:
- vmk0
- ip:
- coredump-location.example.com
- port:
- 6500
- You can also use these functions against an ESXi host directly by establishing a
- connection to an ESXi host using the host's location, username, and password. If ESXi
- connection credentials are used instead of vCenter credentials, the ``host_names`` and
- ``esxi_hosts`` arguments are not needed.
- .. code-block:: bash
- # salt my-minion vsphere.get_coredump_network_config esxi-1.example.com root <host-password>
- local:
- ----------
- 10.4.28.150:
- ----------
- Coredump Config:
- ----------
- enabled:
- True
- host_vnic:
- vmk0
- ip:
- coredump-location.example.com
- port:
- 6500
- '''
- # Import Python Libs
- from __future__ import absolute_import
- import datetime
- import logging
- import sys
- import inspect
- from functools import wraps
- # Import Salt Libs
- import salt.ext.six as six
- import salt.utils
- import salt.utils.vmware
- import salt.utils.http
- from salt.utils import dictupdate
- from salt.exceptions import CommandExecutionError, VMwareSaltError
- from salt.utils.decorators import depends, ignores_kwargs
- from salt.utils import clean_kwargs
- # Import Third Party Libs
- try:
- from pyVmomi import vim, vmodl
- HAS_PYVMOMI = True
- except ImportError:
- HAS_PYVMOMI = False
- esx_cli = salt.utils.which('esxcli')
- if esx_cli:
- HAS_ESX_CLI = True
- else:
- HAS_ESX_CLI = False
- log = logging.getLogger(__name__)
- __virtualname__ = 'vsphere'
- __proxyenabled__ = ['esxi']
- def __virtual__():
- return __virtualname__
- def get_proxy_type():
- '''
- Returns the proxy type
- CLI Example:
- .. code-block:: bash
- salt '*' vsphere.get_proxy_type
- '''
- return __pillar__['proxy']['proxytype']
- def _get_proxy_connection_details():
- '''
- Returns the connection details of the following proxies: esxi
- '''
- proxytype = get_proxy_type()
- if proxytype == 'esxi':
- details = __salt__['esxi.get_details']()
- else:
- raise CommandExecutionError('\'{0}\' proxy is not supported'
- ''.format(proxytype))
- return \
- details.get('vcenter') if 'vcenter' in details \
- else details.get('host'), \
- details.get('username'), \
- details.get('password'), details.get('protocol'), \
- details.get('port'), details.get('mechanism'), \
- details.get('principal'), details.get('domain')
- def supports_proxies(*proxy_types):
- '''
- Decorator to specify which proxy types are supported by a function
- proxy_types:
- Arbitrary list of strings with the supported types of proxies
- '''
- def _supports_proxies(fn):
- def __supports_proxies(*args, **kwargs):
- proxy_type = get_proxy_type()
- if proxy_type not in proxy_types:
- raise CommandExecutionError(
- '\'{0}\' proxy is not supported by function {1}'
- ''.format(proxy_type, fn.__name__))
- return fn(*args, **clean_kwargs(**kwargs))
- return __supports_proxies
- return _supports_proxies
- def gets_service_instance_via_proxy(fn):
- '''
- Decorator that connects to a target system (vCenter or ESXi host) using the
- proxy details and passes the connection (vim.ServiceInstance) to
- the decorated function.
- Notes:
- 1. The decorated function must have a ``service_instance`` parameter
- or a ``**kwarg`` type argument (name of argument is not important);
- 2. If the ``service_instance`` parameter is already defined, the value
- is passed through to the decorated function;
- 3. If the ``service_instance`` parameter in not defined, the
- connection is created using the proxy details and the service instance
- is returned.
- CLI Example:
- None, this is a decorator
- '''
- fn_name = fn.__name__
- try:
- arg_names, args_name, kwargs_name, default_values, _, _, _ = \
- inspect.getfullargspec(fn)
- except AttributeError:
- # Fallback to Python 2.7
- arg_names, args_name, kwargs_name, default_values = \
- inspect.getargspec(fn)
- default_values = default_values if default_values is not None else []
- @wraps(fn)
- def _gets_service_instance_via_proxy(*args, **kwargs):
- if 'service_instance' not in arg_names and not kwargs_name:
- raise CommandExecutionError(
- 'Function {0} must have either a \'service_instance\', or a '
- '\'**kwargs\' type parameter'.format(fn_name))
- connection_details = _get_proxy_connection_details()
- # Figure out how to pass in the connection value
- local_service_instance = None
- if 'service_instance' in arg_names:
- idx = arg_names.index('service_instance')
- if idx >= len(arg_names) - len(default_values):
- # 'service_instance' has a default value:
- # we check if we need to instantiate it or
- # pass it through
- #
- # NOTE: if 'service_instance' doesn't have a default value
- # it must be explicitly set in the function call so we pass it
- # through
- # There are two cases:
- # 1. service_instance was passed in as a positional parameter
- # 2. service_instance was passed in as a named paramter
- if len(args) > idx:
- # case 1: The call was made with enough positional
- # parameters to include 'service_instance'
- if not args[idx]:
- local_service_instance = \
- salt.utils.vmware.get_service_instance(
- *connection_details)
- args[idx] = local_service_instance
- else:
- # case 2: Not enough positional parameters so
- # 'service_instance' must be a named parameter
- if not kwargs.get('service_instance'):
- local_service_instance = \
- salt.utils.vmware.get_service_instance(
- *connection_details)
- kwargs['service_instance'] = local_service_instance
- else:
- # 'service_instance' is not a paremter in the function definition
- # but it will be caught by the **kwargs parameter
- if not kwargs.get('service_instance'):
- local_service_instance = \
- salt.utils.vmware.get_service_instance(
- *connection_details)
- kwargs['service_instance'] = local_service_instance
- try:
- ret = fn(*args, **clean_kwargs(**kwargs))
- # Disconnect if connected in the decorator
- if local_service_instance:
- salt.utils.vmware.disconnect(local_service_instance)
- return ret
- except Exception as e:
- # Disconnect if connected in the decorator
- if local_service_instance:
- salt.utils.vmware.disconnect(local_service_instance)
- # raise original exception and traceback
- six.reraise(*sys.exc_info())
- return _gets_service_instance_via_proxy
- @supports_proxies('esxi')
- def get_service_instance_via_proxy(service_instance=None):
- '''
- Returns a service instance to the proxied endpoint (vCenter/ESXi host).
- Note:
- Should be used by state functions not invoked directly.
- CLI Example:
- See note above
- '''
- connection_details = _get_proxy_connection_details()
- return salt.utils.vmware.get_service_instance(*connection_details)
- @supports_proxies('esxi')
- def disconnect(service_instance):
- '''
- Disconnects from a vCenter or ESXi host
- Note:
- Should be used by state functions, not invoked directly.
- service_instance
- Service instance (vim.ServiceInstance)
- CLI Example:
- See note above.
- '''
- salt.utils.vmware.disconnect(service_instance)
- return True
- @depends(HAS_ESX_CLI)
- def esxcli_cmd(cmd_str, host=None, username=None, password=None, protocol=None, port=None, esxi_hosts=None, credstore=None):
- '''
- Run an ESXCLI command directly on the host or list of hosts.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- cmd_str
- The ESXCLI command to run. Note: This should not include the ``-s``, ``-u``,
- ``-p``, ``-h``, ``--protocol``, or ``--portnumber`` arguments that are
- frequently passed when using a bare ESXCLI command from the command line.
- Those arguments are handled by this function via the other args and kwargs.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- esxi_hosts
- If ``host`` is a vCenter host, then use esxi_hosts to execute this function
- on a list of one or more ESXi machines.
- credstore
- Optionally set to path to the credential store file.
- CLI Example:
- .. code-block:: bash
- # Used for ESXi host connection information
- salt '*' vsphere.esxcli_cmd my.esxi.host root bad-password \
- 'system coredump network get'
- # Used for connecting to a vCenter Server
- salt '*' vsphere.esxcli_cmd my.vcenter.location root bad-password \
- 'system coredump network get' esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
- '''
- ret = {}
- if esxi_hosts:
- if not isinstance(esxi_hosts, list):
- raise CommandExecutionError('\'esxi_hosts\' must be a list.')
- for esxi_host in esxi_hosts:
- response = salt.utils.vmware.esxcli(host, username, password, cmd_str,
- protocol=protocol, port=port,
- esxi_host=esxi_host, credstore=credstore)
- if response['retcode'] != 0:
- ret.update({esxi_host: {'Error': response.get('stdout')}})
- else:
- ret.update({esxi_host: response})
- else:
- # Handles a single host or a vCenter connection when no esxi_hosts are provided.
- response = salt.utils.vmware.esxcli(host, username, password, cmd_str,
- protocol=protocol, port=port,
- credstore=credstore)
- if response['retcode'] != 0:
- ret.update({host: {'Error': response.get('stdout')}})
- else:
- ret.update({host: response})
- return ret
- @depends(HAS_ESX_CLI)
- def get_coredump_network_config(host, username, password, protocol=None, port=None, esxi_hosts=None, credstore=None):
- '''
- Retrieve information on ESXi or vCenter network dump collection and
- format it into a dictionary.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- esxi_hosts
- If ``host`` is a vCenter host, then use esxi_hosts to execute this function
- on a list of one or more ESXi machines.
- credstore
- Optionally set to path to the credential store file.
- :return: A dictionary with the network configuration, or, if getting
- the network config failed, a an error message retrieved from the
- standard cmd.run_all dictionary, per host.
- CLI Example:
- .. code-block:: bash
- # Used for ESXi host connection information
- salt '*' vsphere.get_coredump_network_config my.esxi.host root bad-password
- # Used for connecting to a vCenter Server
- salt '*' vsphere.get_coredump_network_config my.vcenter.location root bad-password \
- esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
- '''
- cmd = 'system coredump network get'
- ret = {}
- if esxi_hosts:
- if not isinstance(esxi_hosts, list):
- raise CommandExecutionError('\'esxi_hosts\' must be a list.')
- for esxi_host in esxi_hosts:
- response = salt.utils.vmware.esxcli(host, username, password, cmd,
- protocol=protocol, port=port,
- esxi_host=esxi_host, credstore=credstore)
- if response['retcode'] != 0:
- ret.update({esxi_host: {'Error': response.get('stdout')}})
- else:
- # format the response stdout into something useful
- ret.update({esxi_host: {'Coredump Config': _format_coredump_stdout(response)}})
- else:
- # Handles a single host or a vCenter connection when no esxi_hosts are provided.
- response = salt.utils.vmware.esxcli(host, username, password, cmd,
- protocol=protocol, port=port,
- credstore=credstore)
- if response['retcode'] != 0:
- ret.update({host: {'Error': response.get('stdout')}})
- else:
- # format the response stdout into something useful
- stdout = _format_coredump_stdout(response)
- ret.update({host: {'Coredump Config': stdout}})
- return ret
- @depends(HAS_ESX_CLI)
- def coredump_network_enable(host, username, password, enabled, protocol=None, port=None, esxi_hosts=None, credstore=None):
- '''
- Enable or disable ESXi core dump collection. Returns ``True`` if coredump is enabled
- and returns ``False`` if core dump is not enabled. If there was an error, the error
- will be the value printed in the ``Error`` key dictionary for the given host.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- enabled
- Python True or False to enable or disable coredumps.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- esxi_hosts
- If ``host`` is a vCenter host, then use esxi_hosts to execute this function
- on a list of one or more ESXi machines.
- credstore
- Optionally set to path to the credential store file.
- CLI Example:
- .. code-block:: bash
- # Used for ESXi host connection information
- salt '*' vsphere.coredump_network_enable my.esxi.host root bad-password True
- # Used for connecting to a vCenter Server
- salt '*' vsphere.coredump_network_enable my.vcenter.location root bad-password True \
- esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
- '''
- if enabled:
- enable_it = 1
- else:
- enable_it = 0
- cmd = 'system coredump network set -e {0}'.format(enable_it)
- ret = {}
- if esxi_hosts:
- if not isinstance(esxi_hosts, list):
- raise CommandExecutionError('\'esxi_hosts\' must be a list.')
- for esxi_host in esxi_hosts:
- response = salt.utils.vmware.esxcli(host, username, password, cmd,
- protocol=protocol, port=port,
- esxi_host=esxi_host, credstore=credstore)
- if response['retcode'] != 0:
- ret.update({esxi_host: {'Error': response.get('stdout')}})
- else:
- ret.update({esxi_host: {'Coredump Enabled': enabled}})
- else:
- # Handles a single host or a vCenter connection when no esxi_hosts are provided.
- response = salt.utils.vmware.esxcli(host, username, password, cmd,
- protocol=protocol, port=port,
- credstore=credstore)
- if response['retcode'] != 0:
- ret.update({host: {'Error': response.get('stdout')}})
- else:
- ret.update({host: {'Coredump Enabled': enabled}})
- return ret
- @depends(HAS_ESX_CLI)
- def set_coredump_network_config(host,
- username,
- password,
- dump_ip,
- protocol=None,
- port=None,
- host_vnic='vmk0',
- dump_port=6500,
- esxi_hosts=None,
- credstore=None):
- '''
- Set the network parameters for a network coredump collection.
- Note that ESXi requires that the dumps first be enabled (see
- `coredump_network_enable`) before these parameters may be set.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- dump_ip
- IP address of host that will accept the dump.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- esxi_hosts
- If ``host`` is a vCenter host, then use esxi_hosts to execute this function
- on a list of one or more ESXi machines.
- host_vnic
- Host VNic port through which to communicate. Defaults to ``vmk0``.
- dump_port
- TCP port to use for the dump, defaults to ``6500``.
- credstore
- Optionally set to path to the credential store file.
- :return: A standard cmd.run_all dictionary with a `success` key added, per host.
- `success` will be True if the set succeeded, False otherwise.
- CLI Example:
- .. code-block:: bash
- # Used for ESXi host connection information
- salt '*' vsphere.set_coredump_network_config my.esxi.host root bad-password 'dump_ip.host.com'
- # Used for connecting to a vCenter Server
- salt '*' vsphere.set_coredump_network_config my.vcenter.location root bad-password 'dump_ip.host.com' \
- esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
- '''
- cmd = 'system coredump network set -v {0} -i {1} -o {2}'.format(host_vnic,
- dump_ip,
- dump_port)
- ret = {}
- if esxi_hosts:
- if not isinstance(esxi_hosts, list):
- raise CommandExecutionError('\'esxi_hosts\' must be a list.')
- for esxi_host in esxi_hosts:
- response = salt.utils.vmware.esxcli(host, username, password, cmd,
- protocol=protocol, port=port,
- esxi_host=esxi_host, credstore=credstore)
- if response['retcode'] != 0:
- response['success'] = False
- else:
- response['success'] = True
- # Update the cmd.run_all dictionary for each particular host.
- ret.update({esxi_host: response})
- else:
- # Handles a single host or a vCenter connection when no esxi_hosts are provided.
- response = salt.utils.vmware.esxcli(host, username, password, cmd,
- protocol=protocol, port=port,
- credstore=credstore)
- if response['retcode'] != 0:
- response['success'] = False
- else:
- response['success'] = True
- ret.update({host: response})
- return ret
- @depends(HAS_ESX_CLI)
- def get_firewall_status(host, username, password, protocol=None, port=None, esxi_hosts=None, credstore=None):
- '''
- Show status of all firewall rule sets.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- esxi_hosts
- If ``host`` is a vCenter host, then use esxi_hosts to execute this function
- on a list of one or more ESXi machines.
- credstore
- Optionally set to path to the credential store file.
- :return: Nested dictionary with two toplevel keys ``rulesets`` and ``success``
- ``success`` will be True or False depending on query success
- ``rulesets`` will list the rulesets and their statuses if ``success``
- was true, per host.
- CLI Example:
- .. code-block:: bash
- # Used for ESXi host connection information
- salt '*' vsphere.get_firewall_status my.esxi.host root bad-password
- # Used for connecting to a vCenter Server
- salt '*' vsphere.get_firewall_status my.vcenter.location root bad-password \
- esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
- '''
- cmd = 'network firewall ruleset list'
- ret = {}
- if esxi_hosts:
- if not isinstance(esxi_hosts, list):
- raise CommandExecutionError('\'esxi_hosts\' must be a list.')
- for esxi_host in esxi_hosts:
- response = salt.utils.vmware.esxcli(host, username, password, cmd,
- protocol=protocol, port=port,
- esxi_host=esxi_host, credstore=credstore)
- if response['retcode'] != 0:
- ret.update({esxi_host: {'Error': response['stdout'],
- 'success': False,
- 'rulesets': None}})
- else:
- # format the response stdout into something useful
- ret.update({esxi_host: _format_firewall_stdout(response)})
- else:
- # Handles a single host or a vCenter connection when no esxi_hosts are provided.
- response = salt.utils.vmware.esxcli(host, username, password, cmd,
- protocol=protocol, port=port,
- credstore=credstore)
- if response['retcode'] != 0:
- ret.update({host: {'Error': response['stdout'],
- 'success': False,
- 'rulesets': None}})
- else:
- # format the response stdout into something useful
- ret.update({host: _format_firewall_stdout(response)})
- return ret
- @depends(HAS_ESX_CLI)
- def enable_firewall_ruleset(host,
- username,
- password,
- ruleset_enable,
- ruleset_name,
- protocol=None,
- port=None,
- esxi_hosts=None,
- credstore=None):
- '''
- Enable or disable an ESXi firewall rule set.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- ruleset_enable
- True to enable the ruleset, false to disable.
- ruleset_name
- Name of ruleset to target.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- esxi_hosts
- If ``host`` is a vCenter host, then use esxi_hosts to execute this function
- on a list of one or more ESXi machines.
- credstore
- Optionally set to path to the credential store file.
- :return: A standard cmd.run_all dictionary, per host.
- CLI Example:
- .. code-block:: bash
- # Used for ESXi host connection information
- salt '*' vsphere.enable_firewall_ruleset my.esxi.host root bad-password True 'syslog'
- # Used for connecting to a vCenter Server
- salt '*' vsphere.enable_firewall_ruleset my.vcenter.location root bad-password True 'syslog' \
- esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
- '''
- cmd = 'network firewall ruleset set --enabled {0} --ruleset-id={1}'.format(
- ruleset_enable, ruleset_name
- )
- ret = {}
- if esxi_hosts:
- if not isinstance(esxi_hosts, list):
- raise CommandExecutionError('\'esxi_hosts\' must be a list.')
- for esxi_host in esxi_hosts:
- response = salt.utils.vmware.esxcli(host, username, password, cmd,
- protocol=protocol, port=port,
- esxi_host=esxi_host, credstore=credstore)
- ret.update({esxi_host: response})
- else:
- # Handles a single host or a vCenter connection when no esxi_hosts are provided.
- response = salt.utils.vmware.esxcli(host, username, password, cmd,
- protocol=protocol, port=port,
- credstore=credstore)
- ret.update({host: response})
- return ret
- @depends(HAS_ESX_CLI)
- def syslog_service_reload(host, username, password, protocol=None, port=None, esxi_hosts=None, credstore=None):
- '''
- Reload the syslog service so it will pick up any changes.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- esxi_hosts
- If ``host`` is a vCenter host, then use esxi_hosts to execute this function
- on a list of one or more ESXi machines.
- credstore
- Optionally set to path to the credential store file.
- :return: A standard cmd.run_all dictionary. This dictionary will at least
- have a `retcode` key. If `retcode` is 0 the command was successful.
- CLI Example:
- .. code-block:: bash
- # Used for ESXi host connection information
- salt '*' vsphere.syslog_service_reload my.esxi.host root bad-password
- # Used for connecting to a vCenter Server
- salt '*' vsphere.syslog_service_reload my.vcenter.location root bad-password \
- esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
- '''
- cmd = 'system syslog reload'
- ret = {}
- if esxi_hosts:
- if not isinstance(esxi_hosts, list):
- raise CommandExecutionError('\'esxi_hosts\' must be a list.')
- for esxi_host in esxi_hosts:
- response = salt.utils.vmware.esxcli(host, username, password, cmd,
- protocol=protocol, port=port,
- esxi_host=esxi_host, credstore=credstore)
- ret.update({esxi_host: response})
- else:
- # Handles a single host or a vCenter connection when no esxi_hosts are provided.
- response = salt.utils.vmware.esxcli(host, username, password, cmd,
- protocol=protocol, port=port,
- credstore=credstore)
- ret.update({host: response})
- return ret
- @depends(HAS_ESX_CLI)
- def set_syslog_config(host,
- username,
- password,
- syslog_config,
- config_value,
- protocol=None,
- port=None,
- firewall=True,
- reset_service=True,
- esxi_hosts=None,
- credstore=None):
- '''
- Set the specified syslog configuration parameter. By default, this function will
- reset the syslog service after the configuration is set.
- host
- ESXi or vCenter host to connect to.
- username
- User to connect as, usually root.
- password
- Password to connect with.
- syslog_config
- Name of parameter to set (corresponds to the command line switch for
- esxcli without the double dashes (--))
- Valid syslog_config values are ``logdir``, ``loghost``, ``default-rotate`,
- ``default-size``, ``default-timeout``, and ``logdir-unique``.
- config_value
- Value for the above parameter. For ``loghost``, URLs or IP addresses to
- use for logging. Multiple log servers can be specified by listing them,
- comma-separated, but without spaces before or after commas.
- (reference: https://blogs.vmware.com/vsphere/2012/04/configuring-multiple-syslog-servers-for-esxi-5.html)
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- firewall
- Enable the firewall rule set for syslog. Defaults to ``True``.
- reset_service
- After a successful parameter set, reset the service. Defaults to ``True``.
- esxi_hosts
- If ``host`` is a vCenter host, then use esxi_hosts to execute this function
- on a list of one or more ESXi machines.
- credstore
- Optionally set to path to the credential store file.
- :return: Dictionary with a top-level key of 'success' which indicates
- if all the parameters were reset, and individual keys
- for each parameter indicating which succeeded or failed, per host.
- CLI Example:
- .. code-block:: bash
- # Used for ESXi host connection information
- salt '*' vsphere.set_syslog_config my.esxi.host root bad-password \
- loghost ssl://localhost:5432,tcp://10.1.0.1:1514
- # Used for connecting to a vCenter Server
- salt '*' vsphere.set_syslog_config my.vcenter.location root bad-password \
- loghost ssl://localhost:5432,tcp://10.1.0.1:1514 \
- esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
- '''
- ret = {}
- # First, enable the syslog firewall ruleset, for each host, if needed.
- if firewall and syslog_config == 'loghost':
- if esxi_hosts:
- if not isinstance(esxi_hosts, list):
- raise CommandExecutionError('\'esxi_hosts\' must be a list.')
- for esxi_host in esxi_hosts:
- response = enable_firewall_ruleset(host, username, password,
- ruleset_enable=True, ruleset_name='syslog',
- protocol=protocol, port=port,
- esxi_hosts=[esxi_host], credstore=credstore).get(esxi_host)
- if response['retcode'] != 0:
- ret.update({esxi_host: {'enable_firewall': {'message': response['stdout'],
- 'success': False}}})
- else:
- ret.update({esxi_host: {'enable_firewall': {'success': True}}})
- else:
- # Handles a single host or a vCenter connection when no esxi_hosts are provided.
- response = enable_firewall_ruleset(host, username, password,
- ruleset_enable=True, ruleset_name='syslog',
- protocol=protocol, port=port,
- credstore=credstore).get(host)
- if response['retcode'] != 0:
- ret.update({host: {'enable_firewall': {'message': response['stdout'],
- 'success': False}}})
- else:
- ret.update({host: {'enable_firewall': {'success': True}}})
- # Set the config value on each esxi_host, if provided.
- if esxi_hosts:
- if not isinstance(esxi_hosts, list):
- raise CommandExecutionError('\'esxi_hosts\' must be a list.')
- for esxi_host in esxi_hosts:
- response = _set_syslog_config_helper(host, username, password, syslog_config,
- config_value, protocol=protocol, port=port,
- reset_service=reset_service, esxi_host=esxi_host,
- credstore=credstore)
- # Ensure we don't overwrite any dictionary data already set
- # By updating the esxi_host directly.
- if ret.get(esxi_host) is None:
- ret.update({esxi_host: {}})
- ret[esxi_host].update(response)
- else:
- # Handles a single host or a vCenter connection when no esxi_hosts are provided.
- response = _set_syslog_config_helper(host, username, password, syslog_config,
- config_value, protocol=protocol, port=port,
- reset_service=reset_service, credstore=credstore)
- # Ensure we don't overwrite any dictionary data already set
- # By updating the host directly.
- if ret.get(host) is None:
- ret.update({host: {}})
- ret[host].update(response)
- return ret
- @depends(HAS_ESX_CLI)
- def get_syslog_config(host, username, password, protocol=None, port=None, esxi_hosts=None, credstore=None):
- '''
- Retrieve the syslog configuration.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- esxi_hosts
- If ``host`` is a vCenter host, then use esxi_hosts to execute this function
- on a list of one or more ESXi machines.
- credstore
- Optionally set to path to the credential store file.
- :return: Dictionary with keys and values corresponding to the
- syslog configuration, per host.
- CLI Example:
- .. code-block:: bash
- # Used for ESXi host connection information
- salt '*' vsphere.get_syslog_config my.esxi.host root bad-password
- # Used for connecting to a vCenter Server
- salt '*' vsphere.get_syslog_config my.vcenter.location root bad-password \
- esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
- '''
- cmd = 'system syslog config get'
- ret = {}
- if esxi_hosts:
- if not isinstance(esxi_hosts, list):
- raise CommandExecutionError('\'esxi_hosts\' must be a list.')
- for esxi_host in esxi_hosts:
- response = salt.utils.vmware.esxcli(host, username, password, cmd,
- protocol=protocol, port=port,
- esxi_host=esxi_host, credstore=credstore)
- # format the response stdout into something useful
- ret.update({esxi_host: _format_syslog_config(response)})
- else:
- # Handles a single host or a vCenter connection when no esxi_hosts are provided.
- response = salt.utils.vmware.esxcli(host, username, password, cmd,
- protocol=protocol, port=port,
- credstore=credstore)
- # format the response stdout into something useful
- ret.update({host: _format_syslog_config(response)})
- return ret
- @depends(HAS_ESX_CLI)
- def reset_syslog_config(host,
- username,
- password,
- protocol=None,
- port=None,
- syslog_config=None,
- esxi_hosts=None,
- credstore=None):
- '''
- Reset the syslog service to its default settings.
- Valid syslog_config values are ``logdir``, ``loghost``, ``logdir-unique``,
- ``default-rotate``, ``default-size``, ``default-timeout``,
- or ``all`` for all of these.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- syslog_config
- List of parameters to reset, provided as a comma-delimited string, or 'all' to
- reset all syslog configuration parameters. Required.
- esxi_hosts
- If ``host`` is a vCenter host, then use esxi_hosts to execute this function
- on a list of one or more ESXi machines.
- credstore
- Optionally set to path to the credential store file.
- :return: Dictionary with a top-level key of 'success' which indicates
- if all the parameters were reset, and individual keys
- for each parameter indicating which succeeded or failed, per host.
- CLI Example:
- ``syslog_config`` can be passed as a quoted, comma-separated string, e.g.
- .. code-block:: bash
- # Used for ESXi host connection information
- salt '*' vsphere.reset_syslog_config my.esxi.host root bad-password \
- syslog_config='logdir,loghost'
- # Used for connecting to a vCenter Server
- salt '*' vsphere.reset_syslog_config my.vcenter.location root bad-password \
- syslog_config='logdir,loghost' esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
- '''
- if not syslog_config:
- raise CommandExecutionError('The \'reset_syslog_config\' function requires a '
- '\'syslog_config\' setting.')
- valid_resets = ['logdir', 'loghost', 'default-rotate',
- 'default-size', 'default-timeout', 'logdir-unique']
- cmd = 'system syslog config set --reset='
- if ',' in syslog_config:
- resets = [ind_reset.strip() for ind_reset in syslog_config.split(',')]
- elif syslog_config == 'all':
- resets = valid_resets
- else:
- resets = [syslog_config]
- ret = {}
- if esxi_hosts:
- if not isinstance(esxi_hosts, list):
- raise CommandExecutionError('\'esxi_hosts\' must be a list.')
- for esxi_host in esxi_hosts:
- response_dict = _reset_syslog_config_params(host, username, password,
- cmd, resets, valid_resets,
- protocol=protocol, port=port,
- esxi_host=esxi_host, credstore=credstore)
- ret.update({esxi_host: response_dict})
- else:
- # Handles a single host or a vCenter connection when no esxi_hosts are provided.
- response_dict = _reset_syslog_config_params(host, username, password,
- cmd, resets, valid_resets,
- protocol=protocol, port=port,
- credstore=credstore)
- ret.update({host: response_dict})
- return ret
- @ignores_kwargs('credstore')
- def upload_ssh_key(host, username, password, ssh_key=None, ssh_key_file=None,
- protocol=None, port=None, certificate_verify=False):
- '''
- Upload an ssh key for root to an ESXi host via http PUT.
- This function only works for ESXi, not vCenter.
- Only one ssh key can be uploaded for root. Uploading a second key will
- replace any existing key.
- :param host: The location of the ESXi Host
- :param username: Username to connect as
- :param password: Password for the ESXi web endpoint
- :param ssh_key: Public SSH key, will be added to authorized_keys on ESXi
- :param ssh_key_file: File containing the SSH key. Use 'ssh_key' or
- ssh_key_file, but not both.
- :param protocol: defaults to https, can be http if ssl is disabled on ESXi
- :param port: defaults to 443 for https
- :param certificate_verify: If true require that the SSL connection present
- a valid certificate
- :return: Dictionary with a 'status' key, True if upload is successful.
- If upload is unsuccessful, 'status' key will be False and
- an 'Error' key will have an informative message.
- CLI Example:
- .. code-block:: bash
- salt '*' vsphere.upload_ssh_key my.esxi.host root bad-password ssh_key_file='/etc/salt/my_keys/my_key.pub'
- '''
- if protocol is None:
- protocol = 'https'
- if port is None:
- port = 443
- url = '{0}://{1}:{2}/host/ssh_root_authorized_keys'.format(protocol,
- host,
- port)
- ret = {}
- result = None
- try:
- if ssh_key:
- result = salt.utils.http.query(url,
- status=True,
- text=True,
- method='PUT',
- username=username,
- password=password,
- data=ssh_key,
- verify_ssl=certificate_verify)
- elif ssh_key_file:
- result = salt.utils.http.query(url,
- status=True,
- text=True,
- method='PUT',
- username=username,
- password=password,
- data_file=ssh_key_file,
- data_render=False,
- verify_ssl=certificate_verify)
- if result.get('status') == 200:
- ret['status'] = True
- else:
- ret['status'] = False
- ret['Error'] = result['error']
- except Exception as msg:
- ret['status'] = False
- ret['Error'] = msg
- return ret
- @ignores_kwargs('credstore')
- def get_ssh_key(host,
- username,
- password,
- protocol=None,
- port=None,
- certificate_verify=False):
- '''
- Retrieve the authorized_keys entry for root.
- This function only works for ESXi, not vCenter.
- :param host: The location of the ESXi Host
- :param username: Username to connect as
- :param password: Password for the ESXi web endpoint
- :param protocol: defaults to https, can be http if ssl is disabled on ESXi
- :param port: defaults to 443 for https
- :param certificate_verify: If true require that the SSL connection present
- a valid certificate
- :return: True if upload is successful
- CLI Example:
- .. code-block:: bash
- salt '*' vsphere.get_ssh_key my.esxi.host root bad-password certificate_verify=True
- '''
- if protocol is None:
- protocol = 'https'
- if port is None:
- port = 443
- url = '{0}://{1}:{2}/host/ssh_root_authorized_keys'.format(protocol,
- host,
- port)
- ret = {}
- try:
- result = salt.utils.http.query(url,
- status=True,
- text=True,
- method='GET',
- username=username,
- password=password,
- verify_ssl=certificate_verify)
- if result.get('status') == 200:
- ret['status'] = True
- ret['key'] = result['text']
- else:
- ret['status'] = False
- ret['Error'] = result['error']
- except Exception as msg:
- ret['status'] = False
- ret['Error'] = msg
- return ret
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def get_host_datetime(host, username, password, protocol=None, port=None, host_names=None):
- '''
- Get the date/time information for a given host or list of host_names.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- host_names
- List of ESXi host names. When the host, username, and password credentials
- are provided for a vCenter Server, the host_names argument is required to tell
- vCenter the hosts for which to get date/time information.
- If host_names is not provided, the date/time information will be retrieved for the
- ``host`` location instead. This is useful for when service instance connection
- information is used for a single ESXi host.
- CLI Example:
- .. code-block:: bash
- # Used for single ESXi host connection information
- salt '*' vsphere.get_host_datetime my.esxi.host root bad-password
- # Used for connecting to a vCenter Server
- salt '*' vsphere.get_host_datetime my.vcenter.location root bad-password \
- host_names='[esxi-1.host.com, esxi-2.host.com]'
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- host_names = _check_hosts(service_instance, host, host_names)
- ret = {}
- for host_name in host_names:
- host_ref = _get_host_ref(service_instance, host, host_name=host_name)
- date_time_manager = _get_date_time_mgr(host_ref)
- date_time = date_time_manager.QueryDateTime()
- ret.update({host_name: date_time})
- return ret
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def get_ntp_config(host, username, password, protocol=None, port=None, host_names=None):
- '''
- Get the NTP configuration information for a given host or list of host_names.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- host_names
- List of ESXi host names. When the host, username, and password credentials
- are provided for a vCenter Server, the host_names argument is required to tell
- vCenter the hosts for which to get ntp configuration information.
- If host_names is not provided, the NTP configuration will be retrieved for the
- ``host`` location instead. This is useful for when service instance connection
- information is used for a single ESXi host.
- CLI Example:
- .. code-block:: bash
- # Used for single ESXi host connection information
- salt '*' vsphere.get_ntp_config my.esxi.host root bad-password
- # Used for connecting to a vCenter Server
- salt '*' vsphere.get_ntp_config my.vcenter.location root bad-password \
- host_names='[esxi-1.host.com, esxi-2.host.com]'
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- host_names = _check_hosts(service_instance, host, host_names)
- ret = {}
- for host_name in host_names:
- host_ref = _get_host_ref(service_instance, host, host_name=host_name)
- ntp_config = host_ref.configManager.dateTimeSystem.dateTimeInfo.ntpConfig.server
- ret.update({host_name: ntp_config})
- return ret
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def get_service_policy(host, username, password, service_name, protocol=None, port=None, host_names=None):
- '''
- Get the service name's policy for a given host or list of hosts.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- service_name
- The name of the service for which to retrieve the policy. Supported service names are:
- - DCUI
- - TSM
- - SSH
- - lbtd
- - lsassd
- - lwiod
- - netlogond
- - ntpd
- - sfcbd-watchdog
- - snmpd
- - vprobed
- - vpxa
- - xorg
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- host_names
- List of ESXi host names. When the host, username, and password credentials
- are provided for a vCenter Server, the host_names argument is required to tell
- vCenter the hosts for which to get service policy information.
- If host_names is not provided, the service policy information will be retrieved
- for the ``host`` location instead. This is useful for when service instance
- connection information is used for a single ESXi host.
- CLI Example:
- .. code-block:: bash
- # Used for single ESXi host connection information
- salt '*' vsphere.get_service_policy my.esxi.host root bad-password 'ssh'
- # Used for connecting to a vCenter Server
- salt '*' vsphere.get_service_policy my.vcenter.location root bad-password 'ntpd' \
- host_names='[esxi-1.host.com, esxi-2.host.com]'
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- valid_services = ['DCUI', 'TSM', 'SSH', 'ssh', 'lbtd', 'lsassd', 'lwiod', 'netlogond',
- 'ntpd', 'sfcbd-watchdog', 'snmpd', 'vprobed', 'vpxa', 'xorg']
- host_names = _check_hosts(service_instance, host, host_names)
- ret = {}
- for host_name in host_names:
- # Check if the service_name provided is a valid one.
- # If we don't have a valid service, return. The service will be invalid for all hosts.
- if service_name not in valid_services:
- ret.update({host_name: {'Error': '{0} is not a valid service name.'.format(service_name)}})
- return ret
- host_ref = _get_host_ref(service_instance, host, host_name=host_name)
- services = host_ref.configManager.serviceSystem.serviceInfo.service
- # Don't require users to know that VMware lists the ssh service as TSM-SSH
- if service_name == 'SSH' or service_name == 'ssh':
- temp_service_name = 'TSM-SSH'
- else:
- temp_service_name = service_name
- # Loop through services until we find a matching name
- for service in services:
- if service.key == temp_service_name:
- ret.update({host_name:
- {service_name: service.policy}})
- # We've found a match - break out of the loop so we don't overwrite the
- # Updated host_name value with an error message.
- break
- else:
- msg = 'Could not find service \'{0}\' for host \'{1}\'.'.format(service_name,
- host_name)
- ret.update({host_name: {'Error': msg}})
- # If we made it this far, something else has gone wrong.
- if ret.get(host_name) is None:
- msg = '\'vsphere.get_service_policy\' failed for host {0}.'.format(host_name)
- log.debug(msg)
- ret.update({host_name: {'Error': msg}})
- return ret
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def get_service_running(host, username, password, service_name, protocol=None, port=None, host_names=None):
- '''
- Get the service name's running state for a given host or list of hosts.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- service_name
- The name of the service for which to retrieve the policy. Supported service names are:
- - DCUI
- - TSM
- - SSH
- - lbtd
- - lsassd
- - lwiod
- - netlogond
- - ntpd
- - sfcbd-watchdog
- - snmpd
- - vprobed
- - vpxa
- - xorg
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- host_names
- List of ESXi host names. When the host, username, and password credentials
- are provided for a vCenter Server, the host_names argument is required to tell
- vCenter the hosts for which to get the service's running state.
- If host_names is not provided, the service's running state will be retrieved
- for the ``host`` location instead. This is useful for when service instance
- connection information is used for a single ESXi host.
- CLI Example:
- .. code-block:: bash
- # Used for single ESXi host connection information
- salt '*' vsphere.get_service_running my.esxi.host root bad-password 'ssh'
- # Used for connecting to a vCenter Server
- salt '*' vsphere.get_service_running my.vcenter.location root bad-password 'ntpd' \
- host_names='[esxi-1.host.com, esxi-2.host.com]'
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- valid_services = ['DCUI', 'TSM', 'SSH', 'ssh', 'lbtd', 'lsassd', 'lwiod', 'netlogond',
- 'ntpd', 'sfcbd-watchdog', 'snmpd', 'vprobed', 'vpxa', 'xorg']
- host_names = _check_hosts(service_instance, host, host_names)
- ret = {}
- for host_name in host_names:
- # Check if the service_name provided is a valid one.
- # If we don't have a valid service, return. The service will be invalid for all hosts.
- if service_name not in valid_services:
- ret.update({host_name: {'Error': '{0} is not a valid service name.'.format(service_name)}})
- return ret
- host_ref = _get_host_ref(service_instance, host, host_name=host_name)
- services = host_ref.configManager.serviceSystem.serviceInfo.service
- # Don't require users to know that VMware lists the ssh service as TSM-SSH
- if service_name == 'SSH' or service_name == 'ssh':
- temp_service_name = 'TSM-SSH'
- else:
- temp_service_name = service_name
- # Loop through services until we find a matching name
- for service in services:
- if service.key == temp_service_name:
- ret.update({host_name:
- {service_name: service.running}})
- # We've found a match - break out of the loop so we don't overwrite the
- # Updated host_name value with an error message.
- break
- else:
- msg = 'Could not find service \'{0}\' for host \'{1}\'.'.format(service_name,
- host_name)
- ret.update({host_name: {'Error': msg}})
- # If we made it this far, something else has gone wrong.
- if ret.get(host_name) is None:
- msg = '\'vsphere.get_service_running\' failed for host {0}.'.format(host_name)
- log.debug(msg)
- ret.update({host_name: {'Error': msg}})
- return ret
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def get_vmotion_enabled(host, username, password, protocol=None, port=None, host_names=None):
- '''
- Get the VMotion enabled status for a given host or a list of host_names. Returns ``True``
- if VMotion is enabled, ``False`` if it is not enabled.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- host_names
- List of ESXi host names. When the host, username, and password credentials
- are provided for a vCenter Server, the host_names argument is required to
- tell vCenter which hosts to check if VMotion is enabled.
- If host_names is not provided, the VMotion status will be retrieved for the
- ``host`` location instead. This is useful for when service instance
- connection information is used for a single ESXi host.
- CLI Example:
- .. code-block:: bash
- # Used for single ESXi host connection information
- salt '*' vsphere.get_vmotion_enabled my.esxi.host root bad-password
- # Used for connecting to a vCenter Server
- salt '*' vsphere.get_vmotion_enabled my.vcenter.location root bad-password \
- host_names='[esxi-1.host.com, esxi-2.host.com]'
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- host_names = _check_hosts(service_instance, host, host_names)
- ret = {}
- for host_name in host_names:
- host_ref = _get_host_ref(service_instance, host, host_name=host_name)
- vmotion_vnic = host_ref.configManager.vmotionSystem.netConfig.selectedVnic
- if vmotion_vnic:
- ret.update({host_name: {'VMotion Enabled': True}})
- else:
- ret.update({host_name: {'VMotion Enabled': False}})
- return ret
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def get_vsan_enabled(host, username, password, protocol=None, port=None, host_names=None):
- '''
- Get the VSAN enabled status for a given host or a list of host_names. Returns ``True``
- if VSAN is enabled, ``False`` if it is not enabled, and ``None`` if a VSAN Host Config
- is unset, per host.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- host_names
- List of ESXi host names. When the host, username, and password credentials
- are provided for a vCenter Server, the host_names argument is required to
- tell vCenter which hosts to check if VSAN enabled.
- If host_names is not provided, the VSAN status will be retrieved for the
- ``host`` location instead. This is useful for when service instance
- connection information is used for a single ESXi host.
- CLI Example:
- .. code-block:: bash
- # Used for single ESXi host connection information
- salt '*' vsphere.get_vsan_enabled my.esxi.host root bad-password
- # Used for connecting to a vCenter Server
- salt '*' vsphere.get_vsan_enabled my.vcenter.location root bad-password \
- host_names='[esxi-1.host.com, esxi-2.host.com]'
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- host_names = _check_hosts(service_instance, host, host_names)
- ret = {}
- for host_name in host_names:
- host_ref = _get_host_ref(service_instance, host, host_name=host_name)
- vsan_config = host_ref.config.vsanHostConfig
- # We must have a VSAN Config in place get information about VSAN state.
- if vsan_config is None:
- msg = 'VSAN System Config Manager is unset for host \'{0}\'.'.format(host_name)
- log.debug(msg)
- ret.update({host_name: {'Error': msg}})
- else:
- ret.update({host_name: {'VSAN Enabled': vsan_config.enabled}})
- return ret
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def get_vsan_eligible_disks(host, username, password, protocol=None, port=None, host_names=None):
- '''
- Returns a list of VSAN-eligible disks for a given host or list of host_names.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- host_names
- List of ESXi host names. When the host, username, and password credentials
- are provided for a vCenter Server, the host_names argument is required to
- tell vCenter which hosts to check if any VSAN-eligible disks are available.
- If host_names is not provided, the VSAN-eligible disks will be retrieved
- for the ``host`` location instead. This is useful for when service instance
- connection information is used for a single ESXi host.
- CLI Example:
- .. code-block:: bash
- # Used for single ESXi host connection information
- salt '*' vsphere.get_vsan_eligible_disks my.esxi.host root bad-password
- # Used for connecting to a vCenter Server
- salt '*' vsphere.get_vsan_eligible_disks my.vcenter.location root bad-password \
- host_names='[esxi-1.host.com, esxi-2.host.com]'
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- host_names = _check_hosts(service_instance, host, host_names)
- response = _get_vsan_eligible_disks(service_instance, host, host_names)
- ret = {}
- for host_name, value in six.iteritems(response):
- error = value.get('Error')
- if error:
- ret.update({host_name: {'Error': error}})
- continue
- disks = value.get('Eligible')
- # If we have eligible disks, it will be a list of disk objects
- if disks and isinstance(disks, list):
- disk_names = []
- # We need to return ONLY the disk names, otherwise
- # MessagePack can't deserialize the disk objects.
- for disk in disks:
- disk_names.append(disk.canonicalName)
- ret.update({host_name: {'Eligible': disk_names}})
- else:
- # If we have disks, but it's not a list, it's actually a
- # string message that we're passing along.
- ret.update({host_name: {'Eligible': disks}})
- return ret
- @depends(HAS_PYVMOMI)
- @supports_proxies('esxi')
- @gets_service_instance_via_proxy
- def test_vcenter_connection(service_instance=None):
- '''
- Checks if a connection is to a vCenter
- CLI Example:
- .. code-block:: bash
- salt '*' vsphere.test_vcenter_connection
- '''
- try:
- if salt.utils.vmware.is_connection_to_a_vcenter(service_instance):
- return True
- except VMwareSaltError:
- return False
- return False
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def system_info(host, username, password, protocol=None, port=None):
- '''
- Return system information about a VMware environment.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- CLI Example:
- .. code-block:: bash
- salt '*' vsphere.system_info 1.2.3.4 root bad-password
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- ret = salt.utils.vmware.get_inventory(service_instance).about.__dict__
- if 'apiType' in ret:
- if ret['apiType'] == 'HostAgent':
- ret = dictupdate.update(ret, salt.utils.vmware.get_hardware_grains(service_instance))
- return ret
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def list_datacenters(host, username, password, protocol=None, port=None):
- '''
- Returns a list of datacenters for the the specified host.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- CLI Example:
- .. code-block:: bash
- salt '*' vsphere.list_datacenters 1.2.3.4 root bad-password
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- return salt.utils.vmware.list_datacenters(service_instance)
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def list_clusters(host, username, password, protocol=None, port=None):
- '''
- Returns a list of clusters for the the specified host.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- CLI Example:
- .. code-block:: bash
- salt '*' vsphere.list_clusters 1.2.3.4 root bad-password
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- return salt.utils.vmware.list_clusters(service_instance)
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def list_datastore_clusters(host, username, password, protocol=None, port=None):
- '''
- Returns a list of datastore clusters for the the specified host.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- CLI Example:
- .. code-block:: bash
- salt '*' vsphere.list_datastore_clusters 1.2.3.4 root bad-password
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- return salt.utils.vmware.list_datastore_clusters(service_instance)
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def list_datastores(host, username, password, protocol=None, port=None):
- '''
- Returns a list of datastores for the the specified host.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- CLI Example:
- .. code-block:: bash
- salt '*' vsphere.list_datastores 1.2.3.4 root bad-password
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- return salt.utils.vmware.list_datastores(service_instance)
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def list_hosts(host, username, password, protocol=None, port=None):
- '''
- Returns a list of hosts for the the specified VMware environment.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- CLI Example:
- .. code-block:: bash
- salt '*' vsphere.list_hosts 1.2.3.4 root bad-password
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- return salt.utils.vmware.list_hosts(service_instance)
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def list_resourcepools(host, username, password, protocol=None, port=None):
- '''
- Returns a list of resource pools for the the specified host.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- CLI Example:
- .. code-block:: bash
- salt '*' vsphere.list_resourcepools 1.2.3.4 root bad-password
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- return salt.utils.vmware.list_resourcepools(service_instance)
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def list_networks(host, username, password, protocol=None, port=None):
- '''
- Returns a list of networks for the the specified host.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- CLI Example:
- .. code-block:: bash
- salt '*' vsphere.list_networks 1.2.3.4 root bad-password
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- return salt.utils.vmware.list_networks(service_instance)
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def list_vms(host, username, password, protocol=None, port=None):
- '''
- Returns a list of VMs for the the specified host.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- CLI Example:
- .. code-block:: bash
- salt '*' vsphere.list_vms 1.2.3.4 root bad-password
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- return salt.utils.vmware.list_vms(service_instance)
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def list_folders(host, username, password, protocol=None, port=None):
- '''
- Returns a list of folders for the the specified host.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- CLI Example:
- .. code-block:: bash
- salt '*' vsphere.list_folders 1.2.3.4 root bad-password
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- return salt.utils.vmware.list_folders(service_instance)
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def list_dvs(host, username, password, protocol=None, port=None):
- '''
- Returns a list of distributed virtual switches for the the specified host.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- CLI Example:
- .. code-block:: bash
- salt '*' vsphere.list_dvs 1.2.3.4 root bad-password
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- return salt.utils.vmware.list_dvs(service_instance)
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def list_vapps(host, username, password, protocol=None, port=None):
- '''
- Returns a list of vApps for the the specified host.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- CLI Example:
- .. code-block:: bash
- # List vapps from all minions
- salt '*' vsphere.list_vapps 1.2.3.4 root bad-password
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- return salt.utils.vmware.list_vapps(service_instance)
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def list_ssds(host, username, password, protocol=None, port=None, host_names=None):
- '''
- Returns a list of SSDs for the given host or list of host_names.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- host_names
- List of ESXi host names. When the host, username, and password credentials
- are provided for a vCenter Server, the host_names argument is required to
- tell vCenter the hosts for which to retrieve SSDs.
- If host_names is not provided, SSDs will be retrieved for the
- ``host`` location instead. This is useful for when service instance
- connection information is used for a single ESXi host.
- CLI Example:
- .. code-block:: bash
- # Used for single ESXi host connection information
- salt '*' vsphere.list_ssds my.esxi.host root bad-password
- # Used for connecting to a vCenter Server
- salt '*' vsphere.list_ssds my.vcenter.location root bad-password \
- host_names='[esxi-1.host.com, esxi-2.host.com]'
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- host_names = _check_hosts(service_instance, host, host_names)
- ret = {}
- names = []
- for host_name in host_names:
- host_ref = _get_host_ref(service_instance, host, host_name=host_name)
- disks = _get_host_ssds(host_ref)
- for disk in disks:
- names.append(disk.canonicalName)
- ret.update({host_name: names})
- return ret
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def list_non_ssds(host, username, password, protocol=None, port=None, host_names=None):
- '''
- Returns a list of Non-SSD disks for the given host or list of host_names.
- .. note::
- In the pyVmomi StorageSystem, ScsiDisks may, or may not have an ``ssd`` attribute.
- This attribute indicates if the ScsiDisk is SSD backed. As this option is optional,
- if a relevant disk in the StorageSystem does not have ``ssd = true``, it will end
- up in the ``non_ssds`` list here.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- host_names
- List of ESXi host names. When the host, username, and password credentials
- are provided for a vCenter Server, the host_names argument is required to
- tell vCenter the hosts for which to retrieve Non-SSD disks.
- If host_names is not provided, Non-SSD disks will be retrieved for the
- ``host`` location instead. This is useful for when service instance
- connection information is used for a single ESXi host.
- CLI Example:
- .. code-block:: bash
- # Used for single ESXi host connection information
- salt '*' vsphere.list_non_ssds my.esxi.host root bad-password
- # Used for connecting to a vCenter Server
- salt '*' vsphere.list_non_ssds my.vcenter.location root bad-password \
- host_names='[esxi-1.host.com, esxi-2.host.com]'
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- host_names = _check_hosts(service_instance, host, host_names)
- ret = {}
- names = []
- for host_name in host_names:
- host_ref = _get_host_ref(service_instance, host, host_name=host_name)
- disks = _get_host_non_ssds(host_ref)
- for disk in disks:
- names.append(disk.canonicalName)
- ret.update({host_name: names})
- return ret
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def set_ntp_config(host, username, password, ntp_servers, protocol=None, port=None, host_names=None):
- '''
- Set NTP configuration for a given host of list of host_names.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- ntp_servers
- A list of servers that should be added to and configured for the specified
- host's NTP configuration.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- host_names
- List of ESXi host names. When the host, username, and password credentials
- are provided for a vCenter Server, the host_names argument is required to tell
- vCenter which hosts to configure ntp servers.
- If host_names is not provided, the NTP servers will be configured for the
- ``host`` location instead. This is useful for when service instance connection
- information is used for a single ESXi host.
- CLI Example:
- .. code-block:: bash
- # Used for single ESXi host connection information
- salt '*' vsphere.ntp_configure my.esxi.host root bad-password '[192.174.1.100, 192.174.1.200]'
- # Used for connecting to a vCenter Server
- salt '*' vsphere.ntp_configure my.vcenter.location root bad-password '[192.174.1.100, 192.174.1.200]' \
- host_names='[esxi-1.host.com, esxi-2.host.com]'
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- if not isinstance(ntp_servers, list):
- raise CommandExecutionError('\'ntp_servers\' must be a list.')
- # Get NTP Config Object from ntp_servers
- ntp_config = vim.HostNtpConfig(server=ntp_servers)
- # Get DateTimeConfig object from ntp_config
- date_config = vim.HostDateTimeConfig(ntpConfig=ntp_config)
- host_names = _check_hosts(service_instance, host, host_names)
- ret = {}
- for host_name in host_names:
- host_ref = _get_host_ref(service_instance, host, host_name=host_name)
- date_time_manager = _get_date_time_mgr(host_ref)
- log.debug('Configuring NTP Servers \'{0}\' for host \'{1}\'.'.format(ntp_servers, host_name))
- try:
- date_time_manager.UpdateDateTimeConfig(config=date_config)
- except vim.fault.HostConfigFault as err:
- msg = 'vsphere.ntp_configure_servers failed: {0}'.format(err)
- log.debug(msg)
- ret.update({host_name: {'Error': msg}})
- continue
- ret.update({host_name: {'NTP Servers': ntp_config}})
- return ret
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def service_start(host,
- username,
- password,
- service_name,
- protocol=None,
- port=None,
- host_names=None):
- '''
- Start the named service for the given host or list of hosts.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- service_name
- The name of the service for which to set the policy. Supported service names are:
- - DCUI
- - TSM
- - SSH
- - lbtd
- - lsassd
- - lwiod
- - netlogond
- - ntpd
- - sfcbd-watchdog
- - snmpd
- - vprobed
- - vpxa
- - xorg
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- host_names
- List of ESXi host names. When the host, username, and password credentials
- are provided for a vCenter Server, the host_names argument is required to tell
- vCenter the hosts for which to start the service.
- If host_names is not provided, the service will be started for the ``host``
- location instead. This is useful for when service instance connection information
- is used for a single ESXi host.
- CLI Example:
- .. code-block:: bash
- # Used for single ESXi host connection information
- salt '*' vsphere.service_start my.esxi.host root bad-password 'ntpd'
- # Used for connecting to a vCenter Server
- salt '*' vsphere.service_start my.vcenter.location root bad-password 'ntpd' \
- host_names='[esxi-1.host.com, esxi-2.host.com]'
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- host_names = _check_hosts(service_instance, host, host_names)
- valid_services = ['DCUI', 'TSM', 'SSH', 'ssh', 'lbtd', 'lsassd', 'lwiod', 'netlogond',
- 'ntpd', 'sfcbd-watchdog', 'snmpd', 'vprobed', 'vpxa', 'xorg']
- ret = {}
- # Don't require users to know that VMware lists the ssh service as TSM-SSH
- if service_name == 'SSH' or service_name == 'ssh':
- temp_service_name = 'TSM-SSH'
- else:
- temp_service_name = service_name
- for host_name in host_names:
- # Check if the service_name provided is a valid one.
- # If we don't have a valid service, return. The service will be invalid for all hosts.
- if service_name not in valid_services:
- ret.update({host_name: {'Error': '{0} is not a valid service name.'.format(service_name)}})
- return ret
- host_ref = _get_host_ref(service_instance, host, host_name=host_name)
- service_manager = _get_service_manager(host_ref)
- log.debug('Starting the \'{0}\' service on {1}.'.format(service_name, host_name))
- # Start the service
- try:
- service_manager.StartService(id=temp_service_name)
- except vim.fault.HostConfigFault as err:
- msg = '\'vsphere.service_start\' failed for host {0}: {1}'.format(host_name, err)
- log.debug(msg)
- ret.update({host_name: {'Error': msg}})
- continue
- # Some services are restricted by the vSphere License Level.
- except vim.fault.RestrictedVersion as err:
- log.debug(err)
- ret.update({host_name: {'Error': err}})
- continue
- ret.update({host_name: {'Service Started': True}})
- return ret
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def service_stop(host,
- username,
- password,
- service_name,
- protocol=None,
- port=None,
- host_names=None):
- '''
- Stop the named service for the given host or list of hosts.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- service_name
- The name of the service for which to set the policy. Supported service names are:
- - DCUI
- - TSM
- - SSH
- - lbtd
- - lsassd
- - lwiod
- - netlogond
- - ntpd
- - sfcbd-watchdog
- - snmpd
- - vprobed
- - vpxa
- - xorg
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- host_names
- List of ESXi host names. When the host, username, and password credentials
- are provided for a vCenter Server, the host_names argument is required to tell
- vCenter the hosts for which to stop the service.
- If host_names is not provided, the service will be stopped for the ``host``
- location instead. This is useful for when service instance connection information
- is used for a single ESXi host.
- CLI Example:
- .. code-block:: bash
- # Used for single ESXi host connection information
- salt '*' vsphere.service_stop my.esxi.host root bad-password 'ssh'
- # Used for connecting to a vCenter Server
- salt '*' vsphere.service_stop my.vcenter.location root bad-password 'ssh' \
- host_names='[esxi-1.host.com, esxi-2.host.com]'
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- host_names = _check_hosts(service_instance, host, host_names)
- valid_services = ['DCUI', 'TSM', 'SSH', 'ssh', 'lbtd', 'lsassd', 'lwiod', 'netlogond',
- 'ntpd', 'sfcbd-watchdog', 'snmpd', 'vprobed', 'vpxa', 'xorg']
- ret = {}
- # Don't require users to know that VMware lists the ssh service as TSM-SSH
- if service_name == 'SSH' or service_name == 'ssh':
- temp_service_name = 'TSM-SSH'
- else:
- temp_service_name = service_name
- for host_name in host_names:
- # Check if the service_name provided is a valid one.
- # If we don't have a valid service, return. The service will be invalid for all hosts.
- if service_name not in valid_services:
- ret.update({host_name: {'Error': '{0} is not a valid service name.'.format(service_name)}})
- return ret
- host_ref = _get_host_ref(service_instance, host, host_name=host_name)
- service_manager = _get_service_manager(host_ref)
- log.debug('Stopping the \'{0}\' service on {1}.'.format(service_name, host_name))
- # Stop the service.
- try:
- service_manager.StopService(id=temp_service_name)
- except vim.fault.HostConfigFault as err:
- msg = '\'vsphere.service_stop\' failed for host {0}: {1}'.format(host_name, err)
- log.debug(msg)
- ret.update({host_name: {'Error': msg}})
- continue
- # Some services are restricted by the vSphere License Level.
- except vim.fault.RestrictedVersion as err:
- log.debug(err)
- ret.update({host_name: {'Error': err}})
- continue
- ret.update({host_name: {'Service Stopped': True}})
- return ret
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def service_restart(host,
- username,
- password,
- service_name,
- protocol=None,
- port=None,
- host_names=None):
- '''
- Restart the named service for the given host or list of hosts.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- service_name
- The name of the service for which to set the policy. Supported service names are:
- - DCUI
- - TSM
- - SSH
- - lbtd
- - lsassd
- - lwiod
- - netlogond
- - ntpd
- - sfcbd-watchdog
- - snmpd
- - vprobed
- - vpxa
- - xorg
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- host_names
- List of ESXi host names. When the host, username, and password credentials
- are provided for a vCenter Server, the host_names argument is required to tell
- vCenter the hosts for which to restart the service.
- If host_names is not provided, the service will be restarted for the ``host``
- location instead. This is useful for when service instance connection information
- is used for a single ESXi host.
- CLI Example:
- .. code-block:: bash
- # Used for single ESXi host connection information
- salt '*' vsphere.service_restart my.esxi.host root bad-password 'ntpd'
- # Used for connecting to a vCenter Server
- salt '*' vsphere.service_restart my.vcenter.location root bad-password 'ntpd' \
- host_names='[esxi-1.host.com, esxi-2.host.com]'
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- host_names = _check_hosts(service_instance, host, host_names)
- valid_services = ['DCUI', 'TSM', 'SSH', 'ssh', 'lbtd', 'lsassd', 'lwiod', 'netlogond',
- 'ntpd', 'sfcbd-watchdog', 'snmpd', 'vprobed', 'vpxa', 'xorg']
- ret = {}
- # Don't require users to know that VMware lists the ssh service as TSM-SSH
- if service_name == 'SSH' or service_name == 'ssh':
- temp_service_name = 'TSM-SSH'
- else:
- temp_service_name = service_name
- for host_name in host_names:
- # Check if the service_name provided is a valid one.
- # If we don't have a valid service, return. The service will be invalid for all hosts.
- if service_name not in valid_services:
- ret.update({host_name: {'Error': '{0} is not a valid service name.'.format(service_name)}})
- return ret
- host_ref = _get_host_ref(service_instance, host, host_name=host_name)
- service_manager = _get_service_manager(host_ref)
- log.debug('Restarting the \'{0}\' service on {1}.'.format(service_name, host_name))
- # Restart the service.
- try:
- service_manager.RestartService(id=temp_service_name)
- except vim.fault.HostConfigFault as err:
- msg = '\'vsphere.service_restart\' failed for host {0}: {1}'.format(host_name, err)
- log.debug(msg)
- ret.update({host_name: {'Error': msg}})
- continue
- # Some services are restricted by the vSphere License Level.
- except vim.fault.RestrictedVersion as err:
- log.debug(err)
- ret.update({host_name: {'Error': err}})
- continue
- ret.update({host_name: {'Service Restarted': True}})
- return ret
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def set_service_policy(host,
- username,
- password,
- service_name,
- service_policy,
- protocol=None,
- port=None,
- host_names=None):
- '''
- Set the service name's policy for a given host or list of hosts.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- service_name
- The name of the service for which to set the policy. Supported service names are:
- - DCUI
- - TSM
- - SSH
- - lbtd
- - lsassd
- - lwiod
- - netlogond
- - ntpd
- - sfcbd-watchdog
- - snmpd
- - vprobed
- - vpxa
- - xorg
- service_policy
- The policy to set for the service. For example, 'automatic'.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- host_names
- List of ESXi host names. When the host, username, and password credentials
- are provided for a vCenter Server, the host_names argument is required to tell
- vCenter the hosts for which to set the service policy.
- If host_names is not provided, the service policy information will be retrieved
- for the ``host`` location instead. This is useful for when service instance
- connection information is used for a single ESXi host.
- CLI Example:
- .. code-block:: bash
- # Used for single ESXi host connection information
- salt '*' vsphere.set_service_policy my.esxi.host root bad-password 'ntpd' 'automatic'
- # Used for connecting to a vCenter Server
- salt '*' vsphere.set_service_policy my.vcenter.location root bad-password 'ntpd' 'automatic' \
- host_names='[esxi-1.host.com, esxi-2.host.com]'
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- host_names = _check_hosts(service_instance, host, host_names)
- valid_services = ['DCUI', 'TSM', 'SSH', 'ssh', 'lbtd', 'lsassd', 'lwiod', 'netlogond',
- 'ntpd', 'sfcbd-watchdog', 'snmpd', 'vprobed', 'vpxa', 'xorg']
- ret = {}
- for host_name in host_names:
- # Check if the service_name provided is a valid one.
- # If we don't have a valid service, return. The service will be invalid for all hosts.
- if service_name not in valid_services:
- ret.update({host_name: {'Error': '{0} is not a valid service name.'.format(service_name)}})
- return ret
- host_ref = _get_host_ref(service_instance, host, host_name=host_name)
- service_manager = _get_service_manager(host_ref)
- services = host_ref.configManager.serviceSystem.serviceInfo.service
- # Services are stored in a general list - we need loop through the list and find
- # service key that matches our service name.
- for service in services:
- service_key = None
- # Find the service key based on the given service_name
- if service.key == service_name:
- service_key = service.key
- elif service_name == 'ssh' or service_name == 'SSH':
- if service.key == 'TSM-SSH':
- service_key = 'TSM-SSH'
- # If we have a service_key, we've found a match. Update the policy.
- if service_key:
- try:
- service_manager.UpdateServicePolicy(id=service_key, policy=service_policy)
- except vim.fault.NotFound:
- msg = 'The service name \'{0}\' was not found.'.format(service_name)
- log.debug(msg)
- ret.update({host_name: {'Error': msg}})
- continue
- # Some services are restricted by the vSphere License Level.
- except vim.fault.HostConfigFault as err:
- msg = '\'vsphere.set_service_policy\' failed for host {0}: {1}'.format(host_name, err)
- log.debug(msg)
- ret.update({host_name: {'Error': msg}})
- continue
- ret.update({host_name: True})
- # If we made it this far, something else has gone wrong.
- if ret.get(host_name) is None:
- msg = 'Could not find service \'{0}\' for host \'{1}\'.'.format(service_name, host_name)
- log.debug(msg)
- ret.update({host_name: {'Error': msg}})
- return ret
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def update_host_datetime(host, username, password, protocol=None, port=None, host_names=None):
- '''
- Update the date/time on the given host or list of host_names. This function should be
- used with caution since network delays and execution delays can result in time skews.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- host_names
- List of ESXi host names. When the host, username, and password credentials
- are provided for a vCenter Server, the host_names argument is required to
- tell vCenter which hosts should update their date/time.
- If host_names is not provided, the date/time will be updated for the ``host``
- location instead. This is useful for when service instance connection
- information is used for a single ESXi host.
- CLI Example:
- .. code-block:: bash
- # Used for single ESXi host connection information
- salt '*' vsphere.update_date_time my.esxi.host root bad-password
- # Used for connecting to a vCenter Server
- salt '*' vsphere.update_date_time my.vcenter.location root bad-password \
- host_names='[esxi-1.host.com, esxi-2.host.com]'
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- host_names = _check_hosts(service_instance, host, host_names)
- ret = {}
- for host_name in host_names:
- host_ref = _get_host_ref(service_instance, host, host_name=host_name)
- date_time_manager = _get_date_time_mgr(host_ref)
- try:
- date_time_manager.UpdateDateTime(datetime.datetime.utcnow())
- except vim.fault.HostConfigFault as err:
- msg = '\'vsphere.update_date_time\' failed for host {0}: {1}'.format(host_name, err)
- log.debug(msg)
- ret.update({host_name: {'Error': msg}})
- continue
- ret.update({host_name: {'Datetime Updated': True}})
- return ret
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def update_host_password(host, username, password, new_password, protocol=None, port=None):
- '''
- Update the password for a given host.
- .. note:: Currently only works with connections to ESXi hosts. Does not work with vCenter servers.
- host
- The location of the ESXi host.
- username
- The username used to login to the ESXi host, such as ``root``.
- password
- The password used to login to the ESXi host.
- new_password
- The new password that will be updated for the provided username on the ESXi host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- CLI Example:
- .. code-block:: bash
- salt '*' vsphere.update_host_password my.esxi.host root original-bad-password new-bad-password
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- # Get LocalAccountManager object
- account_manager = salt.utils.vmware.get_inventory(service_instance).accountManager
- # Create user account specification object and assign id and password attributes
- user_account = vim.host.LocalAccountManager.AccountSpecification()
- user_account.id = username
- user_account.password = new_password
- # Update the password
- try:
- account_manager.UpdateUser(user_account)
- except vmodl.fault.SystemError as err:
- raise CommandExecutionError(err.msg)
- except vim.fault.UserNotFound:
- raise CommandExecutionError('\'vsphere.update_host_password\' failed for host {0}: '
- 'User was not found.'.format(host))
- # If the username and password already exist, we don't need to do anything.
- except vim.fault.AlreadyExists:
- pass
- return True
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def vmotion_disable(host, username, password, protocol=None, port=None, host_names=None):
- '''
- Disable vMotion for a given host or list of host_names.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- host_names
- List of ESXi host names. When the host, username, and password credentials
- are provided for a vCenter Server, the host_names argument is required to
- tell vCenter which hosts should disable VMotion.
- If host_names is not provided, VMotion will be disabled for the ``host``
- location instead. This is useful for when service instance connection
- information is used for a single ESXi host.
- CLI Example:
- .. code-block:: bash
- # Used for single ESXi host connection information
- salt '*' vsphere.vmotion_disable my.esxi.host root bad-password
- # Used for connecting to a vCenter Server
- salt '*' vsphere.vmotion_disable my.vcenter.location root bad-password \
- host_names='[esxi-1.host.com, esxi-2.host.com]'
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- host_names = _check_hosts(service_instance, host, host_names)
- ret = {}
- for host_name in host_names:
- host_ref = _get_host_ref(service_instance, host, host_name=host_name)
- vmotion_system = host_ref.configManager.vmotionSystem
- # Disable VMotion for the host by removing the VNic selected to use for VMotion.
- try:
- vmotion_system.DeselectVnic()
- except vim.fault.HostConfigFault as err:
- msg = 'vsphere.vmotion_disable failed: {0}'.format(err)
- log.debug(msg)
- ret.update({host_name: {'Error': msg,
- 'VMotion Disabled': False}})
- continue
- ret.update({host_name: {'VMotion Disabled': True}})
- return ret
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def vmotion_enable(host, username, password, protocol=None, port=None, host_names=None, device='vmk0'):
- '''
- Enable vMotion for a given host or list of host_names.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- host_names
- List of ESXi host names. When the host, username, and password credentials
- are provided for a vCenter Server, the host_names argument is required to
- tell vCenter which hosts should enable VMotion.
- If host_names is not provided, VMotion will be enabled for the ``host``
- location instead. This is useful for when service instance connection
- information is used for a single ESXi host.
- device
- The device that uniquely identifies the VirtualNic that will be used for
- VMotion for each host. Defaults to ``vmk0``.
- CLI Example:
- .. code-block:: bash
- # Used for single ESXi host connection information
- salt '*' vsphere.vmotion_enable my.esxi.host root bad-password
- # Used for connecting to a vCenter Server
- salt '*' vsphere.vmotion_enable my.vcenter.location root bad-password \
- host_names='[esxi-1.host.com, esxi-2.host.com]'
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- host_names = _check_hosts(service_instance, host, host_names)
- ret = {}
- for host_name in host_names:
- host_ref = _get_host_ref(service_instance, host, host_name=host_name)
- vmotion_system = host_ref.configManager.vmotionSystem
- # Enable VMotion for the host by setting the given device to provide the VNic to use for VMotion.
- try:
- vmotion_system.SelectVnic(device)
- except vim.fault.HostConfigFault as err:
- msg = 'vsphere.vmotion_disable failed: {0}'.format(err)
- log.debug(msg)
- ret.update({host_name: {'Error': msg,
- 'VMotion Enabled': False}})
- continue
- ret.update({host_name: {'VMotion Enabled': True}})
- return ret
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def vsan_add_disks(host, username, password, protocol=None, port=None, host_names=None):
- '''
- Add any VSAN-eligible disks to the VSAN System for the given host or list of host_names.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- host_names
- List of ESXi host names. When the host, username, and password credentials
- are provided for a vCenter Server, the host_names argument is required to
- tell vCenter which hosts need to add any VSAN-eligible disks to the host's
- VSAN system.
- If host_names is not provided, VSAN-eligible disks will be added to the hosts's
- VSAN system for the ``host`` location instead. This is useful for when service
- instance connection information is used for a single ESXi host.
- CLI Example:
- .. code-block:: bash
- # Used for single ESXi host connection information
- salt '*' vsphere.vsan_add_disks my.esxi.host root bad-password
- # Used for connecting to a vCenter Server
- salt '*' vsphere.vsan_add_disks my.vcenter.location root bad-password \
- host_names='[esxi-1.host.com, esxi-2.host.com]'
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- host_names = _check_hosts(service_instance, host, host_names)
- response = _get_vsan_eligible_disks(service_instance, host, host_names)
- ret = {}
- for host_name, value in six.iteritems(response):
- host_ref = _get_host_ref(service_instance, host, host_name=host_name)
- vsan_system = host_ref.configManager.vsanSystem
- # We must have a VSAN Config in place before we can manipulate it.
- if vsan_system is None:
- msg = 'VSAN System Config Manager is unset for host \'{0}\'. ' \
- 'VSAN configuration cannot be changed without a configured ' \
- 'VSAN System.'.format(host_name)
- log.debug(msg)
- ret.update({host_name: {'Error': msg}})
- else:
- eligible = value.get('Eligible')
- error = value.get('Error')
- if eligible and isinstance(eligible, list):
- # If we have eligible, matching disks, add them to VSAN.
- try:
- task = vsan_system.AddDisks(eligible)
- salt.utils.vmware.wait_for_task(task, host_name, 'Adding disks to VSAN', sleep_seconds=3)
- except vim.fault.InsufficientDisks as err:
- log.debug(err.msg)
- ret.update({host_name: {'Error': err.msg}})
- continue
- except Exception as err:
- msg = '\'vsphere.vsan_add_disks\' failed for host {0}: {1}'.format(host_name, err)
- log.debug(msg)
- ret.update({host_name: {'Error': msg}})
- continue
- log.debug('Successfully added disks to the VSAN system for host \'{0}\'.'.format(host_name))
- # We need to return ONLY the disk names, otherwise Message Pack can't deserialize the disk objects.
- disk_names = []
- for disk in eligible:
- disk_names.append(disk.canonicalName)
- ret.update({host_name: {'Disks Added': disk_names}})
- elif eligible and isinstance(eligible, six.string_types):
- # If we have a string type in the eligible value, we don't
- # have any VSAN-eligible disks. Pull the message through.
- ret.update({host_name: {'Disks Added': eligible}})
- elif error:
- # If we hit an error, populate the Error return dict for state functions.
- ret.update({host_name: {'Error': error}})
- else:
- # If we made it this far, we somehow have eligible disks, but they didn't
- # match the disk list and just got an empty list of matching disks.
- ret.update({host_name: {'Disks Added': 'No new VSAN-eligible disks were found to add.'}})
- return ret
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def vsan_disable(host, username, password, protocol=None, port=None, host_names=None):
- '''
- Disable VSAN for a given host or list of host_names.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- host_names
- List of ESXi host names. When the host, username, and password credentials
- are provided for a vCenter Server, the host_names argument is required to
- tell vCenter which hosts should disable VSAN.
- If host_names is not provided, VSAN will be disabled for the ``host``
- location instead. This is useful for when service instance connection
- information is used for a single ESXi host.
- CLI Example:
- .. code-block:: bash
- # Used for single ESXi host connection information
- salt '*' vsphere.vsan_disable my.esxi.host root bad-password
- # Used for connecting to a vCenter Server
- salt '*' vsphere.vsan_disable my.vcenter.location root bad-password \
- host_names='[esxi-1.host.com, esxi-2.host.com]'
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- # Create a VSAN Configuration Object and set the enabled attribute to True
- vsan_config = vim.vsan.host.ConfigInfo()
- vsan_config.enabled = False
- host_names = _check_hosts(service_instance, host, host_names)
- ret = {}
- for host_name in host_names:
- host_ref = _get_host_ref(service_instance, host, host_name=host_name)
- vsan_system = host_ref.configManager.vsanSystem
- # We must have a VSAN Config in place before we can manipulate it.
- if vsan_system is None:
- msg = 'VSAN System Config Manager is unset for host \'{0}\'. ' \
- 'VSAN configuration cannot be changed without a configured ' \
- 'VSAN System.'.format(host_name)
- log.debug(msg)
- ret.update({host_name: {'Error': msg}})
- else:
- try:
- # Disable vsan on the host
- task = vsan_system.UpdateVsan_Task(vsan_config)
- salt.utils.vmware.wait_for_task(task, host_name, 'Disabling VSAN', sleep_seconds=3)
- except vmodl.fault.SystemError as err:
- log.debug(err.msg)
- ret.update({host_name: {'Error': err.msg}})
- continue
- except Exception as err:
- msg = '\'vsphere.vsan_disable\' failed for host {0}: {1}'.format(host_name, err)
- log.debug(msg)
- ret.update({host_name: {'Error': msg}})
- continue
- ret.update({host_name: {'VSAN Disabled': True}})
- return ret
- @depends(HAS_PYVMOMI)
- @ignores_kwargs('credstore')
- def vsan_enable(host, username, password, protocol=None, port=None, host_names=None):
- '''
- Enable VSAN for a given host or list of host_names.
- host
- The location of the host.
- username
- The username used to login to the host, such as ``root``.
- password
- The password used to login to the host.
- protocol
- Optionally set to alternate protocol if the host is not using the default
- protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the host is not using the default
- port. Default port is ``443``.
- host_names
- List of ESXi host names. When the host, username, and password credentials
- are provided for a vCenter Server, the host_names argument is required to
- tell vCenter which hosts should enable VSAN.
- If host_names is not provided, VSAN will be enabled for the ``host``
- location instead. This is useful for when service instance connection
- information is used for a single ESXi host.
- CLI Example:
- .. code-block:: bash
- # Used for single ESXi host connection information
- salt '*' vsphere.vsan_enable my.esxi.host root bad-password
- # Used for connecting to a vCenter Server
- salt '*' vsphere.vsan_enable my.vcenter.location root bad-password \
- host_names='[esxi-1.host.com, esxi-2.host.com]'
- '''
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- # Create a VSAN Configuration Object and set the enabled attribute to True
- vsan_config = vim.vsan.host.ConfigInfo()
- vsan_config.enabled = True
- host_names = _check_hosts(service_instance, host, host_names)
- ret = {}
- for host_name in host_names:
- host_ref = _get_host_ref(service_instance, host, host_name=host_name)
- vsan_system = host_ref.configManager.vsanSystem
- # We must have a VSAN Config in place before we can manipulate it.
- if vsan_system is None:
- msg = 'VSAN System Config Manager is unset for host \'{0}\'. ' \
- 'VSAN configuration cannot be changed without a configured ' \
- 'VSAN System.'.format(host_name)
- log.debug(msg)
- ret.update({host_name: {'Error': msg}})
- else:
- try:
- # Enable vsan on the host
- task = vsan_system.UpdateVsan_Task(vsan_config)
- salt.utils.vmware.wait_for_task(task, host_name, 'Enabling VSAN', sleep_seconds=3)
- except vmodl.fault.SystemError as err:
- log.debug(err.msg)
- ret.update({host_name: {'Error': err.msg}})
- continue
- except vim.fault.VsanFault as err:
- msg = '\'vsphere.vsan_enable\' failed for host {0}: {1}'.format(host_name, err)
- log.debug(msg)
- ret.update({host_name: {'Error': msg}})
- continue
- ret.update({host_name: {'VSAN Enabled': True}})
- return ret
- def _check_hosts(service_instance, host, host_names):
- '''
- Helper function that checks to see if the host provided is a vCenter Server or
- an ESXi host. If it's an ESXi host, returns a list of a single host_name.
- If a host reference isn't found, we're trying to find a host object for a vCenter
- server. Raises a CommandExecutionError in this case, as we need host references to
- check against.
- '''
- if not host_names:
- host_name = _get_host_ref(service_instance, host)
- if host_name:
- host_names = [host]
- else:
- raise CommandExecutionError('No host reference found. If connecting to a '
- 'vCenter Server, a list of \'host_names\' must be '
- 'provided.')
- elif not isinstance(host_names, list):
- raise CommandExecutionError('\'host_names\' must be a list.')
- return host_names
- def _format_coredump_stdout(cmd_ret):
- '''
- Helper function to format the stdout from the get_coredump_network_config function.
- cmd_ret
- The return dictionary that comes from a cmd.run_all call.
- '''
- ret_dict = {}
- for line in cmd_ret['stdout'].splitlines():
- line = line.strip().lower()
- if line.startswith('enabled:'):
- enabled = line.split(':')
- if 'true' in enabled[1]:
- ret_dict['enabled'] = True
- else:
- ret_dict['enabled'] = False
- break
- if line.startswith('host vnic:'):
- host_vnic = line.split(':')
- ret_dict['host_vnic'] = host_vnic[1].strip()
- if line.startswith('network server ip:'):
- ip = line.split(':')
- ret_dict['ip'] = ip[1].strip()
- if line.startswith('network server port:'):
- ip_port = line.split(':')
- ret_dict['port'] = ip_port[1].strip()
- return ret_dict
- def _format_firewall_stdout(cmd_ret):
- '''
- Helper function to format the stdout from the get_firewall_status function.
- cmd_ret
- The return dictionary that comes from a cmd.run_all call.
- '''
- ret_dict = {'success': True,
- 'rulesets': {}}
- for line in cmd_ret['stdout'].splitlines():
- if line.startswith('Name'):
- continue
- if line.startswith('---'):
- continue
- ruleset_status = line.split()
- ret_dict['rulesets'][ruleset_status[0]] = bool(ruleset_status[1])
- return ret_dict
- def _format_syslog_config(cmd_ret):
- '''
- Helper function to format the stdout from the get_syslog_config function.
- cmd_ret
- The return dictionary that comes from a cmd.run_all call.
- '''
- ret_dict = {'success': cmd_ret['retcode'] == 0}
- if cmd_ret['retcode'] != 0:
- ret_dict['message'] = cmd_ret['stdout']
- else:
- for line in cmd_ret['stdout'].splitlines():
- line = line.strip()
- cfgvars = line.split(': ')
- key = cfgvars[0].strip()
- value = cfgvars[1].strip()
- ret_dict[key] = value
- return ret_dict
- def _get_date_time_mgr(host_reference):
- '''
- Helper function that returns a dateTimeManager object
- '''
- return host_reference.configManager.dateTimeSystem
- def _get_host_ref(service_instance, host, host_name=None):
- '''
- Helper function that returns a host object either from the host location or the host_name.
- If host_name is provided, that is the host_object that will be returned.
- The function will first search for hosts by DNS Name. If no hosts are found, it will
- try searching by IP Address.
- '''
- search_index = salt.utils.vmware.get_inventory(service_instance).searchIndex
- # First, try to find the host reference by DNS Name.
- if host_name:
- host_ref = search_index.FindByDnsName(dnsName=host_name, vmSearch=False)
- else:
- host_ref = search_index.FindByDnsName(dnsName=host, vmSearch=False)
- # If we couldn't find the host by DNS Name, then try the IP Address.
- if host_ref is None:
- host_ref = search_index.FindByIp(ip=host, vmSearch=False)
- return host_ref
- def _get_host_ssds(host_reference):
- '''
- Helper function that returns a list of ssd objects for a given host.
- '''
- return _get_host_disks(host_reference).get('SSDs')
- def _get_host_non_ssds(host_reference):
- '''
- Helper function that returns a list of Non-SSD objects for a given host.
- '''
- return _get_host_disks(host_reference).get('Non-SSDs')
- def _get_host_disks(host_reference):
- '''
- Helper function that returns a dictionary containing a list of SSD and Non-SSD disks.
- '''
- storage_system = host_reference.configManager.storageSystem
- disks = storage_system.storageDeviceInfo.scsiLun
- ssds = []
- non_ssds = []
- for disk in disks:
- try:
- has_ssd_attr = disk.ssd
- except AttributeError:
- has_ssd_attr = False
- if has_ssd_attr:
- ssds.append(disk)
- else:
- non_ssds.append(disk)
- return {'SSDs': ssds, 'Non-SSDs': non_ssds}
- def _get_service_manager(host_reference):
- '''
- Helper function that returns a service manager object from a given host object.
- '''
- return host_reference.configManager.serviceSystem
- def _get_vsan_eligible_disks(service_instance, host, host_names):
- '''
- Helper function that returns a dictionary of host_name keys with either a list of eligible
- disks that can be added to VSAN or either an 'Error' message or a message saying no
- eligible disks were found. Possible keys/values look like:
- return = {'host_1': {'Error': 'VSAN System Config Manager is unset ...'},
- 'host_2': {'Eligible': 'The host xxx does not have any VSAN eligible disks.'},
- 'host_3': {'Eligible': [disk1, disk2, disk3, disk4],
- 'host_4': {'Eligible': []}}
- '''
- ret = {}
- for host_name in host_names:
- # Get VSAN System Config Manager, if available.
- host_ref = _get_host_ref(service_instance, host, host_name=host_name)
- vsan_system = host_ref.configManager.vsanSystem
- if vsan_system is None:
- msg = 'VSAN System Config Manager is unset for host \'{0}\'. ' \
- 'VSAN configuration cannot be changed without a configured ' \
- 'VSAN System.'.format(host_name)
- log.debug(msg)
- ret.update({host_name: {'Error': msg}})
- continue
- # Get all VSAN suitable disks for this host.
- suitable_disks = []
- query = vsan_system.QueryDisksForVsan()
- for item in query:
- if item.state == 'eligible':
- suitable_disks.append(item)
- # No suitable disks were found to add. Warn and move on.
- # This isn't an error as the state may run repeatedly after all eligible disks are added.
- if not suitable_disks:
- msg = 'The host \'{0}\' does not have any VSAN eligible disks.'.format(host_name)
- log.warning(msg)
- ret.update({host_name: {'Eligible': msg}})
- continue
- # Get disks for host and combine into one list of Disk Objects
- disks = _get_host_ssds(host_ref) + _get_host_non_ssds(host_ref)
- # Get disks that are in both the disks list and suitable_disks lists.
- matching = []
- for disk in disks:
- for suitable_disk in suitable_disks:
- if disk.canonicalName == suitable_disk.disk.canonicalName:
- matching.append(disk)
- ret.update({host_name: {'Eligible': matching}})
- return ret
- def _reset_syslog_config_params(host, username, password, cmd, resets, valid_resets,
- protocol=None, port=None, esxi_host=None, credstore=None):
- '''
- Helper function for reset_syslog_config that resets the config and populates the return dictionary.
- '''
- ret_dict = {}
- all_success = True
- if not isinstance(resets, list):
- resets = [resets]
- for reset_param in resets:
- if reset_param in valid_resets:
- ret = salt.utils.vmware.esxcli(host, username, password, cmd + reset_param,
- protocol=protocol, port=port,
- esxi_host=esxi_host, credstore=credstore)
- ret_dict[reset_param] = {}
- ret_dict[reset_param]['success'] = ret['retcode'] == 0
- if ret['retcode'] != 0:
- all_success = False
- ret_dict[reset_param]['message'] = ret['stdout']
- else:
- all_success = False
- ret_dict[reset_param] = {}
- ret_dict[reset_param]['success'] = False
- ret_dict[reset_param]['message'] = 'Invalid syslog ' \
- 'configuration parameter'
- ret_dict['success'] = all_success
- return ret_dict
- def _set_syslog_config_helper(host, username, password, syslog_config, config_value,
- protocol=None, port=None, reset_service=None, esxi_host=None, credstore=None):
- '''
- Helper function for set_syslog_config that sets the config and populates the return dictionary.
- '''
- cmd = 'system syslog config set --{0} {1}'.format(syslog_config, config_value)
- ret_dict = {}
- valid_resets = ['logdir', 'loghost', 'default-rotate',
- 'default-size', 'default-timeout', 'logdir-unique']
- if syslog_config not in valid_resets:
- ret_dict.update({'success': False,
- 'message': '\'{0}\' is not a valid config variable.'.format(syslog_config)})
- return ret_dict
- response = salt.utils.vmware.esxcli(host, username, password, cmd,
- protocol=protocol, port=port,
- esxi_host=esxi_host, credstore=credstore)
- # Update the return dictionary for success or error messages.
- if response['retcode'] != 0:
- ret_dict.update({syslog_config: {'success': False,
- 'message': response['stdout']}})
- else:
- ret_dict.update({syslog_config: {'success': True}})
- # Restart syslog for each host, if desired.
- if reset_service:
- if esxi_host:
- host_name = esxi_host
- esxi_host = [esxi_host]
- else:
- host_name = host
- response = syslog_service_reload(host, username, password,
- protocol=protocol, port=port,
- esxi_hosts=esxi_host, credstore=credstore).get(host_name)
- ret_dict.update({'syslog_restart': {'success': response['retcode'] == 0}})
- return ret_dict
- @ignores_kwargs('credstore')
- def add_host_to_dvs(host, username, password, vmknic_name, vmnic_name,
- dvs_name, target_portgroup_name, uplink_portgroup_name,
- protocol=None, port=None, host_names=None):
- '''
- Adds an ESXi host to a vSphere Distributed Virtual Switch and migrates
- the desired adapters to the DVS from the standard switch.
- host
- The location of the vCenter server.
- username
- The username used to login to the vCenter server.
- password
- The password used to login to the vCenter server.
- vmknic_name
- The name of the virtual NIC to migrate.
- vmnic_name
- The name of the physical NIC to migrate.
- dvs_name
- The name of the Distributed Virtual Switch.
- target_portgroup_name
- The name of the distributed portgroup in which to migrate the
- virtual NIC.
- uplink_portgroup_name
- The name of the uplink portgroup in which to migrate the
- physical NIC.
- protocol
- Optionally set to alternate protocol if the vCenter server or ESX/ESXi host is not
- using the default protocol. Default protocol is ``https``.
- port
- Optionally set to alternate port if the vCenter server or ESX/ESXi host is not
- using the default port. Default port is ``443``.
- host_names:
- An array of VMware host names to migrate
- CLI Example:
- .. code-block:: bash
- salt some_host vsphere.add_host_to_dvs host='vsphere.corp.com'
- username='administrator@vsphere.corp.com' password='vsphere_password'
- vmknic_name='vmk0' vmnic_name='vnmic0' dvs_name='DSwitch'
- target_portgroup_name='DPortGroup' uplink_portgroup_name='DSwitch1-DVUplinks-181'
- protocol='https' port='443', host_names="['esxi1.corp.com','esxi2.corp.com','esxi3.corp.com']"
- Return Example:
- .. code-block:: yaml
- somehost:
- ----------
- esxi1.corp.com:
- ----------
- dvs:
- DSwitch
- portgroup:
- DPortGroup
- status:
- True
- uplink:
- DSwitch-DVUplinks-181
- vmknic:
- vmk0
- vmnic:
- vmnic0
- esxi2.corp.com:
- ----------
- dvs:
- DSwitch
- portgroup:
- DPortGroup
- status:
- True
- uplink:
- DSwitch-DVUplinks-181
- vmknic:
- vmk0
- vmnic:
- vmnic0
- esxi3.corp.com:
- ----------
- dvs:
- DSwitch
- portgroup:
- DPortGroup
- status:
- True
- uplink:
- DSwitch-DVUplinks-181
- vmknic:
- vmk0
- vmnic:
- vmnic0
- message:
- success:
- True
- This was very difficult to figure out. VMware's PyVmomi documentation at
- https://github.com/vmware/pyvmomi/blob/master/docs/vim/DistributedVirtualSwitch.rst
- (which is a copy of the official documentation here:
- https://www.vmware.com/support/developer/converter-sdk/conv60_apireference/vim.DistributedVirtualSwitch.html)
- says to create the DVS, create distributed portgroups, and then add the
- host to the DVS specifying which physical NIC to use as the port backing.
- However, if the physical NIC is in use as the only link from the host
- to vSphere, this will fail with an unhelpful "busy" error.
- There is, however, a Powershell PowerCLI cmdlet called Add-VDSwitchPhysicalNetworkAdapter
- that does what we want. I used Onyx (https://labs.vmware.com/flings/onyx)
- to sniff the SOAP stream from Powershell to our vSphere server and got
- this snippet out:
- <UpdateNetworkConfig xmlns="urn:vim25">
- <_this type="HostNetworkSystem">networkSystem-187</_this>
- <config>
- <vswitch>
- <changeOperation>edit</changeOperation>
- <name>vSwitch0</name>
- <spec>
- <numPorts>7812</numPorts>
- </spec>
- </vswitch>
- <proxySwitch>
- <changeOperation>edit</changeOperation>
- <uuid>73 a4 05 50 b0 d2 7e b9-38 80 5d 24 65 8f da 70</uuid>
- <spec>
- <backing xsi:type="DistributedVirtualSwitchHostMemberPnicBacking">
- <pnicSpec><pnicDevice>vmnic0</pnicDevice></pnicSpec>
- </backing>
- </spec>
- </proxySwitch>
- <portgroup>
- <changeOperation>remove</changeOperation>
- <spec>
- <name>Management Network</name><vlanId>-1</vlanId><vswitchName /><policy />
- </spec>
- </portgroup>
- <vnic>
- <changeOperation>edit</changeOperation>
- <device>vmk0</device>
- <portgroup />
- <spec>
- <distributedVirtualPort>
- <switchUuid>73 a4 05 50 b0 d2 7e b9-38 80 5d 24 65 8f da 70</switchUuid>
- <portgroupKey>dvportgroup-191</portgroupKey>
- </distributedVirtualPort>
- </spec>
- </vnic>
- </config>
- <changeMode>modify</changeMode>
- </UpdateNetworkConfig>
- The SOAP API maps closely to PyVmomi, so from there it was (relatively)
- easy to figure out what Python to write.
- '''
- ret = {}
- ret['success'] = True
- ret['message'] = []
- service_instance = salt.utils.vmware.get_service_instance(host=host,
- username=username,
- password=password,
- protocol=protocol,
- port=port)
- dvs = salt.utils.vmware._get_dvs(service_instance, dvs_name)
- if not dvs:
- ret['message'].append('No Distributed Virtual Switch found with name {0}'.format(dvs_name))
- ret['success'] = False
- target_portgroup = salt.utils.vmware._get_dvs_portgroup(dvs,
- target_portgroup_name)
- if not target_portgroup:
- ret['message'].append('No target portgroup found with name {0}'.format(target_portgroup_name))
- ret['success'] = False
- uplink_portgroup = salt.utils.vmware._get_dvs_uplink_portgroup(dvs,
- uplink_portgroup_name)
- if not uplink_portgroup:
- ret['message'].append('No uplink portgroup found with name {0}'.format(uplink_portgroup_name))
- ret['success'] = False
- if len(ret['message']) > 0:
- return ret
- dvs_uuid = dvs.config.uuid
- try:
- host_names = _check_hosts(service_instance, host, host_names)
- except CommandExecutionError as e:
- ret['message'] = 'Error retrieving hosts: {0}'.format(e.msg)
- return ret
- for host_name in host_names:
- ret[host_name] = {}
- ret[host_name].update({'status': False,
- 'uplink': uplink_portgroup_name,
- 'portgroup': target_portgroup_name,
- 'vmknic': vmknic_name,
- 'vmnic': vmnic_name,
- 'dvs': dvs_name})
- host_ref = _get_host_ref(service_instance, host, host_name)
- if not host_ref:
- ret[host_name].update({'message': 'Host {1} not found'.format(host_name)})
- ret['success'] = False
- continue
- dvs_hostmember_config = vim.dvs.HostMember.ConfigInfo(
- host=host_ref
- )
- dvs_hostmember = vim.dvs.HostMember(
- config=dvs_hostmember_config
- )
- p_nics = salt.utils.vmware._get_pnics(host_ref)
- p_nic = [x for x in p_nics if x.device == vmnic_name]
- if len(p_nic) == 0:
- ret[host_name].update({'message': 'Physical nic {0} not found'.format(vmknic_name)})
- ret['success'] = False
- continue
- v_nics = salt.utils.vmware._get_vnics(host_ref)
- v_nic = [x for x in v_nics if x.device == vmknic_name]
- if len(v_nic) == 0:
- ret[host_name].update({'message': 'Virtual nic {0} not found'.format(vmnic_name)})
- ret['success'] = False
- continue
- v_nic_mgr = salt.utils.vmware._get_vnic_manager(host_ref)
- if not v_nic_mgr:
- ret[host_name].update({'message': 'Unable to get the host\'s virtual nic manager.'})
- ret['success'] = False
- continue
- dvs_pnic_spec = vim.dvs.HostMember.PnicSpec(
- pnicDevice=vmnic_name,
- uplinkPortgroupKey=uplink_portgroup.key
- )
- pnic_backing = vim.dvs.HostMember.PnicBacking(
- pnicSpec=[dvs_pnic_spec]
- )
- dvs_hostmember_config_spec = vim.dvs.HostMember.ConfigSpec(
- host=host_ref,
- operation='add',
- )
- dvs_config = vim.DVSConfigSpec(
- configVersion=dvs.config.configVersion,
- host=[dvs_hostmember_config_spec])
- task = dvs.ReconfigureDvs_Task(spec=dvs_config)
- try:
- salt.utils.vmware.wait_for_task(task, host_name,
- 'Adding host to the DVS',
- sleep_seconds=3)
- except Exception as e:
- if hasattr(e, 'message') and hasattr(e.message, 'msg'):
- if not (host_name in e.message.msg and 'already exists' in e.message.msg):
- ret['success'] = False
- ret[host_name].update({'message': e.message.msg})
- continue
- else:
- raise
- network_system = host_ref.configManager.networkSystem
- source_portgroup = None
- for pg in host_ref.config.network.portgroup:
- if pg.spec.name == v_nic[0].portgroup:
- source_portgroup = pg
- break
- if not source_portgroup:
- ret[host_name].update({'message': 'No matching portgroup on the vSwitch'})
- ret['success'] = False
- continue
- virtual_nic_config = vim.HostVirtualNicConfig(
- changeOperation='edit',
- device=v_nic[0].device,
- portgroup=source_portgroup.spec.name,
- spec=vim.HostVirtualNicSpec(
- distributedVirtualPort=vim.DistributedVirtualSwitchPortConnection(
- portgroupKey=target_portgroup.key,
- switchUuid=target_portgroup.config.distributedVirtualSwitch.uuid
- )
- )
- )
- current_vswitch_ports = host_ref.config.network.vswitch[0].numPorts
- vswitch_config = vim.HostVirtualSwitchConfig(
- changeOperation='edit',
- name='vSwitch0',
- spec=vim.HostVirtualSwitchSpec(numPorts=current_vswitch_ports)
- )
- proxyswitch_config = vim.HostProxySwitchConfig(
- changeOperation='edit',
- uuid=dvs_uuid,
- spec=vim.HostProxySwitchSpec(backing=pnic_backing)
- )
- host_network_config = vim.HostNetworkConfig(
- vswitch=[vswitch_config],
- proxySwitch=[proxyswitch_config],
- portgroup=[vim.HostPortGroupConfig(
- changeOperation='remove',
- spec=source_portgroup.spec)
- ],
- vnic=[virtual_nic_config])
- try:
- network_system.UpdateNetworkConfig(changeMode='modify',
- config=host_network_config)
- ret[host_name].update({'status': True})
- except Exception as e:
- if hasattr(e, 'msg'):
- ret[host_name].update({'message': 'Failed to migrate adapters ({0})'.format(e.msg)})
- continue
- else:
- raise
- return ret