PageRenderTime 713ms CodeModel.GetById 51ms RepoModel.GetById 6ms app.codeStats 1ms

/salt/modules/vsphere.py

https://bitbucket.org/bhuvanchandradv/salt
Python | 4206 lines | 3448 code | 158 blank | 600 comment | 173 complexity | 15c137cf6ced75e692d988162a92f3ee MD5 | raw file
Possible License(s): Apache-2.0
  1. # -*- coding: utf-8 -*-
  2. '''
  3. Manage VMware vCenter servers and ESXi hosts.
  4. .. versionadded:: 2015.8.4
  5. :codeauthor: :email:`Alexandru Bleotu <alexandru.bleotu@morganstaley.com>`
  6. Dependencies
  7. ============
  8. - pyVmomi Python Module
  9. - ESXCLI
  10. pyVmomi
  11. -------
  12. PyVmomi can be installed via pip:
  13. .. code-block:: bash
  14. pip install pyVmomi
  15. .. note::
  16. Version 6.0 of pyVmomi has some problems with SSL error handling on certain
  17. versions of Python. If using version 6.0 of pyVmomi, Python 2.6,
  18. Python 2.7.9, or newer must be present. This is due to an upstream dependency
  19. in pyVmomi 6.0 that is not supported in Python versions 2.7 to 2.7.8. If the
  20. version of Python is not in the supported range, you will need to install an
  21. earlier version of pyVmomi. See `Issue #29537`_ for more information.
  22. .. _Issue #29537: https://github.com/saltstack/salt/issues/29537
  23. Based on the note above, to install an earlier version of pyVmomi than the
  24. version currently listed in PyPi, run the following:
  25. .. code-block:: bash
  26. pip install pyVmomi==5.5.0.2014.1.1
  27. The 5.5.0.2014.1.1 is a known stable version that this original vSphere Execution
  28. Module was developed against.
  29. ESXCLI
  30. ------
  31. Currently, about a third of the functions used in the vSphere Execution Module require
  32. the ESXCLI package be installed on the machine running the Proxy Minion process.
  33. The ESXCLI package is also referred to as the VMware vSphere CLI, or vCLI. VMware
  34. provides vCLI package installation instructions for `vSphere 5.5`_ and
  35. `vSphere 6.0`_.
  36. .. _vSphere 5.5: http://pubs.vmware.com/vsphere-55/index.jsp#com.vmware.vcli.getstart.doc/cli_install.4.2.html
  37. .. _vSphere 6.0: http://pubs.vmware.com/vsphere-60/index.jsp#com.vmware.vcli.getstart.doc/cli_install.4.2.html
  38. Once all of the required dependencies are in place and the vCLI package is
  39. installed, you can check to see if you can connect to your ESXi host or vCenter
  40. server by running the following command:
  41. .. code-block:: bash
  42. esxcli -s <host-location> -u <username> -p <password> system syslog config get
  43. If the connection was successful, ESXCLI was successfully installed on your system.
  44. You should see output related to the ESXi host's syslog configuration.
  45. .. note::
  46. Be aware that some functionality in this execution module may depend on the
  47. type of license attached to a vCenter Server or ESXi host(s).
  48. For example, certain services are only available to manipulate service state
  49. or policies with a VMware vSphere Enterprise or Enterprise Plus license, while
  50. others are available with a Standard license. The ``ntpd`` service is restricted
  51. to an Enterprise Plus license, while ``ssh`` is available via the Standard
  52. license.
  53. Please see the `vSphere Comparison`_ page for more information.
  54. .. _vSphere Comparison: https://www.vmware.com/products/vsphere/compare
  55. About
  56. =====
  57. This execution module was designed to be able to handle connections both to a
  58. vCenter Server, as well as to an ESXi host. It utilizes the pyVmomi Python
  59. library and the ESXCLI package to run remote execution functions against either
  60. the defined vCenter server or the ESXi host.
  61. Whether or not the function runs against a vCenter Server or an ESXi host depends
  62. entirely upon the arguments passed into the function. Each function requires a
  63. ``host`` location, ``username``, and ``password``. If the credentials provided
  64. apply to a vCenter Server, then the function will be run against the vCenter
  65. Server. For example, when listing hosts using vCenter credentials, you'll get a
  66. list of hosts associated with that vCenter Server:
  67. .. code-block:: bash
  68. # salt my-minion vsphere.list_hosts <vcenter-ip> <vcenter-user> <vcenter-password>
  69. my-minion:
  70. - esxi-1.example.com
  71. - esxi-2.example.com
  72. However, some functions should be used against ESXi hosts, not vCenter Servers.
  73. Functionality such as getting a host's coredump network configuration should be
  74. performed against a host and not a vCenter server. If the authentication information
  75. you're using is against a vCenter server and not an ESXi host, you can provide the
  76. host name that is associated with the vCenter server in the command, as a list, using
  77. the ``host_names`` or ``esxi_host`` kwarg. For example:
  78. .. code-block:: bash
  79. # salt my-minion vsphere.get_coredump_network_config <vcenter-ip> <vcenter-user> \
  80. <vcenter-password> esxi_hosts='[esxi-1.example.com, esxi-2.example.com]'
  81. my-minion:
  82. ----------
  83. esxi-1.example.com:
  84. ----------
  85. Coredump Config:
  86. ----------
  87. enabled:
  88. False
  89. esxi-2.example.com:
  90. ----------
  91. Coredump Config:
  92. ----------
  93. enabled:
  94. True
  95. host_vnic:
  96. vmk0
  97. ip:
  98. coredump-location.example.com
  99. port:
  100. 6500
  101. You can also use these functions against an ESXi host directly by establishing a
  102. connection to an ESXi host using the host's location, username, and password. If ESXi
  103. connection credentials are used instead of vCenter credentials, the ``host_names`` and
  104. ``esxi_hosts`` arguments are not needed.
  105. .. code-block:: bash
  106. # salt my-minion vsphere.get_coredump_network_config esxi-1.example.com root <host-password>
  107. local:
  108. ----------
  109. 10.4.28.150:
  110. ----------
  111. Coredump Config:
  112. ----------
  113. enabled:
  114. True
  115. host_vnic:
  116. vmk0
  117. ip:
  118. coredump-location.example.com
  119. port:
  120. 6500
  121. '''
  122. # Import Python Libs
  123. from __future__ import absolute_import
  124. import datetime
  125. import logging
  126. import sys
  127. import inspect
  128. from functools import wraps
  129. # Import Salt Libs
  130. import salt.ext.six as six
  131. import salt.utils
  132. import salt.utils.vmware
  133. import salt.utils.http
  134. from salt.utils import dictupdate
  135. from salt.exceptions import CommandExecutionError, VMwareSaltError
  136. from salt.utils.decorators import depends, ignores_kwargs
  137. from salt.utils import clean_kwargs
  138. # Import Third Party Libs
  139. try:
  140. from pyVmomi import vim, vmodl
  141. HAS_PYVMOMI = True
  142. except ImportError:
  143. HAS_PYVMOMI = False
  144. esx_cli = salt.utils.which('esxcli')
  145. if esx_cli:
  146. HAS_ESX_CLI = True
  147. else:
  148. HAS_ESX_CLI = False
  149. log = logging.getLogger(__name__)
  150. __virtualname__ = 'vsphere'
  151. __proxyenabled__ = ['esxi']
  152. def __virtual__():
  153. return __virtualname__
  154. def get_proxy_type():
  155. '''
  156. Returns the proxy type
  157. CLI Example:
  158. .. code-block:: bash
  159. salt '*' vsphere.get_proxy_type
  160. '''
  161. return __pillar__['proxy']['proxytype']
  162. def _get_proxy_connection_details():
  163. '''
  164. Returns the connection details of the following proxies: esxi
  165. '''
  166. proxytype = get_proxy_type()
  167. if proxytype == 'esxi':
  168. details = __salt__['esxi.get_details']()
  169. else:
  170. raise CommandExecutionError('\'{0}\' proxy is not supported'
  171. ''.format(proxytype))
  172. return \
  173. details.get('vcenter') if 'vcenter' in details \
  174. else details.get('host'), \
  175. details.get('username'), \
  176. details.get('password'), details.get('protocol'), \
  177. details.get('port'), details.get('mechanism'), \
  178. details.get('principal'), details.get('domain')
  179. def supports_proxies(*proxy_types):
  180. '''
  181. Decorator to specify which proxy types are supported by a function
  182. proxy_types:
  183. Arbitrary list of strings with the supported types of proxies
  184. '''
  185. def _supports_proxies(fn):
  186. def __supports_proxies(*args, **kwargs):
  187. proxy_type = get_proxy_type()
  188. if proxy_type not in proxy_types:
  189. raise CommandExecutionError(
  190. '\'{0}\' proxy is not supported by function {1}'
  191. ''.format(proxy_type, fn.__name__))
  192. return fn(*args, **clean_kwargs(**kwargs))
  193. return __supports_proxies
  194. return _supports_proxies
  195. def gets_service_instance_via_proxy(fn):
  196. '''
  197. Decorator that connects to a target system (vCenter or ESXi host) using the
  198. proxy details and passes the connection (vim.ServiceInstance) to
  199. the decorated function.
  200. Notes:
  201. 1. The decorated function must have a ``service_instance`` parameter
  202. or a ``**kwarg`` type argument (name of argument is not important);
  203. 2. If the ``service_instance`` parameter is already defined, the value
  204. is passed through to the decorated function;
  205. 3. If the ``service_instance`` parameter in not defined, the
  206. connection is created using the proxy details and the service instance
  207. is returned.
  208. CLI Example:
  209. None, this is a decorator
  210. '''
  211. fn_name = fn.__name__
  212. try:
  213. arg_names, args_name, kwargs_name, default_values, _, _, _ = \
  214. inspect.getfullargspec(fn)
  215. except AttributeError:
  216. # Fallback to Python 2.7
  217. arg_names, args_name, kwargs_name, default_values = \
  218. inspect.getargspec(fn)
  219. default_values = default_values if default_values is not None else []
  220. @wraps(fn)
  221. def _gets_service_instance_via_proxy(*args, **kwargs):
  222. if 'service_instance' not in arg_names and not kwargs_name:
  223. raise CommandExecutionError(
  224. 'Function {0} must have either a \'service_instance\', or a '
  225. '\'**kwargs\' type parameter'.format(fn_name))
  226. connection_details = _get_proxy_connection_details()
  227. # Figure out how to pass in the connection value
  228. local_service_instance = None
  229. if 'service_instance' in arg_names:
  230. idx = arg_names.index('service_instance')
  231. if idx >= len(arg_names) - len(default_values):
  232. # 'service_instance' has a default value:
  233. # we check if we need to instantiate it or
  234. # pass it through
  235. #
  236. # NOTE: if 'service_instance' doesn't have a default value
  237. # it must be explicitly set in the function call so we pass it
  238. # through
  239. # There are two cases:
  240. # 1. service_instance was passed in as a positional parameter
  241. # 2. service_instance was passed in as a named paramter
  242. if len(args) > idx:
  243. # case 1: The call was made with enough positional
  244. # parameters to include 'service_instance'
  245. if not args[idx]:
  246. local_service_instance = \
  247. salt.utils.vmware.get_service_instance(
  248. *connection_details)
  249. args[idx] = local_service_instance
  250. else:
  251. # case 2: Not enough positional parameters so
  252. # 'service_instance' must be a named parameter
  253. if not kwargs.get('service_instance'):
  254. local_service_instance = \
  255. salt.utils.vmware.get_service_instance(
  256. *connection_details)
  257. kwargs['service_instance'] = local_service_instance
  258. else:
  259. # 'service_instance' is not a paremter in the function definition
  260. # but it will be caught by the **kwargs parameter
  261. if not kwargs.get('service_instance'):
  262. local_service_instance = \
  263. salt.utils.vmware.get_service_instance(
  264. *connection_details)
  265. kwargs['service_instance'] = local_service_instance
  266. try:
  267. ret = fn(*args, **clean_kwargs(**kwargs))
  268. # Disconnect if connected in the decorator
  269. if local_service_instance:
  270. salt.utils.vmware.disconnect(local_service_instance)
  271. return ret
  272. except Exception as e:
  273. # Disconnect if connected in the decorator
  274. if local_service_instance:
  275. salt.utils.vmware.disconnect(local_service_instance)
  276. # raise original exception and traceback
  277. six.reraise(*sys.exc_info())
  278. return _gets_service_instance_via_proxy
  279. @supports_proxies('esxi')
  280. def get_service_instance_via_proxy(service_instance=None):
  281. '''
  282. Returns a service instance to the proxied endpoint (vCenter/ESXi host).
  283. Note:
  284. Should be used by state functions not invoked directly.
  285. CLI Example:
  286. See note above
  287. '''
  288. connection_details = _get_proxy_connection_details()
  289. return salt.utils.vmware.get_service_instance(*connection_details)
  290. @supports_proxies('esxi')
  291. def disconnect(service_instance):
  292. '''
  293. Disconnects from a vCenter or ESXi host
  294. Note:
  295. Should be used by state functions, not invoked directly.
  296. service_instance
  297. Service instance (vim.ServiceInstance)
  298. CLI Example:
  299. See note above.
  300. '''
  301. salt.utils.vmware.disconnect(service_instance)
  302. return True
  303. @depends(HAS_ESX_CLI)
  304. def esxcli_cmd(cmd_str, host=None, username=None, password=None, protocol=None, port=None, esxi_hosts=None, credstore=None):
  305. '''
  306. Run an ESXCLI command directly on the host or list of hosts.
  307. host
  308. The location of the host.
  309. username
  310. The username used to login to the host, such as ``root``.
  311. password
  312. The password used to login to the host.
  313. cmd_str
  314. The ESXCLI command to run. Note: This should not include the ``-s``, ``-u``,
  315. ``-p``, ``-h``, ``--protocol``, or ``--portnumber`` arguments that are
  316. frequently passed when using a bare ESXCLI command from the command line.
  317. Those arguments are handled by this function via the other args and kwargs.
  318. protocol
  319. Optionally set to alternate protocol if the host is not using the default
  320. protocol. Default protocol is ``https``.
  321. port
  322. Optionally set to alternate port if the host is not using the default
  323. port. Default port is ``443``.
  324. esxi_hosts
  325. If ``host`` is a vCenter host, then use esxi_hosts to execute this function
  326. on a list of one or more ESXi machines.
  327. credstore
  328. Optionally set to path to the credential store file.
  329. CLI Example:
  330. .. code-block:: bash
  331. # Used for ESXi host connection information
  332. salt '*' vsphere.esxcli_cmd my.esxi.host root bad-password \
  333. 'system coredump network get'
  334. # Used for connecting to a vCenter Server
  335. salt '*' vsphere.esxcli_cmd my.vcenter.location root bad-password \
  336. 'system coredump network get' esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
  337. '''
  338. ret = {}
  339. if esxi_hosts:
  340. if not isinstance(esxi_hosts, list):
  341. raise CommandExecutionError('\'esxi_hosts\' must be a list.')
  342. for esxi_host in esxi_hosts:
  343. response = salt.utils.vmware.esxcli(host, username, password, cmd_str,
  344. protocol=protocol, port=port,
  345. esxi_host=esxi_host, credstore=credstore)
  346. if response['retcode'] != 0:
  347. ret.update({esxi_host: {'Error': response.get('stdout')}})
  348. else:
  349. ret.update({esxi_host: response})
  350. else:
  351. # Handles a single host or a vCenter connection when no esxi_hosts are provided.
  352. response = salt.utils.vmware.esxcli(host, username, password, cmd_str,
  353. protocol=protocol, port=port,
  354. credstore=credstore)
  355. if response['retcode'] != 0:
  356. ret.update({host: {'Error': response.get('stdout')}})
  357. else:
  358. ret.update({host: response})
  359. return ret
  360. @depends(HAS_ESX_CLI)
  361. def get_coredump_network_config(host, username, password, protocol=None, port=None, esxi_hosts=None, credstore=None):
  362. '''
  363. Retrieve information on ESXi or vCenter network dump collection and
  364. format it into a dictionary.
  365. host
  366. The location of the host.
  367. username
  368. The username used to login to the host, such as ``root``.
  369. password
  370. The password used to login to the host.
  371. protocol
  372. Optionally set to alternate protocol if the host is not using the default
  373. protocol. Default protocol is ``https``.
  374. port
  375. Optionally set to alternate port if the host is not using the default
  376. port. Default port is ``443``.
  377. esxi_hosts
  378. If ``host`` is a vCenter host, then use esxi_hosts to execute this function
  379. on a list of one or more ESXi machines.
  380. credstore
  381. Optionally set to path to the credential store file.
  382. :return: A dictionary with the network configuration, or, if getting
  383. the network config failed, a an error message retrieved from the
  384. standard cmd.run_all dictionary, per host.
  385. CLI Example:
  386. .. code-block:: bash
  387. # Used for ESXi host connection information
  388. salt '*' vsphere.get_coredump_network_config my.esxi.host root bad-password
  389. # Used for connecting to a vCenter Server
  390. salt '*' vsphere.get_coredump_network_config my.vcenter.location root bad-password \
  391. esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
  392. '''
  393. cmd = 'system coredump network get'
  394. ret = {}
  395. if esxi_hosts:
  396. if not isinstance(esxi_hosts, list):
  397. raise CommandExecutionError('\'esxi_hosts\' must be a list.')
  398. for esxi_host in esxi_hosts:
  399. response = salt.utils.vmware.esxcli(host, username, password, cmd,
  400. protocol=protocol, port=port,
  401. esxi_host=esxi_host, credstore=credstore)
  402. if response['retcode'] != 0:
  403. ret.update({esxi_host: {'Error': response.get('stdout')}})
  404. else:
  405. # format the response stdout into something useful
  406. ret.update({esxi_host: {'Coredump Config': _format_coredump_stdout(response)}})
  407. else:
  408. # Handles a single host or a vCenter connection when no esxi_hosts are provided.
  409. response = salt.utils.vmware.esxcli(host, username, password, cmd,
  410. protocol=protocol, port=port,
  411. credstore=credstore)
  412. if response['retcode'] != 0:
  413. ret.update({host: {'Error': response.get('stdout')}})
  414. else:
  415. # format the response stdout into something useful
  416. stdout = _format_coredump_stdout(response)
  417. ret.update({host: {'Coredump Config': stdout}})
  418. return ret
  419. @depends(HAS_ESX_CLI)
  420. def coredump_network_enable(host, username, password, enabled, protocol=None, port=None, esxi_hosts=None, credstore=None):
  421. '''
  422. Enable or disable ESXi core dump collection. Returns ``True`` if coredump is enabled
  423. and returns ``False`` if core dump is not enabled. If there was an error, the error
  424. will be the value printed in the ``Error`` key dictionary for the given host.
  425. host
  426. The location of the host.
  427. username
  428. The username used to login to the host, such as ``root``.
  429. password
  430. The password used to login to the host.
  431. enabled
  432. Python True or False to enable or disable coredumps.
  433. protocol
  434. Optionally set to alternate protocol if the host is not using the default
  435. protocol. Default protocol is ``https``.
  436. port
  437. Optionally set to alternate port if the host is not using the default
  438. port. Default port is ``443``.
  439. esxi_hosts
  440. If ``host`` is a vCenter host, then use esxi_hosts to execute this function
  441. on a list of one or more ESXi machines.
  442. credstore
  443. Optionally set to path to the credential store file.
  444. CLI Example:
  445. .. code-block:: bash
  446. # Used for ESXi host connection information
  447. salt '*' vsphere.coredump_network_enable my.esxi.host root bad-password True
  448. # Used for connecting to a vCenter Server
  449. salt '*' vsphere.coredump_network_enable my.vcenter.location root bad-password True \
  450. esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
  451. '''
  452. if enabled:
  453. enable_it = 1
  454. else:
  455. enable_it = 0
  456. cmd = 'system coredump network set -e {0}'.format(enable_it)
  457. ret = {}
  458. if esxi_hosts:
  459. if not isinstance(esxi_hosts, list):
  460. raise CommandExecutionError('\'esxi_hosts\' must be a list.')
  461. for esxi_host in esxi_hosts:
  462. response = salt.utils.vmware.esxcli(host, username, password, cmd,
  463. protocol=protocol, port=port,
  464. esxi_host=esxi_host, credstore=credstore)
  465. if response['retcode'] != 0:
  466. ret.update({esxi_host: {'Error': response.get('stdout')}})
  467. else:
  468. ret.update({esxi_host: {'Coredump Enabled': enabled}})
  469. else:
  470. # Handles a single host or a vCenter connection when no esxi_hosts are provided.
  471. response = salt.utils.vmware.esxcli(host, username, password, cmd,
  472. protocol=protocol, port=port,
  473. credstore=credstore)
  474. if response['retcode'] != 0:
  475. ret.update({host: {'Error': response.get('stdout')}})
  476. else:
  477. ret.update({host: {'Coredump Enabled': enabled}})
  478. return ret
  479. @depends(HAS_ESX_CLI)
  480. def set_coredump_network_config(host,
  481. username,
  482. password,
  483. dump_ip,
  484. protocol=None,
  485. port=None,
  486. host_vnic='vmk0',
  487. dump_port=6500,
  488. esxi_hosts=None,
  489. credstore=None):
  490. '''
  491. Set the network parameters for a network coredump collection.
  492. Note that ESXi requires that the dumps first be enabled (see
  493. `coredump_network_enable`) before these parameters may be set.
  494. host
  495. The location of the host.
  496. username
  497. The username used to login to the host, such as ``root``.
  498. password
  499. The password used to login to the host.
  500. dump_ip
  501. IP address of host that will accept the dump.
  502. protocol
  503. Optionally set to alternate protocol if the host is not using the default
  504. protocol. Default protocol is ``https``.
  505. port
  506. Optionally set to alternate port if the host is not using the default
  507. port. Default port is ``443``.
  508. esxi_hosts
  509. If ``host`` is a vCenter host, then use esxi_hosts to execute this function
  510. on a list of one or more ESXi machines.
  511. host_vnic
  512. Host VNic port through which to communicate. Defaults to ``vmk0``.
  513. dump_port
  514. TCP port to use for the dump, defaults to ``6500``.
  515. credstore
  516. Optionally set to path to the credential store file.
  517. :return: A standard cmd.run_all dictionary with a `success` key added, per host.
  518. `success` will be True if the set succeeded, False otherwise.
  519. CLI Example:
  520. .. code-block:: bash
  521. # Used for ESXi host connection information
  522. salt '*' vsphere.set_coredump_network_config my.esxi.host root bad-password 'dump_ip.host.com'
  523. # Used for connecting to a vCenter Server
  524. salt '*' vsphere.set_coredump_network_config my.vcenter.location root bad-password 'dump_ip.host.com' \
  525. esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
  526. '''
  527. cmd = 'system coredump network set -v {0} -i {1} -o {2}'.format(host_vnic,
  528. dump_ip,
  529. dump_port)
  530. ret = {}
  531. if esxi_hosts:
  532. if not isinstance(esxi_hosts, list):
  533. raise CommandExecutionError('\'esxi_hosts\' must be a list.')
  534. for esxi_host in esxi_hosts:
  535. response = salt.utils.vmware.esxcli(host, username, password, cmd,
  536. protocol=protocol, port=port,
  537. esxi_host=esxi_host, credstore=credstore)
  538. if response['retcode'] != 0:
  539. response['success'] = False
  540. else:
  541. response['success'] = True
  542. # Update the cmd.run_all dictionary for each particular host.
  543. ret.update({esxi_host: response})
  544. else:
  545. # Handles a single host or a vCenter connection when no esxi_hosts are provided.
  546. response = salt.utils.vmware.esxcli(host, username, password, cmd,
  547. protocol=protocol, port=port,
  548. credstore=credstore)
  549. if response['retcode'] != 0:
  550. response['success'] = False
  551. else:
  552. response['success'] = True
  553. ret.update({host: response})
  554. return ret
  555. @depends(HAS_ESX_CLI)
  556. def get_firewall_status(host, username, password, protocol=None, port=None, esxi_hosts=None, credstore=None):
  557. '''
  558. Show status of all firewall rule sets.
  559. host
  560. The location of the host.
  561. username
  562. The username used to login to the host, such as ``root``.
  563. password
  564. The password used to login to the host.
  565. protocol
  566. Optionally set to alternate protocol if the host is not using the default
  567. protocol. Default protocol is ``https``.
  568. port
  569. Optionally set to alternate port if the host is not using the default
  570. port. Default port is ``443``.
  571. esxi_hosts
  572. If ``host`` is a vCenter host, then use esxi_hosts to execute this function
  573. on a list of one or more ESXi machines.
  574. credstore
  575. Optionally set to path to the credential store file.
  576. :return: Nested dictionary with two toplevel keys ``rulesets`` and ``success``
  577. ``success`` will be True or False depending on query success
  578. ``rulesets`` will list the rulesets and their statuses if ``success``
  579. was true, per host.
  580. CLI Example:
  581. .. code-block:: bash
  582. # Used for ESXi host connection information
  583. salt '*' vsphere.get_firewall_status my.esxi.host root bad-password
  584. # Used for connecting to a vCenter Server
  585. salt '*' vsphere.get_firewall_status my.vcenter.location root bad-password \
  586. esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
  587. '''
  588. cmd = 'network firewall ruleset list'
  589. ret = {}
  590. if esxi_hosts:
  591. if not isinstance(esxi_hosts, list):
  592. raise CommandExecutionError('\'esxi_hosts\' must be a list.')
  593. for esxi_host in esxi_hosts:
  594. response = salt.utils.vmware.esxcli(host, username, password, cmd,
  595. protocol=protocol, port=port,
  596. esxi_host=esxi_host, credstore=credstore)
  597. if response['retcode'] != 0:
  598. ret.update({esxi_host: {'Error': response['stdout'],
  599. 'success': False,
  600. 'rulesets': None}})
  601. else:
  602. # format the response stdout into something useful
  603. ret.update({esxi_host: _format_firewall_stdout(response)})
  604. else:
  605. # Handles a single host or a vCenter connection when no esxi_hosts are provided.
  606. response = salt.utils.vmware.esxcli(host, username, password, cmd,
  607. protocol=protocol, port=port,
  608. credstore=credstore)
  609. if response['retcode'] != 0:
  610. ret.update({host: {'Error': response['stdout'],
  611. 'success': False,
  612. 'rulesets': None}})
  613. else:
  614. # format the response stdout into something useful
  615. ret.update({host: _format_firewall_stdout(response)})
  616. return ret
  617. @depends(HAS_ESX_CLI)
  618. def enable_firewall_ruleset(host,
  619. username,
  620. password,
  621. ruleset_enable,
  622. ruleset_name,
  623. protocol=None,
  624. port=None,
  625. esxi_hosts=None,
  626. credstore=None):
  627. '''
  628. Enable or disable an ESXi firewall rule set.
  629. host
  630. The location of the host.
  631. username
  632. The username used to login to the host, such as ``root``.
  633. password
  634. The password used to login to the host.
  635. ruleset_enable
  636. True to enable the ruleset, false to disable.
  637. ruleset_name
  638. Name of ruleset to target.
  639. protocol
  640. Optionally set to alternate protocol if the host is not using the default
  641. protocol. Default protocol is ``https``.
  642. port
  643. Optionally set to alternate port if the host is not using the default
  644. port. Default port is ``443``.
  645. esxi_hosts
  646. If ``host`` is a vCenter host, then use esxi_hosts to execute this function
  647. on a list of one or more ESXi machines.
  648. credstore
  649. Optionally set to path to the credential store file.
  650. :return: A standard cmd.run_all dictionary, per host.
  651. CLI Example:
  652. .. code-block:: bash
  653. # Used for ESXi host connection information
  654. salt '*' vsphere.enable_firewall_ruleset my.esxi.host root bad-password True 'syslog'
  655. # Used for connecting to a vCenter Server
  656. salt '*' vsphere.enable_firewall_ruleset my.vcenter.location root bad-password True 'syslog' \
  657. esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
  658. '''
  659. cmd = 'network firewall ruleset set --enabled {0} --ruleset-id={1}'.format(
  660. ruleset_enable, ruleset_name
  661. )
  662. ret = {}
  663. if esxi_hosts:
  664. if not isinstance(esxi_hosts, list):
  665. raise CommandExecutionError('\'esxi_hosts\' must be a list.')
  666. for esxi_host in esxi_hosts:
  667. response = salt.utils.vmware.esxcli(host, username, password, cmd,
  668. protocol=protocol, port=port,
  669. esxi_host=esxi_host, credstore=credstore)
  670. ret.update({esxi_host: response})
  671. else:
  672. # Handles a single host or a vCenter connection when no esxi_hosts are provided.
  673. response = salt.utils.vmware.esxcli(host, username, password, cmd,
  674. protocol=protocol, port=port,
  675. credstore=credstore)
  676. ret.update({host: response})
  677. return ret
  678. @depends(HAS_ESX_CLI)
  679. def syslog_service_reload(host, username, password, protocol=None, port=None, esxi_hosts=None, credstore=None):
  680. '''
  681. Reload the syslog service so it will pick up any changes.
  682. host
  683. The location of the host.
  684. username
  685. The username used to login to the host, such as ``root``.
  686. password
  687. The password used to login to the host.
  688. protocol
  689. Optionally set to alternate protocol if the host is not using the default
  690. protocol. Default protocol is ``https``.
  691. port
  692. Optionally set to alternate port if the host is not using the default
  693. port. Default port is ``443``.
  694. esxi_hosts
  695. If ``host`` is a vCenter host, then use esxi_hosts to execute this function
  696. on a list of one or more ESXi machines.
  697. credstore
  698. Optionally set to path to the credential store file.
  699. :return: A standard cmd.run_all dictionary. This dictionary will at least
  700. have a `retcode` key. If `retcode` is 0 the command was successful.
  701. CLI Example:
  702. .. code-block:: bash
  703. # Used for ESXi host connection information
  704. salt '*' vsphere.syslog_service_reload my.esxi.host root bad-password
  705. # Used for connecting to a vCenter Server
  706. salt '*' vsphere.syslog_service_reload my.vcenter.location root bad-password \
  707. esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
  708. '''
  709. cmd = 'system syslog reload'
  710. ret = {}
  711. if esxi_hosts:
  712. if not isinstance(esxi_hosts, list):
  713. raise CommandExecutionError('\'esxi_hosts\' must be a list.')
  714. for esxi_host in esxi_hosts:
  715. response = salt.utils.vmware.esxcli(host, username, password, cmd,
  716. protocol=protocol, port=port,
  717. esxi_host=esxi_host, credstore=credstore)
  718. ret.update({esxi_host: response})
  719. else:
  720. # Handles a single host or a vCenter connection when no esxi_hosts are provided.
  721. response = salt.utils.vmware.esxcli(host, username, password, cmd,
  722. protocol=protocol, port=port,
  723. credstore=credstore)
  724. ret.update({host: response})
  725. return ret
  726. @depends(HAS_ESX_CLI)
  727. def set_syslog_config(host,
  728. username,
  729. password,
  730. syslog_config,
  731. config_value,
  732. protocol=None,
  733. port=None,
  734. firewall=True,
  735. reset_service=True,
  736. esxi_hosts=None,
  737. credstore=None):
  738. '''
  739. Set the specified syslog configuration parameter. By default, this function will
  740. reset the syslog service after the configuration is set.
  741. host
  742. ESXi or vCenter host to connect to.
  743. username
  744. User to connect as, usually root.
  745. password
  746. Password to connect with.
  747. syslog_config
  748. Name of parameter to set (corresponds to the command line switch for
  749. esxcli without the double dashes (--))
  750. Valid syslog_config values are ``logdir``, ``loghost``, ``default-rotate`,
  751. ``default-size``, ``default-timeout``, and ``logdir-unique``.
  752. config_value
  753. Value for the above parameter. For ``loghost``, URLs or IP addresses to
  754. use for logging. Multiple log servers can be specified by listing them,
  755. comma-separated, but without spaces before or after commas.
  756. (reference: https://blogs.vmware.com/vsphere/2012/04/configuring-multiple-syslog-servers-for-esxi-5.html)
  757. protocol
  758. Optionally set to alternate protocol if the host is not using the default
  759. protocol. Default protocol is ``https``.
  760. port
  761. Optionally set to alternate port if the host is not using the default
  762. port. Default port is ``443``.
  763. firewall
  764. Enable the firewall rule set for syslog. Defaults to ``True``.
  765. reset_service
  766. After a successful parameter set, reset the service. Defaults to ``True``.
  767. esxi_hosts
  768. If ``host`` is a vCenter host, then use esxi_hosts to execute this function
  769. on a list of one or more ESXi machines.
  770. credstore
  771. Optionally set to path to the credential store file.
  772. :return: Dictionary with a top-level key of 'success' which indicates
  773. if all the parameters were reset, and individual keys
  774. for each parameter indicating which succeeded or failed, per host.
  775. CLI Example:
  776. .. code-block:: bash
  777. # Used for ESXi host connection information
  778. salt '*' vsphere.set_syslog_config my.esxi.host root bad-password \
  779. loghost ssl://localhost:5432,tcp://10.1.0.1:1514
  780. # Used for connecting to a vCenter Server
  781. salt '*' vsphere.set_syslog_config my.vcenter.location root bad-password \
  782. loghost ssl://localhost:5432,tcp://10.1.0.1:1514 \
  783. esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
  784. '''
  785. ret = {}
  786. # First, enable the syslog firewall ruleset, for each host, if needed.
  787. if firewall and syslog_config == 'loghost':
  788. if esxi_hosts:
  789. if not isinstance(esxi_hosts, list):
  790. raise CommandExecutionError('\'esxi_hosts\' must be a list.')
  791. for esxi_host in esxi_hosts:
  792. response = enable_firewall_ruleset(host, username, password,
  793. ruleset_enable=True, ruleset_name='syslog',
  794. protocol=protocol, port=port,
  795. esxi_hosts=[esxi_host], credstore=credstore).get(esxi_host)
  796. if response['retcode'] != 0:
  797. ret.update({esxi_host: {'enable_firewall': {'message': response['stdout'],
  798. 'success': False}}})
  799. else:
  800. ret.update({esxi_host: {'enable_firewall': {'success': True}}})
  801. else:
  802. # Handles a single host or a vCenter connection when no esxi_hosts are provided.
  803. response = enable_firewall_ruleset(host, username, password,
  804. ruleset_enable=True, ruleset_name='syslog',
  805. protocol=protocol, port=port,
  806. credstore=credstore).get(host)
  807. if response['retcode'] != 0:
  808. ret.update({host: {'enable_firewall': {'message': response['stdout'],
  809. 'success': False}}})
  810. else:
  811. ret.update({host: {'enable_firewall': {'success': True}}})
  812. # Set the config value on each esxi_host, if provided.
  813. if esxi_hosts:
  814. if not isinstance(esxi_hosts, list):
  815. raise CommandExecutionError('\'esxi_hosts\' must be a list.')
  816. for esxi_host in esxi_hosts:
  817. response = _set_syslog_config_helper(host, username, password, syslog_config,
  818. config_value, protocol=protocol, port=port,
  819. reset_service=reset_service, esxi_host=esxi_host,
  820. credstore=credstore)
  821. # Ensure we don't overwrite any dictionary data already set
  822. # By updating the esxi_host directly.
  823. if ret.get(esxi_host) is None:
  824. ret.update({esxi_host: {}})
  825. ret[esxi_host].update(response)
  826. else:
  827. # Handles a single host or a vCenter connection when no esxi_hosts are provided.
  828. response = _set_syslog_config_helper(host, username, password, syslog_config,
  829. config_value, protocol=protocol, port=port,
  830. reset_service=reset_service, credstore=credstore)
  831. # Ensure we don't overwrite any dictionary data already set
  832. # By updating the host directly.
  833. if ret.get(host) is None:
  834. ret.update({host: {}})
  835. ret[host].update(response)
  836. return ret
  837. @depends(HAS_ESX_CLI)
  838. def get_syslog_config(host, username, password, protocol=None, port=None, esxi_hosts=None, credstore=None):
  839. '''
  840. Retrieve the syslog configuration.
  841. host
  842. The location of the host.
  843. username
  844. The username used to login to the host, such as ``root``.
  845. password
  846. The password used to login to the host.
  847. protocol
  848. Optionally set to alternate protocol if the host is not using the default
  849. protocol. Default protocol is ``https``.
  850. port
  851. Optionally set to alternate port if the host is not using the default
  852. port. Default port is ``443``.
  853. esxi_hosts
  854. If ``host`` is a vCenter host, then use esxi_hosts to execute this function
  855. on a list of one or more ESXi machines.
  856. credstore
  857. Optionally set to path to the credential store file.
  858. :return: Dictionary with keys and values corresponding to the
  859. syslog configuration, per host.
  860. CLI Example:
  861. .. code-block:: bash
  862. # Used for ESXi host connection information
  863. salt '*' vsphere.get_syslog_config my.esxi.host root bad-password
  864. # Used for connecting to a vCenter Server
  865. salt '*' vsphere.get_syslog_config my.vcenter.location root bad-password \
  866. esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
  867. '''
  868. cmd = 'system syslog config get'
  869. ret = {}
  870. if esxi_hosts:
  871. if not isinstance(esxi_hosts, list):
  872. raise CommandExecutionError('\'esxi_hosts\' must be a list.')
  873. for esxi_host in esxi_hosts:
  874. response = salt.utils.vmware.esxcli(host, username, password, cmd,
  875. protocol=protocol, port=port,
  876. esxi_host=esxi_host, credstore=credstore)
  877. # format the response stdout into something useful
  878. ret.update({esxi_host: _format_syslog_config(response)})
  879. else:
  880. # Handles a single host or a vCenter connection when no esxi_hosts are provided.
  881. response = salt.utils.vmware.esxcli(host, username, password, cmd,
  882. protocol=protocol, port=port,
  883. credstore=credstore)
  884. # format the response stdout into something useful
  885. ret.update({host: _format_syslog_config(response)})
  886. return ret
  887. @depends(HAS_ESX_CLI)
  888. def reset_syslog_config(host,
  889. username,
  890. password,
  891. protocol=None,
  892. port=None,
  893. syslog_config=None,
  894. esxi_hosts=None,
  895. credstore=None):
  896. '''
  897. Reset the syslog service to its default settings.
  898. Valid syslog_config values are ``logdir``, ``loghost``, ``logdir-unique``,
  899. ``default-rotate``, ``default-size``, ``default-timeout``,
  900. or ``all`` for all of these.
  901. host
  902. The location of the host.
  903. username
  904. The username used to login to the host, such as ``root``.
  905. password
  906. The password used to login to the host.
  907. protocol
  908. Optionally set to alternate protocol if the host is not using the default
  909. protocol. Default protocol is ``https``.
  910. port
  911. Optionally set to alternate port if the host is not using the default
  912. port. Default port is ``443``.
  913. syslog_config
  914. List of parameters to reset, provided as a comma-delimited string, or 'all' to
  915. reset all syslog configuration parameters. Required.
  916. esxi_hosts
  917. If ``host`` is a vCenter host, then use esxi_hosts to execute this function
  918. on a list of one or more ESXi machines.
  919. credstore
  920. Optionally set to path to the credential store file.
  921. :return: Dictionary with a top-level key of 'success' which indicates
  922. if all the parameters were reset, and individual keys
  923. for each parameter indicating which succeeded or failed, per host.
  924. CLI Example:
  925. ``syslog_config`` can be passed as a quoted, comma-separated string, e.g.
  926. .. code-block:: bash
  927. # Used for ESXi host connection information
  928. salt '*' vsphere.reset_syslog_config my.esxi.host root bad-password \
  929. syslog_config='logdir,loghost'
  930. # Used for connecting to a vCenter Server
  931. salt '*' vsphere.reset_syslog_config my.vcenter.location root bad-password \
  932. syslog_config='logdir,loghost' esxi_hosts='[esxi-1.host.com, esxi-2.host.com]'
  933. '''
  934. if not syslog_config:
  935. raise CommandExecutionError('The \'reset_syslog_config\' function requires a '
  936. '\'syslog_config\' setting.')
  937. valid_resets = ['logdir', 'loghost', 'default-rotate',
  938. 'default-size', 'default-timeout', 'logdir-unique']
  939. cmd = 'system syslog config set --reset='
  940. if ',' in syslog_config:
  941. resets = [ind_reset.strip() for ind_reset in syslog_config.split(',')]
  942. elif syslog_config == 'all':
  943. resets = valid_resets
  944. else:
  945. resets = [syslog_config]
  946. ret = {}
  947. if esxi_hosts:
  948. if not isinstance(esxi_hosts, list):
  949. raise CommandExecutionError('\'esxi_hosts\' must be a list.')
  950. for esxi_host in esxi_hosts:
  951. response_dict = _reset_syslog_config_params(host, username, password,
  952. cmd, resets, valid_resets,
  953. protocol=protocol, port=port,
  954. esxi_host=esxi_host, credstore=credstore)
  955. ret.update({esxi_host: response_dict})
  956. else:
  957. # Handles a single host or a vCenter connection when no esxi_hosts are provided.
  958. response_dict = _reset_syslog_config_params(host, username, password,
  959. cmd, resets, valid_resets,
  960. protocol=protocol, port=port,
  961. credstore=credstore)
  962. ret.update({host: response_dict})
  963. return ret
  964. @ignores_kwargs('credstore')
  965. def upload_ssh_key(host, username, password, ssh_key=None, ssh_key_file=None,
  966. protocol=None, port=None, certificate_verify=False):
  967. '''
  968. Upload an ssh key for root to an ESXi host via http PUT.
  969. This function only works for ESXi, not vCenter.
  970. Only one ssh key can be uploaded for root. Uploading a second key will
  971. replace any existing key.
  972. :param host: The location of the ESXi Host
  973. :param username: Username to connect as
  974. :param password: Password for the ESXi web endpoint
  975. :param ssh_key: Public SSH key, will be added to authorized_keys on ESXi
  976. :param ssh_key_file: File containing the SSH key. Use 'ssh_key' or
  977. ssh_key_file, but not both.
  978. :param protocol: defaults to https, can be http if ssl is disabled on ESXi
  979. :param port: defaults to 443 for https
  980. :param certificate_verify: If true require that the SSL connection present
  981. a valid certificate
  982. :return: Dictionary with a 'status' key, True if upload is successful.
  983. If upload is unsuccessful, 'status' key will be False and
  984. an 'Error' key will have an informative message.
  985. CLI Example:
  986. .. code-block:: bash
  987. salt '*' vsphere.upload_ssh_key my.esxi.host root bad-password ssh_key_file='/etc/salt/my_keys/my_key.pub'
  988. '''
  989. if protocol is None:
  990. protocol = 'https'
  991. if port is None:
  992. port = 443
  993. url = '{0}://{1}:{2}/host/ssh_root_authorized_keys'.format(protocol,
  994. host,
  995. port)
  996. ret = {}
  997. result = None
  998. try:
  999. if ssh_key:
  1000. result = salt.utils.http.query(url,
  1001. status=True,
  1002. text=True,
  1003. method='PUT',
  1004. username=username,
  1005. password=password,
  1006. data=ssh_key,
  1007. verify_ssl=certificate_verify)
  1008. elif ssh_key_file:
  1009. result = salt.utils.http.query(url,
  1010. status=True,
  1011. text=True,
  1012. method='PUT',
  1013. username=username,
  1014. password=password,
  1015. data_file=ssh_key_file,
  1016. data_render=False,
  1017. verify_ssl=certificate_verify)
  1018. if result.get('status') == 200:
  1019. ret['status'] = True
  1020. else:
  1021. ret['status'] = False
  1022. ret['Error'] = result['error']
  1023. except Exception as msg:
  1024. ret['status'] = False
  1025. ret['Error'] = msg
  1026. return ret
  1027. @ignores_kwargs('credstore')
  1028. def get_ssh_key(host,
  1029. username,
  1030. password,
  1031. protocol=None,
  1032. port=None,
  1033. certificate_verify=False):
  1034. '''
  1035. Retrieve the authorized_keys entry for root.
  1036. This function only works for ESXi, not vCenter.
  1037. :param host: The location of the ESXi Host
  1038. :param username: Username to connect as
  1039. :param password: Password for the ESXi web endpoint
  1040. :param protocol: defaults to https, can be http if ssl is disabled on ESXi
  1041. :param port: defaults to 443 for https
  1042. :param certificate_verify: If true require that the SSL connection present
  1043. a valid certificate
  1044. :return: True if upload is successful
  1045. CLI Example:
  1046. .. code-block:: bash
  1047. salt '*' vsphere.get_ssh_key my.esxi.host root bad-password certificate_verify=True
  1048. '''
  1049. if protocol is None:
  1050. protocol = 'https'
  1051. if port is None:
  1052. port = 443
  1053. url = '{0}://{1}:{2}/host/ssh_root_authorized_keys'.format(protocol,
  1054. host,
  1055. port)
  1056. ret = {}
  1057. try:
  1058. result = salt.utils.http.query(url,
  1059. status=True,
  1060. text=True,
  1061. method='GET',
  1062. username=username,
  1063. password=password,
  1064. verify_ssl=certificate_verify)
  1065. if result.get('status') == 200:
  1066. ret['status'] = True
  1067. ret['key'] = result['text']
  1068. else:
  1069. ret['status'] = False
  1070. ret['Error'] = result['error']
  1071. except Exception as msg:
  1072. ret['status'] = False
  1073. ret['Error'] = msg
  1074. return ret
  1075. @depends(HAS_PYVMOMI)
  1076. @ignores_kwargs('credstore')
  1077. def get_host_datetime(host, username, password, protocol=None, port=None, host_names=None):
  1078. '''
  1079. Get the date/time information for a given host or list of host_names.
  1080. host
  1081. The location of the host.
  1082. username
  1083. The username used to login to the host, such as ``root``.
  1084. password
  1085. The password used to login to the host.
  1086. protocol
  1087. Optionally set to alternate protocol if the host is not using the default
  1088. protocol. Default protocol is ``https``.
  1089. port
  1090. Optionally set to alternate port if the host is not using the default
  1091. port. Default port is ``443``.
  1092. host_names
  1093. List of ESXi host names. When the host, username, and password credentials
  1094. are provided for a vCenter Server, the host_names argument is required to tell
  1095. vCenter the hosts for which to get date/time information.
  1096. If host_names is not provided, the date/time information will be retrieved for the
  1097. ``host`` location instead. This is useful for when service instance connection
  1098. information is used for a single ESXi host.
  1099. CLI Example:
  1100. .. code-block:: bash
  1101. # Used for single ESXi host connection information
  1102. salt '*' vsphere.get_host_datetime my.esxi.host root bad-password
  1103. # Used for connecting to a vCenter Server
  1104. salt '*' vsphere.get_host_datetime my.vcenter.location root bad-password \
  1105. host_names='[esxi-1.host.com, esxi-2.host.com]'
  1106. '''
  1107. service_instance = salt.utils.vmware.get_service_instance(host=host,
  1108. username=username,
  1109. password=password,
  1110. protocol=protocol,
  1111. port=port)
  1112. host_names = _check_hosts(service_instance, host, host_names)
  1113. ret = {}
  1114. for host_name in host_names:
  1115. host_ref = _get_host_ref(service_instance, host, host_name=host_name)
  1116. date_time_manager = _get_date_time_mgr(host_ref)
  1117. date_time = date_time_manager.QueryDateTime()
  1118. ret.update({host_name: date_time})
  1119. return ret
  1120. @depends(HAS_PYVMOMI)
  1121. @ignores_kwargs('credstore')
  1122. def get_ntp_config(host, username, password, protocol=None, port=None, host_names=None):
  1123. '''
  1124. Get the NTP configuration information for a given host or list of host_names.
  1125. host
  1126. The location of the host.
  1127. username
  1128. The username used to login to the host, such as ``root``.
  1129. password
  1130. The password used to login to the host.
  1131. protocol
  1132. Optionally set to alternate protocol if the host is not using the default
  1133. protocol. Default protocol is ``https``.
  1134. port
  1135. Optionally set to alternate port if the host is not using the default
  1136. port. Default port is ``443``.
  1137. host_names
  1138. List of ESXi host names. When the host, username, and password credentials
  1139. are provided for a vCenter Server, the host_names argument is required to tell
  1140. vCenter the hosts for which to get ntp configuration information.
  1141. If host_names is not provided, the NTP configuration will be retrieved for the
  1142. ``host`` location instead. This is useful for when service instance connection
  1143. information is used for a single ESXi host.
  1144. CLI Example:
  1145. .. code-block:: bash
  1146. # Used for single ESXi host connection information
  1147. salt '*' vsphere.get_ntp_config my.esxi.host root bad-password
  1148. # Used for connecting to a vCenter Server
  1149. salt '*' vsphere.get_ntp_config my.vcenter.location root bad-password \
  1150. host_names='[esxi-1.host.com, esxi-2.host.com]'
  1151. '''
  1152. service_instance = salt.utils.vmware.get_service_instance(host=host,
  1153. username=username,
  1154. password=password,
  1155. protocol=protocol,
  1156. port=port)
  1157. host_names = _check_hosts(service_instance, host, host_names)
  1158. ret = {}
  1159. for host_name in host_names:
  1160. host_ref = _get_host_ref(service_instance, host, host_name=host_name)
  1161. ntp_config = host_ref.configManager.dateTimeSystem.dateTimeInfo.ntpConfig.server
  1162. ret.update({host_name: ntp_config})
  1163. return ret
  1164. @depends(HAS_PYVMOMI)
  1165. @ignores_kwargs('credstore')
  1166. def get_service_policy(host, username, password, service_name, protocol=None, port=None, host_names=None):
  1167. '''
  1168. Get the service name's policy for a given host or list of hosts.
  1169. host
  1170. The location of the host.
  1171. username
  1172. The username used to login to the host, such as ``root``.
  1173. password
  1174. The password used to login to the host.
  1175. service_name
  1176. The name of the service for which to retrieve the policy. Supported service names are:
  1177. - DCUI
  1178. - TSM
  1179. - SSH
  1180. - lbtd
  1181. - lsassd
  1182. - lwiod
  1183. - netlogond
  1184. - ntpd
  1185. - sfcbd-watchdog
  1186. - snmpd
  1187. - vprobed
  1188. - vpxa
  1189. - xorg
  1190. protocol
  1191. Optionally set to alternate protocol if the host is not using the default
  1192. protocol. Default protocol is ``https``.
  1193. port
  1194. Optionally set to alternate port if the host is not using the default
  1195. port. Default port is ``443``.
  1196. host_names
  1197. List of ESXi host names. When the host, username, and password credentials
  1198. are provided for a vCenter Server, the host_names argument is required to tell
  1199. vCenter the hosts for which to get service policy information.
  1200. If host_names is not provided, the service policy information will be retrieved
  1201. for the ``host`` location instead. This is useful for when service instance
  1202. connection information is used for a single ESXi host.
  1203. CLI Example:
  1204. .. code-block:: bash
  1205. # Used for single ESXi host connection information
  1206. salt '*' vsphere.get_service_policy my.esxi.host root bad-password 'ssh'
  1207. # Used for connecting to a vCenter Server
  1208. salt '*' vsphere.get_service_policy my.vcenter.location root bad-password 'ntpd' \
  1209. host_names='[esxi-1.host.com, esxi-2.host.com]'
  1210. '''
  1211. service_instance = salt.utils.vmware.get_service_instance(host=host,
  1212. username=username,
  1213. password=password,
  1214. protocol=protocol,
  1215. port=port)
  1216. valid_services = ['DCUI', 'TSM', 'SSH', 'ssh', 'lbtd', 'lsassd', 'lwiod', 'netlogond',
  1217. 'ntpd', 'sfcbd-watchdog', 'snmpd', 'vprobed', 'vpxa', 'xorg']
  1218. host_names = _check_hosts(service_instance, host, host_names)
  1219. ret = {}
  1220. for host_name in host_names:
  1221. # Check if the service_name provided is a valid one.
  1222. # If we don't have a valid service, return. The service will be invalid for all hosts.
  1223. if service_name not in valid_services:
  1224. ret.update({host_name: {'Error': '{0} is not a valid service name.'.format(service_name)}})
  1225. return ret
  1226. host_ref = _get_host_ref(service_instance, host, host_name=host_name)
  1227. services = host_ref.configManager.serviceSystem.serviceInfo.service
  1228. # Don't require users to know that VMware lists the ssh service as TSM-SSH
  1229. if service_name == 'SSH' or service_name == 'ssh':
  1230. temp_service_name = 'TSM-SSH'
  1231. else:
  1232. temp_service_name = service_name
  1233. # Loop through services until we find a matching name
  1234. for service in services:
  1235. if service.key == temp_service_name:
  1236. ret.update({host_name:
  1237. {service_name: service.policy}})
  1238. # We've found a match - break out of the loop so we don't overwrite the
  1239. # Updated host_name value with an error message.
  1240. break
  1241. else:
  1242. msg = 'Could not find service \'{0}\' for host \'{1}\'.'.format(service_name,
  1243. host_name)
  1244. ret.update({host_name: {'Error': msg}})
  1245. # If we made it this far, something else has gone wrong.
  1246. if ret.get(host_name) is None:
  1247. msg = '\'vsphere.get_service_policy\' failed for host {0}.'.format(host_name)
  1248. log.debug(msg)
  1249. ret.update({host_name: {'Error': msg}})
  1250. return ret
  1251. @depends(HAS_PYVMOMI)
  1252. @ignores_kwargs('credstore')
  1253. def get_service_running(host, username, password, service_name, protocol=None, port=None, host_names=None):
  1254. '''
  1255. Get the service name's running state for a given host or list of hosts.
  1256. host
  1257. The location of the host.
  1258. username
  1259. The username used to login to the host, such as ``root``.
  1260. password
  1261. The password used to login to the host.
  1262. service_name
  1263. The name of the service for which to retrieve the policy. Supported service names are:
  1264. - DCUI
  1265. - TSM
  1266. - SSH
  1267. - lbtd
  1268. - lsassd
  1269. - lwiod
  1270. - netlogond
  1271. - ntpd
  1272. - sfcbd-watchdog
  1273. - snmpd
  1274. - vprobed
  1275. - vpxa
  1276. - xorg
  1277. protocol
  1278. Optionally set to alternate protocol if the host is not using the default
  1279. protocol. Default protocol is ``https``.
  1280. port
  1281. Optionally set to alternate port if the host is not using the default
  1282. port. Default port is ``443``.
  1283. host_names
  1284. List of ESXi host names. When the host, username, and password credentials
  1285. are provided for a vCenter Server, the host_names argument is required to tell
  1286. vCenter the hosts for which to get the service's running state.
  1287. If host_names is not provided, the service's running state will be retrieved
  1288. for the ``host`` location instead. This is useful for when service instance
  1289. connection information is used for a single ESXi host.
  1290. CLI Example:
  1291. .. code-block:: bash
  1292. # Used for single ESXi host connection information
  1293. salt '*' vsphere.get_service_running my.esxi.host root bad-password 'ssh'
  1294. # Used for connecting to a vCenter Server
  1295. salt '*' vsphere.get_service_running my.vcenter.location root bad-password 'ntpd' \
  1296. host_names='[esxi-1.host.com, esxi-2.host.com]'
  1297. '''
  1298. service_instance = salt.utils.vmware.get_service_instance(host=host,
  1299. username=username,
  1300. password=password,
  1301. protocol=protocol,
  1302. port=port)
  1303. valid_services = ['DCUI', 'TSM', 'SSH', 'ssh', 'lbtd', 'lsassd', 'lwiod', 'netlogond',
  1304. 'ntpd', 'sfcbd-watchdog', 'snmpd', 'vprobed', 'vpxa', 'xorg']
  1305. host_names = _check_hosts(service_instance, host, host_names)
  1306. ret = {}
  1307. for host_name in host_names:
  1308. # Check if the service_name provided is a valid one.
  1309. # If we don't have a valid service, return. The service will be invalid for all hosts.
  1310. if service_name not in valid_services:
  1311. ret.update({host_name: {'Error': '{0} is not a valid service name.'.format(service_name)}})
  1312. return ret
  1313. host_ref = _get_host_ref(service_instance, host, host_name=host_name)
  1314. services = host_ref.configManager.serviceSystem.serviceInfo.service
  1315. # Don't require users to know that VMware lists the ssh service as TSM-SSH
  1316. if service_name == 'SSH' or service_name == 'ssh':
  1317. temp_service_name = 'TSM-SSH'
  1318. else:
  1319. temp_service_name = service_name
  1320. # Loop through services until we find a matching name
  1321. for service in services:
  1322. if service.key == temp_service_name:
  1323. ret.update({host_name:
  1324. {service_name: service.running}})
  1325. # We've found a match - break out of the loop so we don't overwrite the
  1326. # Updated host_name value with an error message.
  1327. break
  1328. else:
  1329. msg = 'Could not find service \'{0}\' for host \'{1}\'.'.format(service_name,
  1330. host_name)
  1331. ret.update({host_name: {'Error': msg}})
  1332. # If we made it this far, something else has gone wrong.
  1333. if ret.get(host_name) is None:
  1334. msg = '\'vsphere.get_service_running\' failed for host {0}.'.format(host_name)
  1335. log.debug(msg)
  1336. ret.update({host_name: {'Error': msg}})
  1337. return ret
  1338. @depends(HAS_PYVMOMI)
  1339. @ignores_kwargs('credstore')
  1340. def get_vmotion_enabled(host, username, password, protocol=None, port=None, host_names=None):
  1341. '''
  1342. Get the VMotion enabled status for a given host or a list of host_names. Returns ``True``
  1343. if VMotion is enabled, ``False`` if it is not enabled.
  1344. host
  1345. The location of the host.
  1346. username
  1347. The username used to login to the host, such as ``root``.
  1348. password
  1349. The password used to login to the host.
  1350. protocol
  1351. Optionally set to alternate protocol if the host is not using the default
  1352. protocol. Default protocol is ``https``.
  1353. port
  1354. Optionally set to alternate port if the host is not using the default
  1355. port. Default port is ``443``.
  1356. host_names
  1357. List of ESXi host names. When the host, username, and password credentials
  1358. are provided for a vCenter Server, the host_names argument is required to
  1359. tell vCenter which hosts to check if VMotion is enabled.
  1360. If host_names is not provided, the VMotion status will be retrieved for the
  1361. ``host`` location instead. This is useful for when service instance
  1362. connection information is used for a single ESXi host.
  1363. CLI Example:
  1364. .. code-block:: bash
  1365. # Used for single ESXi host connection information
  1366. salt '*' vsphere.get_vmotion_enabled my.esxi.host root bad-password
  1367. # Used for connecting to a vCenter Server
  1368. salt '*' vsphere.get_vmotion_enabled my.vcenter.location root bad-password \
  1369. host_names='[esxi-1.host.com, esxi-2.host.com]'
  1370. '''
  1371. service_instance = salt.utils.vmware.get_service_instance(host=host,
  1372. username=username,
  1373. password=password,
  1374. protocol=protocol,
  1375. port=port)
  1376. host_names = _check_hosts(service_instance, host, host_names)
  1377. ret = {}
  1378. for host_name in host_names:
  1379. host_ref = _get_host_ref(service_instance, host, host_name=host_name)
  1380. vmotion_vnic = host_ref.configManager.vmotionSystem.netConfig.selectedVnic
  1381. if vmotion_vnic:
  1382. ret.update({host_name: {'VMotion Enabled': True}})
  1383. else:
  1384. ret.update({host_name: {'VMotion Enabled': False}})
  1385. return ret
  1386. @depends(HAS_PYVMOMI)
  1387. @ignores_kwargs('credstore')
  1388. def get_vsan_enabled(host, username, password, protocol=None, port=None, host_names=None):
  1389. '''
  1390. Get the VSAN enabled status for a given host or a list of host_names. Returns ``True``
  1391. if VSAN is enabled, ``False`` if it is not enabled, and ``None`` if a VSAN Host Config
  1392. is unset, per host.
  1393. host
  1394. The location of the host.
  1395. username
  1396. The username used to login to the host, such as ``root``.
  1397. password
  1398. The password used to login to the host.
  1399. protocol
  1400. Optionally set to alternate protocol if the host is not using the default
  1401. protocol. Default protocol is ``https``.
  1402. port
  1403. Optionally set to alternate port if the host is not using the default
  1404. port. Default port is ``443``.
  1405. host_names
  1406. List of ESXi host names. When the host, username, and password credentials
  1407. are provided for a vCenter Server, the host_names argument is required to
  1408. tell vCenter which hosts to check if VSAN enabled.
  1409. If host_names is not provided, the VSAN status will be retrieved for the
  1410. ``host`` location instead. This is useful for when service instance
  1411. connection information is used for a single ESXi host.
  1412. CLI Example:
  1413. .. code-block:: bash
  1414. # Used for single ESXi host connection information
  1415. salt '*' vsphere.get_vsan_enabled my.esxi.host root bad-password
  1416. # Used for connecting to a vCenter Server
  1417. salt '*' vsphere.get_vsan_enabled my.vcenter.location root bad-password \
  1418. host_names='[esxi-1.host.com, esxi-2.host.com]'
  1419. '''
  1420. service_instance = salt.utils.vmware.get_service_instance(host=host,
  1421. username=username,
  1422. password=password,
  1423. protocol=protocol,
  1424. port=port)
  1425. host_names = _check_hosts(service_instance, host, host_names)
  1426. ret = {}
  1427. for host_name in host_names:
  1428. host_ref = _get_host_ref(service_instance, host, host_name=host_name)
  1429. vsan_config = host_ref.config.vsanHostConfig
  1430. # We must have a VSAN Config in place get information about VSAN state.
  1431. if vsan_config is None:
  1432. msg = 'VSAN System Config Manager is unset for host \'{0}\'.'.format(host_name)
  1433. log.debug(msg)
  1434. ret.update({host_name: {'Error': msg}})
  1435. else:
  1436. ret.update({host_name: {'VSAN Enabled': vsan_config.enabled}})
  1437. return ret
  1438. @depends(HAS_PYVMOMI)
  1439. @ignores_kwargs('credstore')
  1440. def get_vsan_eligible_disks(host, username, password, protocol=None, port=None, host_names=None):
  1441. '''
  1442. Returns a list of VSAN-eligible disks for a given host or list of host_names.
  1443. host
  1444. The location of the host.
  1445. username
  1446. The username used to login to the host, such as ``root``.
  1447. password
  1448. The password used to login to the host.
  1449. protocol
  1450. Optionally set to alternate protocol if the host is not using the default
  1451. protocol. Default protocol is ``https``.
  1452. port
  1453. Optionally set to alternate port if the host is not using the default
  1454. port. Default port is ``443``.
  1455. host_names
  1456. List of ESXi host names. When the host, username, and password credentials
  1457. are provided for a vCenter Server, the host_names argument is required to
  1458. tell vCenter which hosts to check if any VSAN-eligible disks are available.
  1459. If host_names is not provided, the VSAN-eligible disks will be retrieved
  1460. for the ``host`` location instead. This is useful for when service instance
  1461. connection information is used for a single ESXi host.
  1462. CLI Example:
  1463. .. code-block:: bash
  1464. # Used for single ESXi host connection information
  1465. salt '*' vsphere.get_vsan_eligible_disks my.esxi.host root bad-password
  1466. # Used for connecting to a vCenter Server
  1467. salt '*' vsphere.get_vsan_eligible_disks my.vcenter.location root bad-password \
  1468. host_names='[esxi-1.host.com, esxi-2.host.com]'
  1469. '''
  1470. service_instance = salt.utils.vmware.get_service_instance(host=host,
  1471. username=username,
  1472. password=password,
  1473. protocol=protocol,
  1474. port=port)
  1475. host_names = _check_hosts(service_instance, host, host_names)
  1476. response = _get_vsan_eligible_disks(service_instance, host, host_names)
  1477. ret = {}
  1478. for host_name, value in six.iteritems(response):
  1479. error = value.get('Error')
  1480. if error:
  1481. ret.update({host_name: {'Error': error}})
  1482. continue
  1483. disks = value.get('Eligible')
  1484. # If we have eligible disks, it will be a list of disk objects
  1485. if disks and isinstance(disks, list):
  1486. disk_names = []
  1487. # We need to return ONLY the disk names, otherwise
  1488. # MessagePack can't deserialize the disk objects.
  1489. for disk in disks:
  1490. disk_names.append(disk.canonicalName)
  1491. ret.update({host_name: {'Eligible': disk_names}})
  1492. else:
  1493. # If we have disks, but it's not a list, it's actually a
  1494. # string message that we're passing along.
  1495. ret.update({host_name: {'Eligible': disks}})
  1496. return ret
  1497. @depends(HAS_PYVMOMI)
  1498. @supports_proxies('esxi')
  1499. @gets_service_instance_via_proxy
  1500. def test_vcenter_connection(service_instance=None):
  1501. '''
  1502. Checks if a connection is to a vCenter
  1503. CLI Example:
  1504. .. code-block:: bash
  1505. salt '*' vsphere.test_vcenter_connection
  1506. '''
  1507. try:
  1508. if salt.utils.vmware.is_connection_to_a_vcenter(service_instance):
  1509. return True
  1510. except VMwareSaltError:
  1511. return False
  1512. return False
  1513. @depends(HAS_PYVMOMI)
  1514. @ignores_kwargs('credstore')
  1515. def system_info(host, username, password, protocol=None, port=None):
  1516. '''
  1517. Return system information about a VMware environment.
  1518. host
  1519. The location of the host.
  1520. username
  1521. The username used to login to the host, such as ``root``.
  1522. password
  1523. The password used to login to the host.
  1524. protocol
  1525. Optionally set to alternate protocol if the host is not using the default
  1526. protocol. Default protocol is ``https``.
  1527. port
  1528. Optionally set to alternate port if the host is not using the default
  1529. port. Default port is ``443``.
  1530. CLI Example:
  1531. .. code-block:: bash
  1532. salt '*' vsphere.system_info 1.2.3.4 root bad-password
  1533. '''
  1534. service_instance = salt.utils.vmware.get_service_instance(host=host,
  1535. username=username,
  1536. password=password,
  1537. protocol=protocol,
  1538. port=port)
  1539. ret = salt.utils.vmware.get_inventory(service_instance).about.__dict__
  1540. if 'apiType' in ret:
  1541. if ret['apiType'] == 'HostAgent':
  1542. ret = dictupdate.update(ret, salt.utils.vmware.get_hardware_grains(service_instance))
  1543. return ret
  1544. @depends(HAS_PYVMOMI)
  1545. @ignores_kwargs('credstore')
  1546. def list_datacenters(host, username, password, protocol=None, port=None):
  1547. '''
  1548. Returns a list of datacenters for the the specified host.
  1549. host
  1550. The location of the host.
  1551. username
  1552. The username used to login to the host, such as ``root``.
  1553. password
  1554. The password used to login to the host.
  1555. protocol
  1556. Optionally set to alternate protocol if the host is not using the default
  1557. protocol. Default protocol is ``https``.
  1558. port
  1559. Optionally set to alternate port if the host is not using the default
  1560. port. Default port is ``443``.
  1561. CLI Example:
  1562. .. code-block:: bash
  1563. salt '*' vsphere.list_datacenters 1.2.3.4 root bad-password
  1564. '''
  1565. service_instance = salt.utils.vmware.get_service_instance(host=host,
  1566. username=username,
  1567. password=password,
  1568. protocol=protocol,
  1569. port=port)
  1570. return salt.utils.vmware.list_datacenters(service_instance)
  1571. @depends(HAS_PYVMOMI)
  1572. @ignores_kwargs('credstore')
  1573. def list_clusters(host, username, password, protocol=None, port=None):
  1574. '''
  1575. Returns a list of clusters for the the specified host.
  1576. host
  1577. The location of the host.
  1578. username
  1579. The username used to login to the host, such as ``root``.
  1580. password
  1581. The password used to login to the host.
  1582. protocol
  1583. Optionally set to alternate protocol if the host is not using the default
  1584. protocol. Default protocol is ``https``.
  1585. port
  1586. Optionally set to alternate port if the host is not using the default
  1587. port. Default port is ``443``.
  1588. CLI Example:
  1589. .. code-block:: bash
  1590. salt '*' vsphere.list_clusters 1.2.3.4 root bad-password
  1591. '''
  1592. service_instance = salt.utils.vmware.get_service_instance(host=host,
  1593. username=username,
  1594. password=password,
  1595. protocol=protocol,
  1596. port=port)
  1597. return salt.utils.vmware.list_clusters(service_instance)
  1598. @depends(HAS_PYVMOMI)
  1599. @ignores_kwargs('credstore')
  1600. def list_datastore_clusters(host, username, password, protocol=None, port=None):
  1601. '''
  1602. Returns a list of datastore clusters for the the specified host.
  1603. host
  1604. The location of the host.
  1605. username
  1606. The username used to login to the host, such as ``root``.
  1607. password
  1608. The password used to login to the host.
  1609. protocol
  1610. Optionally set to alternate protocol if the host is not using the default
  1611. protocol. Default protocol is ``https``.
  1612. port
  1613. Optionally set to alternate port if the host is not using the default
  1614. port. Default port is ``443``.
  1615. CLI Example:
  1616. .. code-block:: bash
  1617. salt '*' vsphere.list_datastore_clusters 1.2.3.4 root bad-password
  1618. '''
  1619. service_instance = salt.utils.vmware.get_service_instance(host=host,
  1620. username=username,
  1621. password=password,
  1622. protocol=protocol,
  1623. port=port)
  1624. return salt.utils.vmware.list_datastore_clusters(service_instance)
  1625. @depends(HAS_PYVMOMI)
  1626. @ignores_kwargs('credstore')
  1627. def list_datastores(host, username, password, protocol=None, port=None):
  1628. '''
  1629. Returns a list of datastores for the the specified host.
  1630. host
  1631. The location of the host.
  1632. username
  1633. The username used to login to the host, such as ``root``.
  1634. password
  1635. The password used to login to the host.
  1636. protocol
  1637. Optionally set to alternate protocol if the host is not using the default
  1638. protocol. Default protocol is ``https``.
  1639. port
  1640. Optionally set to alternate port if the host is not using the default
  1641. port. Default port is ``443``.
  1642. CLI Example:
  1643. .. code-block:: bash
  1644. salt '*' vsphere.list_datastores 1.2.3.4 root bad-password
  1645. '''
  1646. service_instance = salt.utils.vmware.get_service_instance(host=host,
  1647. username=username,
  1648. password=password,
  1649. protocol=protocol,
  1650. port=port)
  1651. return salt.utils.vmware.list_datastores(service_instance)
  1652. @depends(HAS_PYVMOMI)
  1653. @ignores_kwargs('credstore')
  1654. def list_hosts(host, username, password, protocol=None, port=None):
  1655. '''
  1656. Returns a list of hosts for the the specified VMware environment.
  1657. host
  1658. The location of the host.
  1659. username
  1660. The username used to login to the host, such as ``root``.
  1661. password
  1662. The password used to login to the host.
  1663. protocol
  1664. Optionally set to alternate protocol if the host is not using the default
  1665. protocol. Default protocol is ``https``.
  1666. port
  1667. Optionally set to alternate port if the host is not using the default
  1668. port. Default port is ``443``.
  1669. CLI Example:
  1670. .. code-block:: bash
  1671. salt '*' vsphere.list_hosts 1.2.3.4 root bad-password
  1672. '''
  1673. service_instance = salt.utils.vmware.get_service_instance(host=host,
  1674. username=username,
  1675. password=password,
  1676. protocol=protocol,
  1677. port=port)
  1678. return salt.utils.vmware.list_hosts(service_instance)
  1679. @depends(HAS_PYVMOMI)
  1680. @ignores_kwargs('credstore')
  1681. def list_resourcepools(host, username, password, protocol=None, port=None):
  1682. '''
  1683. Returns a list of resource pools for the the specified host.
  1684. host
  1685. The location of the host.
  1686. username
  1687. The username used to login to the host, such as ``root``.
  1688. password
  1689. The password used to login to the host.
  1690. protocol
  1691. Optionally set to alternate protocol if the host is not using the default
  1692. protocol. Default protocol is ``https``.
  1693. port
  1694. Optionally set to alternate port if the host is not using the default
  1695. port. Default port is ``443``.
  1696. CLI Example:
  1697. .. code-block:: bash
  1698. salt '*' vsphere.list_resourcepools 1.2.3.4 root bad-password
  1699. '''
  1700. service_instance = salt.utils.vmware.get_service_instance(host=host,
  1701. username=username,
  1702. password=password,
  1703. protocol=protocol,
  1704. port=port)
  1705. return salt.utils.vmware.list_resourcepools(service_instance)
  1706. @depends(HAS_PYVMOMI)
  1707. @ignores_kwargs('credstore')
  1708. def list_networks(host, username, password, protocol=None, port=None):
  1709. '''
  1710. Returns a list of networks for the the specified host.
  1711. host
  1712. The location of the host.
  1713. username
  1714. The username used to login to the host, such as ``root``.
  1715. password
  1716. The password used to login to the host.
  1717. protocol
  1718. Optionally set to alternate protocol if the host is not using the default
  1719. protocol. Default protocol is ``https``.
  1720. port
  1721. Optionally set to alternate port if the host is not using the default
  1722. port. Default port is ``443``.
  1723. CLI Example:
  1724. .. code-block:: bash
  1725. salt '*' vsphere.list_networks 1.2.3.4 root bad-password
  1726. '''
  1727. service_instance = salt.utils.vmware.get_service_instance(host=host,
  1728. username=username,
  1729. password=password,
  1730. protocol=protocol,
  1731. port=port)
  1732. return salt.utils.vmware.list_networks(service_instance)
  1733. @depends(HAS_PYVMOMI)
  1734. @ignores_kwargs('credstore')
  1735. def list_vms(host, username, password, protocol=None, port=None):
  1736. '''
  1737. Returns a list of VMs for the the specified host.
  1738. host
  1739. The location of the host.
  1740. username
  1741. The username used to login to the host, such as ``root``.
  1742. password
  1743. The password used to login to the host.
  1744. protocol
  1745. Optionally set to alternate protocol if the host is not using the default
  1746. protocol. Default protocol is ``https``.
  1747. port
  1748. Optionally set to alternate port if the host is not using the default
  1749. port. Default port is ``443``.
  1750. CLI Example:
  1751. .. code-block:: bash
  1752. salt '*' vsphere.list_vms 1.2.3.4 root bad-password
  1753. '''
  1754. service_instance = salt.utils.vmware.get_service_instance(host=host,
  1755. username=username,
  1756. password=password,
  1757. protocol=protocol,
  1758. port=port)
  1759. return salt.utils.vmware.list_vms(service_instance)
  1760. @depends(HAS_PYVMOMI)
  1761. @ignores_kwargs('credstore')
  1762. def list_folders(host, username, password, protocol=None, port=None):
  1763. '''
  1764. Returns a list of folders for the the specified host.
  1765. host
  1766. The location of the host.
  1767. username
  1768. The username used to login to the host, such as ``root``.
  1769. password
  1770. The password used to login to the host.
  1771. protocol
  1772. Optionally set to alternate protocol if the host is not using the default
  1773. protocol. Default protocol is ``https``.
  1774. port
  1775. Optionally set to alternate port if the host is not using the default
  1776. port. Default port is ``443``.
  1777. CLI Example:
  1778. .. code-block:: bash
  1779. salt '*' vsphere.list_folders 1.2.3.4 root bad-password
  1780. '''
  1781. service_instance = salt.utils.vmware.get_service_instance(host=host,
  1782. username=username,
  1783. password=password,
  1784. protocol=protocol,
  1785. port=port)
  1786. return salt.utils.vmware.list_folders(service_instance)
  1787. @depends(HAS_PYVMOMI)
  1788. @ignores_kwargs('credstore')
  1789. def list_dvs(host, username, password, protocol=None, port=None):
  1790. '''
  1791. Returns a list of distributed virtual switches for the the specified host.
  1792. host
  1793. The location of the host.
  1794. username
  1795. The username used to login to the host, such as ``root``.
  1796. password
  1797. The password used to login to the host.
  1798. protocol
  1799. Optionally set to alternate protocol if the host is not using the default
  1800. protocol. Default protocol is ``https``.
  1801. port
  1802. Optionally set to alternate port if the host is not using the default
  1803. port. Default port is ``443``.
  1804. CLI Example:
  1805. .. code-block:: bash
  1806. salt '*' vsphere.list_dvs 1.2.3.4 root bad-password
  1807. '''
  1808. service_instance = salt.utils.vmware.get_service_instance(host=host,
  1809. username=username,
  1810. password=password,
  1811. protocol=protocol,
  1812. port=port)
  1813. return salt.utils.vmware.list_dvs(service_instance)
  1814. @depends(HAS_PYVMOMI)
  1815. @ignores_kwargs('credstore')
  1816. def list_vapps(host, username, password, protocol=None, port=None):
  1817. '''
  1818. Returns a list of vApps for the the specified host.
  1819. host
  1820. The location of the host.
  1821. username
  1822. The username used to login to the host, such as ``root``.
  1823. password
  1824. The password used to login to the host.
  1825. protocol
  1826. Optionally set to alternate protocol if the host is not using the default
  1827. protocol. Default protocol is ``https``.
  1828. port
  1829. Optionally set to alternate port if the host is not using the default
  1830. port. Default port is ``443``.
  1831. CLI Example:
  1832. .. code-block:: bash
  1833. # List vapps from all minions
  1834. salt '*' vsphere.list_vapps 1.2.3.4 root bad-password
  1835. '''
  1836. service_instance = salt.utils.vmware.get_service_instance(host=host,
  1837. username=username,
  1838. password=password,
  1839. protocol=protocol,
  1840. port=port)
  1841. return salt.utils.vmware.list_vapps(service_instance)
  1842. @depends(HAS_PYVMOMI)
  1843. @ignores_kwargs('credstore')
  1844. def list_ssds(host, username, password, protocol=None, port=None, host_names=None):
  1845. '''
  1846. Returns a list of SSDs for the given host or list of host_names.
  1847. host
  1848. The location of the host.
  1849. username
  1850. The username used to login to the host, such as ``root``.
  1851. password
  1852. The password used to login to the host.
  1853. protocol
  1854. Optionally set to alternate protocol if the host is not using the default
  1855. protocol. Default protocol is ``https``.
  1856. port
  1857. Optionally set to alternate port if the host is not using the default
  1858. port. Default port is ``443``.
  1859. host_names
  1860. List of ESXi host names. When the host, username, and password credentials
  1861. are provided for a vCenter Server, the host_names argument is required to
  1862. tell vCenter the hosts for which to retrieve SSDs.
  1863. If host_names is not provided, SSDs will be retrieved for the
  1864. ``host`` location instead. This is useful for when service instance
  1865. connection information is used for a single ESXi host.
  1866. CLI Example:
  1867. .. code-block:: bash
  1868. # Used for single ESXi host connection information
  1869. salt '*' vsphere.list_ssds my.esxi.host root bad-password
  1870. # Used for connecting to a vCenter Server
  1871. salt '*' vsphere.list_ssds my.vcenter.location root bad-password \
  1872. host_names='[esxi-1.host.com, esxi-2.host.com]'
  1873. '''
  1874. service_instance = salt.utils.vmware.get_service_instance(host=host,
  1875. username=username,
  1876. password=password,
  1877. protocol=protocol,
  1878. port=port)
  1879. host_names = _check_hosts(service_instance, host, host_names)
  1880. ret = {}
  1881. names = []
  1882. for host_name in host_names:
  1883. host_ref = _get_host_ref(service_instance, host, host_name=host_name)
  1884. disks = _get_host_ssds(host_ref)
  1885. for disk in disks:
  1886. names.append(disk.canonicalName)
  1887. ret.update({host_name: names})
  1888. return ret
  1889. @depends(HAS_PYVMOMI)
  1890. @ignores_kwargs('credstore')
  1891. def list_non_ssds(host, username, password, protocol=None, port=None, host_names=None):
  1892. '''
  1893. Returns a list of Non-SSD disks for the given host or list of host_names.
  1894. .. note::
  1895. In the pyVmomi StorageSystem, ScsiDisks may, or may not have an ``ssd`` attribute.
  1896. This attribute indicates if the ScsiDisk is SSD backed. As this option is optional,
  1897. if a relevant disk in the StorageSystem does not have ``ssd = true``, it will end
  1898. up in the ``non_ssds`` list here.
  1899. host
  1900. The location of the host.
  1901. username
  1902. The username used to login to the host, such as ``root``.
  1903. password
  1904. The password used to login to the host.
  1905. protocol
  1906. Optionally set to alternate protocol if the host is not using the default
  1907. protocol. Default protocol is ``https``.
  1908. port
  1909. Optionally set to alternate port if the host is not using the default
  1910. port. Default port is ``443``.
  1911. host_names
  1912. List of ESXi host names. When the host, username, and password credentials
  1913. are provided for a vCenter Server, the host_names argument is required to
  1914. tell vCenter the hosts for which to retrieve Non-SSD disks.
  1915. If host_names is not provided, Non-SSD disks will be retrieved for the
  1916. ``host`` location instead. This is useful for when service instance
  1917. connection information is used for a single ESXi host.
  1918. CLI Example:
  1919. .. code-block:: bash
  1920. # Used for single ESXi host connection information
  1921. salt '*' vsphere.list_non_ssds my.esxi.host root bad-password
  1922. # Used for connecting to a vCenter Server
  1923. salt '*' vsphere.list_non_ssds my.vcenter.location root bad-password \
  1924. host_names='[esxi-1.host.com, esxi-2.host.com]'
  1925. '''
  1926. service_instance = salt.utils.vmware.get_service_instance(host=host,
  1927. username=username,
  1928. password=password,
  1929. protocol=protocol,
  1930. port=port)
  1931. host_names = _check_hosts(service_instance, host, host_names)
  1932. ret = {}
  1933. names = []
  1934. for host_name in host_names:
  1935. host_ref = _get_host_ref(service_instance, host, host_name=host_name)
  1936. disks = _get_host_non_ssds(host_ref)
  1937. for disk in disks:
  1938. names.append(disk.canonicalName)
  1939. ret.update({host_name: names})
  1940. return ret
  1941. @depends(HAS_PYVMOMI)
  1942. @ignores_kwargs('credstore')
  1943. def set_ntp_config(host, username, password, ntp_servers, protocol=None, port=None, host_names=None):
  1944. '''
  1945. Set NTP configuration for a given host of list of host_names.
  1946. host
  1947. The location of the host.
  1948. username
  1949. The username used to login to the host, such as ``root``.
  1950. password
  1951. The password used to login to the host.
  1952. ntp_servers
  1953. A list of servers that should be added to and configured for the specified
  1954. host's NTP configuration.
  1955. protocol
  1956. Optionally set to alternate protocol if the host is not using the default
  1957. protocol. Default protocol is ``https``.
  1958. port
  1959. Optionally set to alternate port if the host is not using the default
  1960. port. Default port is ``443``.
  1961. host_names
  1962. List of ESXi host names. When the host, username, and password credentials
  1963. are provided for a vCenter Server, the host_names argument is required to tell
  1964. vCenter which hosts to configure ntp servers.
  1965. If host_names is not provided, the NTP servers will be configured for the
  1966. ``host`` location instead. This is useful for when service instance connection
  1967. information is used for a single ESXi host.
  1968. CLI Example:
  1969. .. code-block:: bash
  1970. # Used for single ESXi host connection information
  1971. salt '*' vsphere.ntp_configure my.esxi.host root bad-password '[192.174.1.100, 192.174.1.200]'
  1972. # Used for connecting to a vCenter Server
  1973. salt '*' vsphere.ntp_configure my.vcenter.location root bad-password '[192.174.1.100, 192.174.1.200]' \
  1974. host_names='[esxi-1.host.com, esxi-2.host.com]'
  1975. '''
  1976. service_instance = salt.utils.vmware.get_service_instance(host=host,
  1977. username=username,
  1978. password=password,
  1979. protocol=protocol,
  1980. port=port)
  1981. if not isinstance(ntp_servers, list):
  1982. raise CommandExecutionError('\'ntp_servers\' must be a list.')
  1983. # Get NTP Config Object from ntp_servers
  1984. ntp_config = vim.HostNtpConfig(server=ntp_servers)
  1985. # Get DateTimeConfig object from ntp_config
  1986. date_config = vim.HostDateTimeConfig(ntpConfig=ntp_config)
  1987. host_names = _check_hosts(service_instance, host, host_names)
  1988. ret = {}
  1989. for host_name in host_names:
  1990. host_ref = _get_host_ref(service_instance, host, host_name=host_name)
  1991. date_time_manager = _get_date_time_mgr(host_ref)
  1992. log.debug('Configuring NTP Servers \'{0}\' for host \'{1}\'.'.format(ntp_servers, host_name))
  1993. try:
  1994. date_time_manager.UpdateDateTimeConfig(config=date_config)
  1995. except vim.fault.HostConfigFault as err:
  1996. msg = 'vsphere.ntp_configure_servers failed: {0}'.format(err)
  1997. log.debug(msg)
  1998. ret.update({host_name: {'Error': msg}})
  1999. continue
  2000. ret.update({host_name: {'NTP Servers': ntp_config}})
  2001. return ret
  2002. @depends(HAS_PYVMOMI)
  2003. @ignores_kwargs('credstore')
  2004. def service_start(host,
  2005. username,
  2006. password,
  2007. service_name,
  2008. protocol=None,
  2009. port=None,
  2010. host_names=None):
  2011. '''
  2012. Start the named service for the given host or list of hosts.
  2013. host
  2014. The location of the host.
  2015. username
  2016. The username used to login to the host, such as ``root``.
  2017. password
  2018. The password used to login to the host.
  2019. service_name
  2020. The name of the service for which to set the policy. Supported service names are:
  2021. - DCUI
  2022. - TSM
  2023. - SSH
  2024. - lbtd
  2025. - lsassd
  2026. - lwiod
  2027. - netlogond
  2028. - ntpd
  2029. - sfcbd-watchdog
  2030. - snmpd
  2031. - vprobed
  2032. - vpxa
  2033. - xorg
  2034. protocol
  2035. Optionally set to alternate protocol if the host is not using the default
  2036. protocol. Default protocol is ``https``.
  2037. port
  2038. Optionally set to alternate port if the host is not using the default
  2039. port. Default port is ``443``.
  2040. host_names
  2041. List of ESXi host names. When the host, username, and password credentials
  2042. are provided for a vCenter Server, the host_names argument is required to tell
  2043. vCenter the hosts for which to start the service.
  2044. If host_names is not provided, the service will be started for the ``host``
  2045. location instead. This is useful for when service instance connection information
  2046. is used for a single ESXi host.
  2047. CLI Example:
  2048. .. code-block:: bash
  2049. # Used for single ESXi host connection information
  2050. salt '*' vsphere.service_start my.esxi.host root bad-password 'ntpd'
  2051. # Used for connecting to a vCenter Server
  2052. salt '*' vsphere.service_start my.vcenter.location root bad-password 'ntpd' \
  2053. host_names='[esxi-1.host.com, esxi-2.host.com]'
  2054. '''
  2055. service_instance = salt.utils.vmware.get_service_instance(host=host,
  2056. username=username,
  2057. password=password,
  2058. protocol=protocol,
  2059. port=port)
  2060. host_names = _check_hosts(service_instance, host, host_names)
  2061. valid_services = ['DCUI', 'TSM', 'SSH', 'ssh', 'lbtd', 'lsassd', 'lwiod', 'netlogond',
  2062. 'ntpd', 'sfcbd-watchdog', 'snmpd', 'vprobed', 'vpxa', 'xorg']
  2063. ret = {}
  2064. # Don't require users to know that VMware lists the ssh service as TSM-SSH
  2065. if service_name == 'SSH' or service_name == 'ssh':
  2066. temp_service_name = 'TSM-SSH'
  2067. else:
  2068. temp_service_name = service_name
  2069. for host_name in host_names:
  2070. # Check if the service_name provided is a valid one.
  2071. # If we don't have a valid service, return. The service will be invalid for all hosts.
  2072. if service_name not in valid_services:
  2073. ret.update({host_name: {'Error': '{0} is not a valid service name.'.format(service_name)}})
  2074. return ret
  2075. host_ref = _get_host_ref(service_instance, host, host_name=host_name)
  2076. service_manager = _get_service_manager(host_ref)
  2077. log.debug('Starting the \'{0}\' service on {1}.'.format(service_name, host_name))
  2078. # Start the service
  2079. try:
  2080. service_manager.StartService(id=temp_service_name)
  2081. except vim.fault.HostConfigFault as err:
  2082. msg = '\'vsphere.service_start\' failed for host {0}: {1}'.format(host_name, err)
  2083. log.debug(msg)
  2084. ret.update({host_name: {'Error': msg}})
  2085. continue
  2086. # Some services are restricted by the vSphere License Level.
  2087. except vim.fault.RestrictedVersion as err:
  2088. log.debug(err)
  2089. ret.update({host_name: {'Error': err}})
  2090. continue
  2091. ret.update({host_name: {'Service Started': True}})
  2092. return ret
  2093. @depends(HAS_PYVMOMI)
  2094. @ignores_kwargs('credstore')
  2095. def service_stop(host,
  2096. username,
  2097. password,
  2098. service_name,
  2099. protocol=None,
  2100. port=None,
  2101. host_names=None):
  2102. '''
  2103. Stop the named service for the given host or list of hosts.
  2104. host
  2105. The location of the host.
  2106. username
  2107. The username used to login to the host, such as ``root``.
  2108. password
  2109. The password used to login to the host.
  2110. service_name
  2111. The name of the service for which to set the policy. Supported service names are:
  2112. - DCUI
  2113. - TSM
  2114. - SSH
  2115. - lbtd
  2116. - lsassd
  2117. - lwiod
  2118. - netlogond
  2119. - ntpd
  2120. - sfcbd-watchdog
  2121. - snmpd
  2122. - vprobed
  2123. - vpxa
  2124. - xorg
  2125. protocol
  2126. Optionally set to alternate protocol if the host is not using the default
  2127. protocol. Default protocol is ``https``.
  2128. port
  2129. Optionally set to alternate port if the host is not using the default
  2130. port. Default port is ``443``.
  2131. host_names
  2132. List of ESXi host names. When the host, username, and password credentials
  2133. are provided for a vCenter Server, the host_names argument is required to tell
  2134. vCenter the hosts for which to stop the service.
  2135. If host_names is not provided, the service will be stopped for the ``host``
  2136. location instead. This is useful for when service instance connection information
  2137. is used for a single ESXi host.
  2138. CLI Example:
  2139. .. code-block:: bash
  2140. # Used for single ESXi host connection information
  2141. salt '*' vsphere.service_stop my.esxi.host root bad-password 'ssh'
  2142. # Used for connecting to a vCenter Server
  2143. salt '*' vsphere.service_stop my.vcenter.location root bad-password 'ssh' \
  2144. host_names='[esxi-1.host.com, esxi-2.host.com]'
  2145. '''
  2146. service_instance = salt.utils.vmware.get_service_instance(host=host,
  2147. username=username,
  2148. password=password,
  2149. protocol=protocol,
  2150. port=port)
  2151. host_names = _check_hosts(service_instance, host, host_names)
  2152. valid_services = ['DCUI', 'TSM', 'SSH', 'ssh', 'lbtd', 'lsassd', 'lwiod', 'netlogond',
  2153. 'ntpd', 'sfcbd-watchdog', 'snmpd', 'vprobed', 'vpxa', 'xorg']
  2154. ret = {}
  2155. # Don't require users to know that VMware lists the ssh service as TSM-SSH
  2156. if service_name == 'SSH' or service_name == 'ssh':
  2157. temp_service_name = 'TSM-SSH'
  2158. else:
  2159. temp_service_name = service_name
  2160. for host_name in host_names:
  2161. # Check if the service_name provided is a valid one.
  2162. # If we don't have a valid service, return. The service will be invalid for all hosts.
  2163. if service_name not in valid_services:
  2164. ret.update({host_name: {'Error': '{0} is not a valid service name.'.format(service_name)}})
  2165. return ret
  2166. host_ref = _get_host_ref(service_instance, host, host_name=host_name)
  2167. service_manager = _get_service_manager(host_ref)
  2168. log.debug('Stopping the \'{0}\' service on {1}.'.format(service_name, host_name))
  2169. # Stop the service.
  2170. try:
  2171. service_manager.StopService(id=temp_service_name)
  2172. except vim.fault.HostConfigFault as err:
  2173. msg = '\'vsphere.service_stop\' failed for host {0}: {1}'.format(host_name, err)
  2174. log.debug(msg)
  2175. ret.update({host_name: {'Error': msg}})
  2176. continue
  2177. # Some services are restricted by the vSphere License Level.
  2178. except vim.fault.RestrictedVersion as err:
  2179. log.debug(err)
  2180. ret.update({host_name: {'Error': err}})
  2181. continue
  2182. ret.update({host_name: {'Service Stopped': True}})
  2183. return ret
  2184. @depends(HAS_PYVMOMI)
  2185. @ignores_kwargs('credstore')
  2186. def service_restart(host,
  2187. username,
  2188. password,
  2189. service_name,
  2190. protocol=None,
  2191. port=None,
  2192. host_names=None):
  2193. '''
  2194. Restart the named service for the given host or list of hosts.
  2195. host
  2196. The location of the host.
  2197. username
  2198. The username used to login to the host, such as ``root``.
  2199. password
  2200. The password used to login to the host.
  2201. service_name
  2202. The name of the service for which to set the policy. Supported service names are:
  2203. - DCUI
  2204. - TSM
  2205. - SSH
  2206. - lbtd
  2207. - lsassd
  2208. - lwiod
  2209. - netlogond
  2210. - ntpd
  2211. - sfcbd-watchdog
  2212. - snmpd
  2213. - vprobed
  2214. - vpxa
  2215. - xorg
  2216. protocol
  2217. Optionally set to alternate protocol if the host is not using the default
  2218. protocol. Default protocol is ``https``.
  2219. port
  2220. Optionally set to alternate port if the host is not using the default
  2221. port. Default port is ``443``.
  2222. host_names
  2223. List of ESXi host names. When the host, username, and password credentials
  2224. are provided for a vCenter Server, the host_names argument is required to tell
  2225. vCenter the hosts for which to restart the service.
  2226. If host_names is not provided, the service will be restarted for the ``host``
  2227. location instead. This is useful for when service instance connection information
  2228. is used for a single ESXi host.
  2229. CLI Example:
  2230. .. code-block:: bash
  2231. # Used for single ESXi host connection information
  2232. salt '*' vsphere.service_restart my.esxi.host root bad-password 'ntpd'
  2233. # Used for connecting to a vCenter Server
  2234. salt '*' vsphere.service_restart my.vcenter.location root bad-password 'ntpd' \
  2235. host_names='[esxi-1.host.com, esxi-2.host.com]'
  2236. '''
  2237. service_instance = salt.utils.vmware.get_service_instance(host=host,
  2238. username=username,
  2239. password=password,
  2240. protocol=protocol,
  2241. port=port)
  2242. host_names = _check_hosts(service_instance, host, host_names)
  2243. valid_services = ['DCUI', 'TSM', 'SSH', 'ssh', 'lbtd', 'lsassd', 'lwiod', 'netlogond',
  2244. 'ntpd', 'sfcbd-watchdog', 'snmpd', 'vprobed', 'vpxa', 'xorg']
  2245. ret = {}
  2246. # Don't require users to know that VMware lists the ssh service as TSM-SSH
  2247. if service_name == 'SSH' or service_name == 'ssh':
  2248. temp_service_name = 'TSM-SSH'
  2249. else:
  2250. temp_service_name = service_name
  2251. for host_name in host_names:
  2252. # Check if the service_name provided is a valid one.
  2253. # If we don't have a valid service, return. The service will be invalid for all hosts.
  2254. if service_name not in valid_services:
  2255. ret.update({host_name: {'Error': '{0} is not a valid service name.'.format(service_name)}})
  2256. return ret
  2257. host_ref = _get_host_ref(service_instance, host, host_name=host_name)
  2258. service_manager = _get_service_manager(host_ref)
  2259. log.debug('Restarting the \'{0}\' service on {1}.'.format(service_name, host_name))
  2260. # Restart the service.
  2261. try:
  2262. service_manager.RestartService(id=temp_service_name)
  2263. except vim.fault.HostConfigFault as err:
  2264. msg = '\'vsphere.service_restart\' failed for host {0}: {1}'.format(host_name, err)
  2265. log.debug(msg)
  2266. ret.update({host_name: {'Error': msg}})
  2267. continue
  2268. # Some services are restricted by the vSphere License Level.
  2269. except vim.fault.RestrictedVersion as err:
  2270. log.debug(err)
  2271. ret.update({host_name: {'Error': err}})
  2272. continue
  2273. ret.update({host_name: {'Service Restarted': True}})
  2274. return ret
  2275. @depends(HAS_PYVMOMI)
  2276. @ignores_kwargs('credstore')
  2277. def set_service_policy(host,
  2278. username,
  2279. password,
  2280. service_name,
  2281. service_policy,
  2282. protocol=None,
  2283. port=None,
  2284. host_names=None):
  2285. '''
  2286. Set the service name's policy for a given host or list of hosts.
  2287. host
  2288. The location of the host.
  2289. username
  2290. The username used to login to the host, such as ``root``.
  2291. password
  2292. The password used to login to the host.
  2293. service_name
  2294. The name of the service for which to set the policy. Supported service names are:
  2295. - DCUI
  2296. - TSM
  2297. - SSH
  2298. - lbtd
  2299. - lsassd
  2300. - lwiod
  2301. - netlogond
  2302. - ntpd
  2303. - sfcbd-watchdog
  2304. - snmpd
  2305. - vprobed
  2306. - vpxa
  2307. - xorg
  2308. service_policy
  2309. The policy to set for the service. For example, 'automatic'.
  2310. protocol
  2311. Optionally set to alternate protocol if the host is not using the default
  2312. protocol. Default protocol is ``https``.
  2313. port
  2314. Optionally set to alternate port if the host is not using the default
  2315. port. Default port is ``443``.
  2316. host_names
  2317. List of ESXi host names. When the host, username, and password credentials
  2318. are provided for a vCenter Server, the host_names argument is required to tell
  2319. vCenter the hosts for which to set the service policy.
  2320. If host_names is not provided, the service policy information will be retrieved
  2321. for the ``host`` location instead. This is useful for when service instance
  2322. connection information is used for a single ESXi host.
  2323. CLI Example:
  2324. .. code-block:: bash
  2325. # Used for single ESXi host connection information
  2326. salt '*' vsphere.set_service_policy my.esxi.host root bad-password 'ntpd' 'automatic'
  2327. # Used for connecting to a vCenter Server
  2328. salt '*' vsphere.set_service_policy my.vcenter.location root bad-password 'ntpd' 'automatic' \
  2329. host_names='[esxi-1.host.com, esxi-2.host.com]'
  2330. '''
  2331. service_instance = salt.utils.vmware.get_service_instance(host=host,
  2332. username=username,
  2333. password=password,
  2334. protocol=protocol,
  2335. port=port)
  2336. host_names = _check_hosts(service_instance, host, host_names)
  2337. valid_services = ['DCUI', 'TSM', 'SSH', 'ssh', 'lbtd', 'lsassd', 'lwiod', 'netlogond',
  2338. 'ntpd', 'sfcbd-watchdog', 'snmpd', 'vprobed', 'vpxa', 'xorg']
  2339. ret = {}
  2340. for host_name in host_names:
  2341. # Check if the service_name provided is a valid one.
  2342. # If we don't have a valid service, return. The service will be invalid for all hosts.
  2343. if service_name not in valid_services:
  2344. ret.update({host_name: {'Error': '{0} is not a valid service name.'.format(service_name)}})
  2345. return ret
  2346. host_ref = _get_host_ref(service_instance, host, host_name=host_name)
  2347. service_manager = _get_service_manager(host_ref)
  2348. services = host_ref.configManager.serviceSystem.serviceInfo.service
  2349. # Services are stored in a general list - we need loop through the list and find
  2350. # service key that matches our service name.
  2351. for service in services:
  2352. service_key = None
  2353. # Find the service key based on the given service_name
  2354. if service.key == service_name:
  2355. service_key = service.key
  2356. elif service_name == 'ssh' or service_name == 'SSH':
  2357. if service.key == 'TSM-SSH':
  2358. service_key = 'TSM-SSH'
  2359. # If we have a service_key, we've found a match. Update the policy.
  2360. if service_key:
  2361. try:
  2362. service_manager.UpdateServicePolicy(id=service_key, policy=service_policy)
  2363. except vim.fault.NotFound:
  2364. msg = 'The service name \'{0}\' was not found.'.format(service_name)
  2365. log.debug(msg)
  2366. ret.update({host_name: {'Error': msg}})
  2367. continue
  2368. # Some services are restricted by the vSphere License Level.
  2369. except vim.fault.HostConfigFault as err:
  2370. msg = '\'vsphere.set_service_policy\' failed for host {0}: {1}'.format(host_name, err)
  2371. log.debug(msg)
  2372. ret.update({host_name: {'Error': msg}})
  2373. continue
  2374. ret.update({host_name: True})
  2375. # If we made it this far, something else has gone wrong.
  2376. if ret.get(host_name) is None:
  2377. msg = 'Could not find service \'{0}\' for host \'{1}\'.'.format(service_name, host_name)
  2378. log.debug(msg)
  2379. ret.update({host_name: {'Error': msg}})
  2380. return ret
  2381. @depends(HAS_PYVMOMI)
  2382. @ignores_kwargs('credstore')
  2383. def update_host_datetime(host, username, password, protocol=None, port=None, host_names=None):
  2384. '''
  2385. Update the date/time on the given host or list of host_names. This function should be
  2386. used with caution since network delays and execution delays can result in time skews.
  2387. host
  2388. The location of the host.
  2389. username
  2390. The username used to login to the host, such as ``root``.
  2391. password
  2392. The password used to login to the host.
  2393. protocol
  2394. Optionally set to alternate protocol if the host is not using the default
  2395. protocol. Default protocol is ``https``.
  2396. port
  2397. Optionally set to alternate port if the host is not using the default
  2398. port. Default port is ``443``.
  2399. host_names
  2400. List of ESXi host names. When the host, username, and password credentials
  2401. are provided for a vCenter Server, the host_names argument is required to
  2402. tell vCenter which hosts should update their date/time.
  2403. If host_names is not provided, the date/time will be updated for the ``host``
  2404. location instead. This is useful for when service instance connection
  2405. information is used for a single ESXi host.
  2406. CLI Example:
  2407. .. code-block:: bash
  2408. # Used for single ESXi host connection information
  2409. salt '*' vsphere.update_date_time my.esxi.host root bad-password
  2410. # Used for connecting to a vCenter Server
  2411. salt '*' vsphere.update_date_time my.vcenter.location root bad-password \
  2412. host_names='[esxi-1.host.com, esxi-2.host.com]'
  2413. '''
  2414. service_instance = salt.utils.vmware.get_service_instance(host=host,
  2415. username=username,
  2416. password=password,
  2417. protocol=protocol,
  2418. port=port)
  2419. host_names = _check_hosts(service_instance, host, host_names)
  2420. ret = {}
  2421. for host_name in host_names:
  2422. host_ref = _get_host_ref(service_instance, host, host_name=host_name)
  2423. date_time_manager = _get_date_time_mgr(host_ref)
  2424. try:
  2425. date_time_manager.UpdateDateTime(datetime.datetime.utcnow())
  2426. except vim.fault.HostConfigFault as err:
  2427. msg = '\'vsphere.update_date_time\' failed for host {0}: {1}'.format(host_name, err)
  2428. log.debug(msg)
  2429. ret.update({host_name: {'Error': msg}})
  2430. continue
  2431. ret.update({host_name: {'Datetime Updated': True}})
  2432. return ret
  2433. @depends(HAS_PYVMOMI)
  2434. @ignores_kwargs('credstore')
  2435. def update_host_password(host, username, password, new_password, protocol=None, port=None):
  2436. '''
  2437. Update the password for a given host.
  2438. .. note:: Currently only works with connections to ESXi hosts. Does not work with vCenter servers.
  2439. host
  2440. The location of the ESXi host.
  2441. username
  2442. The username used to login to the ESXi host, such as ``root``.
  2443. password
  2444. The password used to login to the ESXi host.
  2445. new_password
  2446. The new password that will be updated for the provided username on the ESXi host.
  2447. protocol
  2448. Optionally set to alternate protocol if the host is not using the default
  2449. protocol. Default protocol is ``https``.
  2450. port
  2451. Optionally set to alternate port if the host is not using the default
  2452. port. Default port is ``443``.
  2453. CLI Example:
  2454. .. code-block:: bash
  2455. salt '*' vsphere.update_host_password my.esxi.host root original-bad-password new-bad-password
  2456. '''
  2457. service_instance = salt.utils.vmware.get_service_instance(host=host,
  2458. username=username,
  2459. password=password,
  2460. protocol=protocol,
  2461. port=port)
  2462. # Get LocalAccountManager object
  2463. account_manager = salt.utils.vmware.get_inventory(service_instance).accountManager
  2464. # Create user account specification object and assign id and password attributes
  2465. user_account = vim.host.LocalAccountManager.AccountSpecification()
  2466. user_account.id = username
  2467. user_account.password = new_password
  2468. # Update the password
  2469. try:
  2470. account_manager.UpdateUser(user_account)
  2471. except vmodl.fault.SystemError as err:
  2472. raise CommandExecutionError(err.msg)
  2473. except vim.fault.UserNotFound:
  2474. raise CommandExecutionError('\'vsphere.update_host_password\' failed for host {0}: '
  2475. 'User was not found.'.format(host))
  2476. # If the username and password already exist, we don't need to do anything.
  2477. except vim.fault.AlreadyExists:
  2478. pass
  2479. return True
  2480. @depends(HAS_PYVMOMI)
  2481. @ignores_kwargs('credstore')
  2482. def vmotion_disable(host, username, password, protocol=None, port=None, host_names=None):
  2483. '''
  2484. Disable vMotion for a given host or list of host_names.
  2485. host
  2486. The location of the host.
  2487. username
  2488. The username used to login to the host, such as ``root``.
  2489. password
  2490. The password used to login to the host.
  2491. protocol
  2492. Optionally set to alternate protocol if the host is not using the default
  2493. protocol. Default protocol is ``https``.
  2494. port
  2495. Optionally set to alternate port if the host is not using the default
  2496. port. Default port is ``443``.
  2497. host_names
  2498. List of ESXi host names. When the host, username, and password credentials
  2499. are provided for a vCenter Server, the host_names argument is required to
  2500. tell vCenter which hosts should disable VMotion.
  2501. If host_names is not provided, VMotion will be disabled for the ``host``
  2502. location instead. This is useful for when service instance connection
  2503. information is used for a single ESXi host.
  2504. CLI Example:
  2505. .. code-block:: bash
  2506. # Used for single ESXi host connection information
  2507. salt '*' vsphere.vmotion_disable my.esxi.host root bad-password
  2508. # Used for connecting to a vCenter Server
  2509. salt '*' vsphere.vmotion_disable my.vcenter.location root bad-password \
  2510. host_names='[esxi-1.host.com, esxi-2.host.com]'
  2511. '''
  2512. service_instance = salt.utils.vmware.get_service_instance(host=host,
  2513. username=username,
  2514. password=password,
  2515. protocol=protocol,
  2516. port=port)
  2517. host_names = _check_hosts(service_instance, host, host_names)
  2518. ret = {}
  2519. for host_name in host_names:
  2520. host_ref = _get_host_ref(service_instance, host, host_name=host_name)
  2521. vmotion_system = host_ref.configManager.vmotionSystem
  2522. # Disable VMotion for the host by removing the VNic selected to use for VMotion.
  2523. try:
  2524. vmotion_system.DeselectVnic()
  2525. except vim.fault.HostConfigFault as err:
  2526. msg = 'vsphere.vmotion_disable failed: {0}'.format(err)
  2527. log.debug(msg)
  2528. ret.update({host_name: {'Error': msg,
  2529. 'VMotion Disabled': False}})
  2530. continue
  2531. ret.update({host_name: {'VMotion Disabled': True}})
  2532. return ret
  2533. @depends(HAS_PYVMOMI)
  2534. @ignores_kwargs('credstore')
  2535. def vmotion_enable(host, username, password, protocol=None, port=None, host_names=None, device='vmk0'):
  2536. '''
  2537. Enable vMotion for a given host or list of host_names.
  2538. host
  2539. The location of the host.
  2540. username
  2541. The username used to login to the host, such as ``root``.
  2542. password
  2543. The password used to login to the host.
  2544. protocol
  2545. Optionally set to alternate protocol if the host is not using the default
  2546. protocol. Default protocol is ``https``.
  2547. port
  2548. Optionally set to alternate port if the host is not using the default
  2549. port. Default port is ``443``.
  2550. host_names
  2551. List of ESXi host names. When the host, username, and password credentials
  2552. are provided for a vCenter Server, the host_names argument is required to
  2553. tell vCenter which hosts should enable VMotion.
  2554. If host_names is not provided, VMotion will be enabled for the ``host``
  2555. location instead. This is useful for when service instance connection
  2556. information is used for a single ESXi host.
  2557. device
  2558. The device that uniquely identifies the VirtualNic that will be used for
  2559. VMotion for each host. Defaults to ``vmk0``.
  2560. CLI Example:
  2561. .. code-block:: bash
  2562. # Used for single ESXi host connection information
  2563. salt '*' vsphere.vmotion_enable my.esxi.host root bad-password
  2564. # Used for connecting to a vCenter Server
  2565. salt '*' vsphere.vmotion_enable my.vcenter.location root bad-password \
  2566. host_names='[esxi-1.host.com, esxi-2.host.com]'
  2567. '''
  2568. service_instance = salt.utils.vmware.get_service_instance(host=host,
  2569. username=username,
  2570. password=password,
  2571. protocol=protocol,
  2572. port=port)
  2573. host_names = _check_hosts(service_instance, host, host_names)
  2574. ret = {}
  2575. for host_name in host_names:
  2576. host_ref = _get_host_ref(service_instance, host, host_name=host_name)
  2577. vmotion_system = host_ref.configManager.vmotionSystem
  2578. # Enable VMotion for the host by setting the given device to provide the VNic to use for VMotion.
  2579. try:
  2580. vmotion_system.SelectVnic(device)
  2581. except vim.fault.HostConfigFault as err:
  2582. msg = 'vsphere.vmotion_disable failed: {0}'.format(err)
  2583. log.debug(msg)
  2584. ret.update({host_name: {'Error': msg,
  2585. 'VMotion Enabled': False}})
  2586. continue
  2587. ret.update({host_name: {'VMotion Enabled': True}})
  2588. return ret
  2589. @depends(HAS_PYVMOMI)
  2590. @ignores_kwargs('credstore')
  2591. def vsan_add_disks(host, username, password, protocol=None, port=None, host_names=None):
  2592. '''
  2593. Add any VSAN-eligible disks to the VSAN System for the given host or list of host_names.
  2594. host
  2595. The location of the host.
  2596. username
  2597. The username used to login to the host, such as ``root``.
  2598. password
  2599. The password used to login to the host.
  2600. protocol
  2601. Optionally set to alternate protocol if the host is not using the default
  2602. protocol. Default protocol is ``https``.
  2603. port
  2604. Optionally set to alternate port if the host is not using the default
  2605. port. Default port is ``443``.
  2606. host_names
  2607. List of ESXi host names. When the host, username, and password credentials
  2608. are provided for a vCenter Server, the host_names argument is required to
  2609. tell vCenter which hosts need to add any VSAN-eligible disks to the host's
  2610. VSAN system.
  2611. If host_names is not provided, VSAN-eligible disks will be added to the hosts's
  2612. VSAN system for the ``host`` location instead. This is useful for when service
  2613. instance connection information is used for a single ESXi host.
  2614. CLI Example:
  2615. .. code-block:: bash
  2616. # Used for single ESXi host connection information
  2617. salt '*' vsphere.vsan_add_disks my.esxi.host root bad-password
  2618. # Used for connecting to a vCenter Server
  2619. salt '*' vsphere.vsan_add_disks my.vcenter.location root bad-password \
  2620. host_names='[esxi-1.host.com, esxi-2.host.com]'
  2621. '''
  2622. service_instance = salt.utils.vmware.get_service_instance(host=host,
  2623. username=username,
  2624. password=password,
  2625. protocol=protocol,
  2626. port=port)
  2627. host_names = _check_hosts(service_instance, host, host_names)
  2628. response = _get_vsan_eligible_disks(service_instance, host, host_names)
  2629. ret = {}
  2630. for host_name, value in six.iteritems(response):
  2631. host_ref = _get_host_ref(service_instance, host, host_name=host_name)
  2632. vsan_system = host_ref.configManager.vsanSystem
  2633. # We must have a VSAN Config in place before we can manipulate it.
  2634. if vsan_system is None:
  2635. msg = 'VSAN System Config Manager is unset for host \'{0}\'. ' \
  2636. 'VSAN configuration cannot be changed without a configured ' \
  2637. 'VSAN System.'.format(host_name)
  2638. log.debug(msg)
  2639. ret.update({host_name: {'Error': msg}})
  2640. else:
  2641. eligible = value.get('Eligible')
  2642. error = value.get('Error')
  2643. if eligible and isinstance(eligible, list):
  2644. # If we have eligible, matching disks, add them to VSAN.
  2645. try:
  2646. task = vsan_system.AddDisks(eligible)
  2647. salt.utils.vmware.wait_for_task(task, host_name, 'Adding disks to VSAN', sleep_seconds=3)
  2648. except vim.fault.InsufficientDisks as err:
  2649. log.debug(err.msg)
  2650. ret.update({host_name: {'Error': err.msg}})
  2651. continue
  2652. except Exception as err:
  2653. msg = '\'vsphere.vsan_add_disks\' failed for host {0}: {1}'.format(host_name, err)
  2654. log.debug(msg)
  2655. ret.update({host_name: {'Error': msg}})
  2656. continue
  2657. log.debug('Successfully added disks to the VSAN system for host \'{0}\'.'.format(host_name))
  2658. # We need to return ONLY the disk names, otherwise Message Pack can't deserialize the disk objects.
  2659. disk_names = []
  2660. for disk in eligible:
  2661. disk_names.append(disk.canonicalName)
  2662. ret.update({host_name: {'Disks Added': disk_names}})
  2663. elif eligible and isinstance(eligible, six.string_types):
  2664. # If we have a string type in the eligible value, we don't
  2665. # have any VSAN-eligible disks. Pull the message through.
  2666. ret.update({host_name: {'Disks Added': eligible}})
  2667. elif error:
  2668. # If we hit an error, populate the Error return dict for state functions.
  2669. ret.update({host_name: {'Error': error}})
  2670. else:
  2671. # If we made it this far, we somehow have eligible disks, but they didn't
  2672. # match the disk list and just got an empty list of matching disks.
  2673. ret.update({host_name: {'Disks Added': 'No new VSAN-eligible disks were found to add.'}})
  2674. return ret
  2675. @depends(HAS_PYVMOMI)
  2676. @ignores_kwargs('credstore')
  2677. def vsan_disable(host, username, password, protocol=None, port=None, host_names=None):
  2678. '''
  2679. Disable VSAN for a given host or list of host_names.
  2680. host
  2681. The location of the host.
  2682. username
  2683. The username used to login to the host, such as ``root``.
  2684. password
  2685. The password used to login to the host.
  2686. protocol
  2687. Optionally set to alternate protocol if the host is not using the default
  2688. protocol. Default protocol is ``https``.
  2689. port
  2690. Optionally set to alternate port if the host is not using the default
  2691. port. Default port is ``443``.
  2692. host_names
  2693. List of ESXi host names. When the host, username, and password credentials
  2694. are provided for a vCenter Server, the host_names argument is required to
  2695. tell vCenter which hosts should disable VSAN.
  2696. If host_names is not provided, VSAN will be disabled for the ``host``
  2697. location instead. This is useful for when service instance connection
  2698. information is used for a single ESXi host.
  2699. CLI Example:
  2700. .. code-block:: bash
  2701. # Used for single ESXi host connection information
  2702. salt '*' vsphere.vsan_disable my.esxi.host root bad-password
  2703. # Used for connecting to a vCenter Server
  2704. salt '*' vsphere.vsan_disable my.vcenter.location root bad-password \
  2705. host_names='[esxi-1.host.com, esxi-2.host.com]'
  2706. '''
  2707. service_instance = salt.utils.vmware.get_service_instance(host=host,
  2708. username=username,
  2709. password=password,
  2710. protocol=protocol,
  2711. port=port)
  2712. # Create a VSAN Configuration Object and set the enabled attribute to True
  2713. vsan_config = vim.vsan.host.ConfigInfo()
  2714. vsan_config.enabled = False
  2715. host_names = _check_hosts(service_instance, host, host_names)
  2716. ret = {}
  2717. for host_name in host_names:
  2718. host_ref = _get_host_ref(service_instance, host, host_name=host_name)
  2719. vsan_system = host_ref.configManager.vsanSystem
  2720. # We must have a VSAN Config in place before we can manipulate it.
  2721. if vsan_system is None:
  2722. msg = 'VSAN System Config Manager is unset for host \'{0}\'. ' \
  2723. 'VSAN configuration cannot be changed without a configured ' \
  2724. 'VSAN System.'.format(host_name)
  2725. log.debug(msg)
  2726. ret.update({host_name: {'Error': msg}})
  2727. else:
  2728. try:
  2729. # Disable vsan on the host
  2730. task = vsan_system.UpdateVsan_Task(vsan_config)
  2731. salt.utils.vmware.wait_for_task(task, host_name, 'Disabling VSAN', sleep_seconds=3)
  2732. except vmodl.fault.SystemError as err:
  2733. log.debug(err.msg)
  2734. ret.update({host_name: {'Error': err.msg}})
  2735. continue
  2736. except Exception as err:
  2737. msg = '\'vsphere.vsan_disable\' failed for host {0}: {1}'.format(host_name, err)
  2738. log.debug(msg)
  2739. ret.update({host_name: {'Error': msg}})
  2740. continue
  2741. ret.update({host_name: {'VSAN Disabled': True}})
  2742. return ret
  2743. @depends(HAS_PYVMOMI)
  2744. @ignores_kwargs('credstore')
  2745. def vsan_enable(host, username, password, protocol=None, port=None, host_names=None):
  2746. '''
  2747. Enable VSAN for a given host or list of host_names.
  2748. host
  2749. The location of the host.
  2750. username
  2751. The username used to login to the host, such as ``root``.
  2752. password
  2753. The password used to login to the host.
  2754. protocol
  2755. Optionally set to alternate protocol if the host is not using the default
  2756. protocol. Default protocol is ``https``.
  2757. port
  2758. Optionally set to alternate port if the host is not using the default
  2759. port. Default port is ``443``.
  2760. host_names
  2761. List of ESXi host names. When the host, username, and password credentials
  2762. are provided for a vCenter Server, the host_names argument is required to
  2763. tell vCenter which hosts should enable VSAN.
  2764. If host_names is not provided, VSAN will be enabled for the ``host``
  2765. location instead. This is useful for when service instance connection
  2766. information is used for a single ESXi host.
  2767. CLI Example:
  2768. .. code-block:: bash
  2769. # Used for single ESXi host connection information
  2770. salt '*' vsphere.vsan_enable my.esxi.host root bad-password
  2771. # Used for connecting to a vCenter Server
  2772. salt '*' vsphere.vsan_enable my.vcenter.location root bad-password \
  2773. host_names='[esxi-1.host.com, esxi-2.host.com]'
  2774. '''
  2775. service_instance = salt.utils.vmware.get_service_instance(host=host,
  2776. username=username,
  2777. password=password,
  2778. protocol=protocol,
  2779. port=port)
  2780. # Create a VSAN Configuration Object and set the enabled attribute to True
  2781. vsan_config = vim.vsan.host.ConfigInfo()
  2782. vsan_config.enabled = True
  2783. host_names = _check_hosts(service_instance, host, host_names)
  2784. ret = {}
  2785. for host_name in host_names:
  2786. host_ref = _get_host_ref(service_instance, host, host_name=host_name)
  2787. vsan_system = host_ref.configManager.vsanSystem
  2788. # We must have a VSAN Config in place before we can manipulate it.
  2789. if vsan_system is None:
  2790. msg = 'VSAN System Config Manager is unset for host \'{0}\'. ' \
  2791. 'VSAN configuration cannot be changed without a configured ' \
  2792. 'VSAN System.'.format(host_name)
  2793. log.debug(msg)
  2794. ret.update({host_name: {'Error': msg}})
  2795. else:
  2796. try:
  2797. # Enable vsan on the host
  2798. task = vsan_system.UpdateVsan_Task(vsan_config)
  2799. salt.utils.vmware.wait_for_task(task, host_name, 'Enabling VSAN', sleep_seconds=3)
  2800. except vmodl.fault.SystemError as err:
  2801. log.debug(err.msg)
  2802. ret.update({host_name: {'Error': err.msg}})
  2803. continue
  2804. except vim.fault.VsanFault as err:
  2805. msg = '\'vsphere.vsan_enable\' failed for host {0}: {1}'.format(host_name, err)
  2806. log.debug(msg)
  2807. ret.update({host_name: {'Error': msg}})
  2808. continue
  2809. ret.update({host_name: {'VSAN Enabled': True}})
  2810. return ret
  2811. def _check_hosts(service_instance, host, host_names):
  2812. '''
  2813. Helper function that checks to see if the host provided is a vCenter Server or
  2814. an ESXi host. If it's an ESXi host, returns a list of a single host_name.
  2815. If a host reference isn't found, we're trying to find a host object for a vCenter
  2816. server. Raises a CommandExecutionError in this case, as we need host references to
  2817. check against.
  2818. '''
  2819. if not host_names:
  2820. host_name = _get_host_ref(service_instance, host)
  2821. if host_name:
  2822. host_names = [host]
  2823. else:
  2824. raise CommandExecutionError('No host reference found. If connecting to a '
  2825. 'vCenter Server, a list of \'host_names\' must be '
  2826. 'provided.')
  2827. elif not isinstance(host_names, list):
  2828. raise CommandExecutionError('\'host_names\' must be a list.')
  2829. return host_names
  2830. def _format_coredump_stdout(cmd_ret):
  2831. '''
  2832. Helper function to format the stdout from the get_coredump_network_config function.
  2833. cmd_ret
  2834. The return dictionary that comes from a cmd.run_all call.
  2835. '''
  2836. ret_dict = {}
  2837. for line in cmd_ret['stdout'].splitlines():
  2838. line = line.strip().lower()
  2839. if line.startswith('enabled:'):
  2840. enabled = line.split(':')
  2841. if 'true' in enabled[1]:
  2842. ret_dict['enabled'] = True
  2843. else:
  2844. ret_dict['enabled'] = False
  2845. break
  2846. if line.startswith('host vnic:'):
  2847. host_vnic = line.split(':')
  2848. ret_dict['host_vnic'] = host_vnic[1].strip()
  2849. if line.startswith('network server ip:'):
  2850. ip = line.split(':')
  2851. ret_dict['ip'] = ip[1].strip()
  2852. if line.startswith('network server port:'):
  2853. ip_port = line.split(':')
  2854. ret_dict['port'] = ip_port[1].strip()
  2855. return ret_dict
  2856. def _format_firewall_stdout(cmd_ret):
  2857. '''
  2858. Helper function to format the stdout from the get_firewall_status function.
  2859. cmd_ret
  2860. The return dictionary that comes from a cmd.run_all call.
  2861. '''
  2862. ret_dict = {'success': True,
  2863. 'rulesets': {}}
  2864. for line in cmd_ret['stdout'].splitlines():
  2865. if line.startswith('Name'):
  2866. continue
  2867. if line.startswith('---'):
  2868. continue
  2869. ruleset_status = line.split()
  2870. ret_dict['rulesets'][ruleset_status[0]] = bool(ruleset_status[1])
  2871. return ret_dict
  2872. def _format_syslog_config(cmd_ret):
  2873. '''
  2874. Helper function to format the stdout from the get_syslog_config function.
  2875. cmd_ret
  2876. The return dictionary that comes from a cmd.run_all call.
  2877. '''
  2878. ret_dict = {'success': cmd_ret['retcode'] == 0}
  2879. if cmd_ret['retcode'] != 0:
  2880. ret_dict['message'] = cmd_ret['stdout']
  2881. else:
  2882. for line in cmd_ret['stdout'].splitlines():
  2883. line = line.strip()
  2884. cfgvars = line.split(': ')
  2885. key = cfgvars[0].strip()
  2886. value = cfgvars[1].strip()
  2887. ret_dict[key] = value
  2888. return ret_dict
  2889. def _get_date_time_mgr(host_reference):
  2890. '''
  2891. Helper function that returns a dateTimeManager object
  2892. '''
  2893. return host_reference.configManager.dateTimeSystem
  2894. def _get_host_ref(service_instance, host, host_name=None):
  2895. '''
  2896. Helper function that returns a host object either from the host location or the host_name.
  2897. If host_name is provided, that is the host_object that will be returned.
  2898. The function will first search for hosts by DNS Name. If no hosts are found, it will
  2899. try searching by IP Address.
  2900. '''
  2901. search_index = salt.utils.vmware.get_inventory(service_instance).searchIndex
  2902. # First, try to find the host reference by DNS Name.
  2903. if host_name:
  2904. host_ref = search_index.FindByDnsName(dnsName=host_name, vmSearch=False)
  2905. else:
  2906. host_ref = search_index.FindByDnsName(dnsName=host, vmSearch=False)
  2907. # If we couldn't find the host by DNS Name, then try the IP Address.
  2908. if host_ref is None:
  2909. host_ref = search_index.FindByIp(ip=host, vmSearch=False)
  2910. return host_ref
  2911. def _get_host_ssds(host_reference):
  2912. '''
  2913. Helper function that returns a list of ssd objects for a given host.
  2914. '''
  2915. return _get_host_disks(host_reference).get('SSDs')
  2916. def _get_host_non_ssds(host_reference):
  2917. '''
  2918. Helper function that returns a list of Non-SSD objects for a given host.
  2919. '''
  2920. return _get_host_disks(host_reference).get('Non-SSDs')
  2921. def _get_host_disks(host_reference):
  2922. '''
  2923. Helper function that returns a dictionary containing a list of SSD and Non-SSD disks.
  2924. '''
  2925. storage_system = host_reference.configManager.storageSystem
  2926. disks = storage_system.storageDeviceInfo.scsiLun
  2927. ssds = []
  2928. non_ssds = []
  2929. for disk in disks:
  2930. try:
  2931. has_ssd_attr = disk.ssd
  2932. except AttributeError:
  2933. has_ssd_attr = False
  2934. if has_ssd_attr:
  2935. ssds.append(disk)
  2936. else:
  2937. non_ssds.append(disk)
  2938. return {'SSDs': ssds, 'Non-SSDs': non_ssds}
  2939. def _get_service_manager(host_reference):
  2940. '''
  2941. Helper function that returns a service manager object from a given host object.
  2942. '''
  2943. return host_reference.configManager.serviceSystem
  2944. def _get_vsan_eligible_disks(service_instance, host, host_names):
  2945. '''
  2946. Helper function that returns a dictionary of host_name keys with either a list of eligible
  2947. disks that can be added to VSAN or either an 'Error' message or a message saying no
  2948. eligible disks were found. Possible keys/values look like:
  2949. return = {'host_1': {'Error': 'VSAN System Config Manager is unset ...'},
  2950. 'host_2': {'Eligible': 'The host xxx does not have any VSAN eligible disks.'},
  2951. 'host_3': {'Eligible': [disk1, disk2, disk3, disk4],
  2952. 'host_4': {'Eligible': []}}
  2953. '''
  2954. ret = {}
  2955. for host_name in host_names:
  2956. # Get VSAN System Config Manager, if available.
  2957. host_ref = _get_host_ref(service_instance, host, host_name=host_name)
  2958. vsan_system = host_ref.configManager.vsanSystem
  2959. if vsan_system is None:
  2960. msg = 'VSAN System Config Manager is unset for host \'{0}\'. ' \
  2961. 'VSAN configuration cannot be changed without a configured ' \
  2962. 'VSAN System.'.format(host_name)
  2963. log.debug(msg)
  2964. ret.update({host_name: {'Error': msg}})
  2965. continue
  2966. # Get all VSAN suitable disks for this host.
  2967. suitable_disks = []
  2968. query = vsan_system.QueryDisksForVsan()
  2969. for item in query:
  2970. if item.state == 'eligible':
  2971. suitable_disks.append(item)
  2972. # No suitable disks were found to add. Warn and move on.
  2973. # This isn't an error as the state may run repeatedly after all eligible disks are added.
  2974. if not suitable_disks:
  2975. msg = 'The host \'{0}\' does not have any VSAN eligible disks.'.format(host_name)
  2976. log.warning(msg)
  2977. ret.update({host_name: {'Eligible': msg}})
  2978. continue
  2979. # Get disks for host and combine into one list of Disk Objects
  2980. disks = _get_host_ssds(host_ref) + _get_host_non_ssds(host_ref)
  2981. # Get disks that are in both the disks list and suitable_disks lists.
  2982. matching = []
  2983. for disk in disks:
  2984. for suitable_disk in suitable_disks:
  2985. if disk.canonicalName == suitable_disk.disk.canonicalName:
  2986. matching.append(disk)
  2987. ret.update({host_name: {'Eligible': matching}})
  2988. return ret
  2989. def _reset_syslog_config_params(host, username, password, cmd, resets, valid_resets,
  2990. protocol=None, port=None, esxi_host=None, credstore=None):
  2991. '''
  2992. Helper function for reset_syslog_config that resets the config and populates the return dictionary.
  2993. '''
  2994. ret_dict = {}
  2995. all_success = True
  2996. if not isinstance(resets, list):
  2997. resets = [resets]
  2998. for reset_param in resets:
  2999. if reset_param in valid_resets:
  3000. ret = salt.utils.vmware.esxcli(host, username, password, cmd + reset_param,
  3001. protocol=protocol, port=port,
  3002. esxi_host=esxi_host, credstore=credstore)
  3003. ret_dict[reset_param] = {}
  3004. ret_dict[reset_param]['success'] = ret['retcode'] == 0
  3005. if ret['retcode'] != 0:
  3006. all_success = False
  3007. ret_dict[reset_param]['message'] = ret['stdout']
  3008. else:
  3009. all_success = False
  3010. ret_dict[reset_param] = {}
  3011. ret_dict[reset_param]['success'] = False
  3012. ret_dict[reset_param]['message'] = 'Invalid syslog ' \
  3013. 'configuration parameter'
  3014. ret_dict['success'] = all_success
  3015. return ret_dict
  3016. def _set_syslog_config_helper(host, username, password, syslog_config, config_value,
  3017. protocol=None, port=None, reset_service=None, esxi_host=None, credstore=None):
  3018. '''
  3019. Helper function for set_syslog_config that sets the config and populates the return dictionary.
  3020. '''
  3021. cmd = 'system syslog config set --{0} {1}'.format(syslog_config, config_value)
  3022. ret_dict = {}
  3023. valid_resets = ['logdir', 'loghost', 'default-rotate',
  3024. 'default-size', 'default-timeout', 'logdir-unique']
  3025. if syslog_config not in valid_resets:
  3026. ret_dict.update({'success': False,
  3027. 'message': '\'{0}\' is not a valid config variable.'.format(syslog_config)})
  3028. return ret_dict
  3029. response = salt.utils.vmware.esxcli(host, username, password, cmd,
  3030. protocol=protocol, port=port,
  3031. esxi_host=esxi_host, credstore=credstore)
  3032. # Update the return dictionary for success or error messages.
  3033. if response['retcode'] != 0:
  3034. ret_dict.update({syslog_config: {'success': False,
  3035. 'message': response['stdout']}})
  3036. else:
  3037. ret_dict.update({syslog_config: {'success': True}})
  3038. # Restart syslog for each host, if desired.
  3039. if reset_service:
  3040. if esxi_host:
  3041. host_name = esxi_host
  3042. esxi_host = [esxi_host]
  3043. else:
  3044. host_name = host
  3045. response = syslog_service_reload(host, username, password,
  3046. protocol=protocol, port=port,
  3047. esxi_hosts=esxi_host, credstore=credstore).get(host_name)
  3048. ret_dict.update({'syslog_restart': {'success': response['retcode'] == 0}})
  3049. return ret_dict
  3050. @ignores_kwargs('credstore')
  3051. def add_host_to_dvs(host, username, password, vmknic_name, vmnic_name,
  3052. dvs_name, target_portgroup_name, uplink_portgroup_name,
  3053. protocol=None, port=None, host_names=None):
  3054. '''
  3055. Adds an ESXi host to a vSphere Distributed Virtual Switch and migrates
  3056. the desired adapters to the DVS from the standard switch.
  3057. host
  3058. The location of the vCenter server.
  3059. username
  3060. The username used to login to the vCenter server.
  3061. password
  3062. The password used to login to the vCenter server.
  3063. vmknic_name
  3064. The name of the virtual NIC to migrate.
  3065. vmnic_name
  3066. The name of the physical NIC to migrate.
  3067. dvs_name
  3068. The name of the Distributed Virtual Switch.
  3069. target_portgroup_name
  3070. The name of the distributed portgroup in which to migrate the
  3071. virtual NIC.
  3072. uplink_portgroup_name
  3073. The name of the uplink portgroup in which to migrate the
  3074. physical NIC.
  3075. protocol
  3076. Optionally set to alternate protocol if the vCenter server or ESX/ESXi host is not
  3077. using the default protocol. Default protocol is ``https``.
  3078. port
  3079. Optionally set to alternate port if the vCenter server or ESX/ESXi host is not
  3080. using the default port. Default port is ``443``.
  3081. host_names:
  3082. An array of VMware host names to migrate
  3083. CLI Example:
  3084. .. code-block:: bash
  3085. salt some_host vsphere.add_host_to_dvs host='vsphere.corp.com'
  3086. username='administrator@vsphere.corp.com' password='vsphere_password'
  3087. vmknic_name='vmk0' vmnic_name='vnmic0' dvs_name='DSwitch'
  3088. target_portgroup_name='DPortGroup' uplink_portgroup_name='DSwitch1-DVUplinks-181'
  3089. protocol='https' port='443', host_names="['esxi1.corp.com','esxi2.corp.com','esxi3.corp.com']"
  3090. Return Example:
  3091. .. code-block:: yaml
  3092. somehost:
  3093. ----------
  3094. esxi1.corp.com:
  3095. ----------
  3096. dvs:
  3097. DSwitch
  3098. portgroup:
  3099. DPortGroup
  3100. status:
  3101. True
  3102. uplink:
  3103. DSwitch-DVUplinks-181
  3104. vmknic:
  3105. vmk0
  3106. vmnic:
  3107. vmnic0
  3108. esxi2.corp.com:
  3109. ----------
  3110. dvs:
  3111. DSwitch
  3112. portgroup:
  3113. DPortGroup
  3114. status:
  3115. True
  3116. uplink:
  3117. DSwitch-DVUplinks-181
  3118. vmknic:
  3119. vmk0
  3120. vmnic:
  3121. vmnic0
  3122. esxi3.corp.com:
  3123. ----------
  3124. dvs:
  3125. DSwitch
  3126. portgroup:
  3127. DPortGroup
  3128. status:
  3129. True
  3130. uplink:
  3131. DSwitch-DVUplinks-181
  3132. vmknic:
  3133. vmk0
  3134. vmnic:
  3135. vmnic0
  3136. message:
  3137. success:
  3138. True
  3139. This was very difficult to figure out. VMware's PyVmomi documentation at
  3140. https://github.com/vmware/pyvmomi/blob/master/docs/vim/DistributedVirtualSwitch.rst
  3141. (which is a copy of the official documentation here:
  3142. https://www.vmware.com/support/developer/converter-sdk/conv60_apireference/vim.DistributedVirtualSwitch.html)
  3143. says to create the DVS, create distributed portgroups, and then add the
  3144. host to the DVS specifying which physical NIC to use as the port backing.
  3145. However, if the physical NIC is in use as the only link from the host
  3146. to vSphere, this will fail with an unhelpful "busy" error.
  3147. There is, however, a Powershell PowerCLI cmdlet called Add-VDSwitchPhysicalNetworkAdapter
  3148. that does what we want. I used Onyx (https://labs.vmware.com/flings/onyx)
  3149. to sniff the SOAP stream from Powershell to our vSphere server and got
  3150. this snippet out:
  3151. <UpdateNetworkConfig xmlns="urn:vim25">
  3152. <_this type="HostNetworkSystem">networkSystem-187</_this>
  3153. <config>
  3154. <vswitch>
  3155. <changeOperation>edit</changeOperation>
  3156. <name>vSwitch0</name>
  3157. <spec>
  3158. <numPorts>7812</numPorts>
  3159. </spec>
  3160. </vswitch>
  3161. <proxySwitch>
  3162. <changeOperation>edit</changeOperation>
  3163. <uuid>73 a4 05 50 b0 d2 7e b9-38 80 5d 24 65 8f da 70</uuid>
  3164. <spec>
  3165. <backing xsi:type="DistributedVirtualSwitchHostMemberPnicBacking">
  3166. <pnicSpec><pnicDevice>vmnic0</pnicDevice></pnicSpec>
  3167. </backing>
  3168. </spec>
  3169. </proxySwitch>
  3170. <portgroup>
  3171. <changeOperation>remove</changeOperation>
  3172. <spec>
  3173. <name>Management Network</name><vlanId>-1</vlanId><vswitchName /><policy />
  3174. </spec>
  3175. </portgroup>
  3176. <vnic>
  3177. <changeOperation>edit</changeOperation>
  3178. <device>vmk0</device>
  3179. <portgroup />
  3180. <spec>
  3181. <distributedVirtualPort>
  3182. <switchUuid>73 a4 05 50 b0 d2 7e b9-38 80 5d 24 65 8f da 70</switchUuid>
  3183. <portgroupKey>dvportgroup-191</portgroupKey>
  3184. </distributedVirtualPort>
  3185. </spec>
  3186. </vnic>
  3187. </config>
  3188. <changeMode>modify</changeMode>
  3189. </UpdateNetworkConfig>
  3190. The SOAP API maps closely to PyVmomi, so from there it was (relatively)
  3191. easy to figure out what Python to write.
  3192. '''
  3193. ret = {}
  3194. ret['success'] = True
  3195. ret['message'] = []
  3196. service_instance = salt.utils.vmware.get_service_instance(host=host,
  3197. username=username,
  3198. password=password,
  3199. protocol=protocol,
  3200. port=port)
  3201. dvs = salt.utils.vmware._get_dvs(service_instance, dvs_name)
  3202. if not dvs:
  3203. ret['message'].append('No Distributed Virtual Switch found with name {0}'.format(dvs_name))
  3204. ret['success'] = False
  3205. target_portgroup = salt.utils.vmware._get_dvs_portgroup(dvs,
  3206. target_portgroup_name)
  3207. if not target_portgroup:
  3208. ret['message'].append('No target portgroup found with name {0}'.format(target_portgroup_name))
  3209. ret['success'] = False
  3210. uplink_portgroup = salt.utils.vmware._get_dvs_uplink_portgroup(dvs,
  3211. uplink_portgroup_name)
  3212. if not uplink_portgroup:
  3213. ret['message'].append('No uplink portgroup found with name {0}'.format(uplink_portgroup_name))
  3214. ret['success'] = False
  3215. if len(ret['message']) > 0:
  3216. return ret
  3217. dvs_uuid = dvs.config.uuid
  3218. try:
  3219. host_names = _check_hosts(service_instance, host, host_names)
  3220. except CommandExecutionError as e:
  3221. ret['message'] = 'Error retrieving hosts: {0}'.format(e.msg)
  3222. return ret
  3223. for host_name in host_names:
  3224. ret[host_name] = {}
  3225. ret[host_name].update({'status': False,
  3226. 'uplink': uplink_portgroup_name,
  3227. 'portgroup': target_portgroup_name,
  3228. 'vmknic': vmknic_name,
  3229. 'vmnic': vmnic_name,
  3230. 'dvs': dvs_name})
  3231. host_ref = _get_host_ref(service_instance, host, host_name)
  3232. if not host_ref:
  3233. ret[host_name].update({'message': 'Host {1} not found'.format(host_name)})
  3234. ret['success'] = False
  3235. continue
  3236. dvs_hostmember_config = vim.dvs.HostMember.ConfigInfo(
  3237. host=host_ref
  3238. )
  3239. dvs_hostmember = vim.dvs.HostMember(
  3240. config=dvs_hostmember_config
  3241. )
  3242. p_nics = salt.utils.vmware._get_pnics(host_ref)
  3243. p_nic = [x for x in p_nics if x.device == vmnic_name]
  3244. if len(p_nic) == 0:
  3245. ret[host_name].update({'message': 'Physical nic {0} not found'.format(vmknic_name)})
  3246. ret['success'] = False
  3247. continue
  3248. v_nics = salt.utils.vmware._get_vnics(host_ref)
  3249. v_nic = [x for x in v_nics if x.device == vmknic_name]
  3250. if len(v_nic) == 0:
  3251. ret[host_name].update({'message': 'Virtual nic {0} not found'.format(vmnic_name)})
  3252. ret['success'] = False
  3253. continue
  3254. v_nic_mgr = salt.utils.vmware._get_vnic_manager(host_ref)
  3255. if not v_nic_mgr:
  3256. ret[host_name].update({'message': 'Unable to get the host\'s virtual nic manager.'})
  3257. ret['success'] = False
  3258. continue
  3259. dvs_pnic_spec = vim.dvs.HostMember.PnicSpec(
  3260. pnicDevice=vmnic_name,
  3261. uplinkPortgroupKey=uplink_portgroup.key
  3262. )
  3263. pnic_backing = vim.dvs.HostMember.PnicBacking(
  3264. pnicSpec=[dvs_pnic_spec]
  3265. )
  3266. dvs_hostmember_config_spec = vim.dvs.HostMember.ConfigSpec(
  3267. host=host_ref,
  3268. operation='add',
  3269. )
  3270. dvs_config = vim.DVSConfigSpec(
  3271. configVersion=dvs.config.configVersion,
  3272. host=[dvs_hostmember_config_spec])
  3273. task = dvs.ReconfigureDvs_Task(spec=dvs_config)
  3274. try:
  3275. salt.utils.vmware.wait_for_task(task, host_name,
  3276. 'Adding host to the DVS',
  3277. sleep_seconds=3)
  3278. except Exception as e:
  3279. if hasattr(e, 'message') and hasattr(e.message, 'msg'):
  3280. if not (host_name in e.message.msg and 'already exists' in e.message.msg):
  3281. ret['success'] = False
  3282. ret[host_name].update({'message': e.message.msg})
  3283. continue
  3284. else:
  3285. raise
  3286. network_system = host_ref.configManager.networkSystem
  3287. source_portgroup = None
  3288. for pg in host_ref.config.network.portgroup:
  3289. if pg.spec.name == v_nic[0].portgroup:
  3290. source_portgroup = pg
  3291. break
  3292. if not source_portgroup:
  3293. ret[host_name].update({'message': 'No matching portgroup on the vSwitch'})
  3294. ret['success'] = False
  3295. continue
  3296. virtual_nic_config = vim.HostVirtualNicConfig(
  3297. changeOperation='edit',
  3298. device=v_nic[0].device,
  3299. portgroup=source_portgroup.spec.name,
  3300. spec=vim.HostVirtualNicSpec(
  3301. distributedVirtualPort=vim.DistributedVirtualSwitchPortConnection(
  3302. portgroupKey=target_portgroup.key,
  3303. switchUuid=target_portgroup.config.distributedVirtualSwitch.uuid
  3304. )
  3305. )
  3306. )
  3307. current_vswitch_ports = host_ref.config.network.vswitch[0].numPorts
  3308. vswitch_config = vim.HostVirtualSwitchConfig(
  3309. changeOperation='edit',
  3310. name='vSwitch0',
  3311. spec=vim.HostVirtualSwitchSpec(numPorts=current_vswitch_ports)
  3312. )
  3313. proxyswitch_config = vim.HostProxySwitchConfig(
  3314. changeOperation='edit',
  3315. uuid=dvs_uuid,
  3316. spec=vim.HostProxySwitchSpec(backing=pnic_backing)
  3317. )
  3318. host_network_config = vim.HostNetworkConfig(
  3319. vswitch=[vswitch_config],
  3320. proxySwitch=[proxyswitch_config],
  3321. portgroup=[vim.HostPortGroupConfig(
  3322. changeOperation='remove',
  3323. spec=source_portgroup.spec)
  3324. ],
  3325. vnic=[virtual_nic_config])
  3326. try:
  3327. network_system.UpdateNetworkConfig(changeMode='modify',
  3328. config=host_network_config)
  3329. ret[host_name].update({'status': True})
  3330. except Exception as e:
  3331. if hasattr(e, 'msg'):
  3332. ret[host_name].update({'message': 'Failed to migrate adapters ({0})'.format(e.msg)})
  3333. continue
  3334. else:
  3335. raise
  3336. return ret