mirror of
https://github.com/saltstack/salt.git
synced 2025-04-16 09:40:20 +00:00

Since "pchanges" was never supported in the state compiler, and "changes" is what these reqs always used, replacing "pchanges" with "changes" will allow those requisites to work in test mode. Conflicts: - salt/states/file.py - salt/states/linux_acl.py - salt/utils/napalm.py - tests/integration/modules/test_state.py - tests/unit/states/test_file.py
716 lines
26 KiB
Python
716 lines
26 KiB
Python
# -*- coding: utf-8 -*-
|
|
'''
|
|
Manage VMware distributed virtual switches (DVSs) and their distributed virtual
|
|
portgroups (DVportgroups).
|
|
|
|
:codeauthor: :email:`Alexandru Bleotu <alexandru.bleotu@morganstaley.com>`
|
|
|
|
Examples
|
|
========
|
|
|
|
Several settings can be changed for DVSs and DVporgroups. Here are two examples
|
|
covering all of the settings. Fewer settings can be used
|
|
|
|
DVS
|
|
---
|
|
|
|
.. code-block:: python
|
|
|
|
'name': 'dvs1',
|
|
'max_mtu': 1000,
|
|
'uplink_names': [
|
|
'dvUplink1',
|
|
'dvUplink2',
|
|
'dvUplink3'
|
|
],
|
|
'capability': {
|
|
'portgroup_operation_supported': false,
|
|
'operation_supported': true,
|
|
'port_operation_supported': false
|
|
},
|
|
'lacp_api_version': 'multipleLag',
|
|
'contact_email': 'foo@email.com',
|
|
'product_info': {
|
|
'version':
|
|
'6.0.0',
|
|
'vendor':
|
|
'VMware,
|
|
Inc.',
|
|
'name':
|
|
'DVS'
|
|
},
|
|
'network_resource_management_enabled': true,
|
|
'contact_name': 'me@email.com',
|
|
'infrastructure_traffic_resource_pools': [
|
|
{
|
|
'reservation': 0,
|
|
'limit': 1000,
|
|
'share_level': 'high',
|
|
'key': 'management',
|
|
'num_shares': 100
|
|
},
|
|
{
|
|
'reservation': 0,
|
|
'limit': -1,
|
|
'share_level': 'normal',
|
|
'key': 'faultTolerance',
|
|
'num_shares': 50
|
|
},
|
|
{
|
|
'reservation': 0,
|
|
'limit': 32000,
|
|
'share_level': 'normal',
|
|
'key': 'vmotion',
|
|
'num_shares': 50
|
|
},
|
|
{
|
|
'reservation': 10000,
|
|
'limit': -1,
|
|
'share_level': 'normal',
|
|
'key': 'virtualMachine',
|
|
'num_shares': 50
|
|
},
|
|
{
|
|
'reservation': 0,
|
|
'limit': -1,
|
|
'share_level': 'custom',
|
|
'key': 'iSCSI',
|
|
'num_shares': 75
|
|
},
|
|
{
|
|
'reservation': 0,
|
|
'limit': -1,
|
|
'share_level': 'normal',
|
|
'key': 'nfs',
|
|
'num_shares': 50
|
|
},
|
|
{
|
|
'reservation': 0,
|
|
'limit': -1,
|
|
'share_level': 'normal',
|
|
'key': 'hbr',
|
|
'num_shares': 50
|
|
},
|
|
{
|
|
'reservation': 8750,
|
|
'limit': 15000,
|
|
'share_level': 'high',
|
|
'key': 'vsan',
|
|
'num_shares': 100
|
|
},
|
|
{
|
|
'reservation': 0,
|
|
'limit': -1,
|
|
'share_level': 'normal',
|
|
'key': 'vdp',
|
|
'num_shares': 50
|
|
}
|
|
],
|
|
'link_discovery_protocol': {
|
|
'operation':
|
|
'listen',
|
|
'protocol':
|
|
'cdp'
|
|
},
|
|
'network_resource_control_version': 'version3',
|
|
'description': 'Managed by Salt. Random settings.'
|
|
|
|
Note: The mandatory attribute is: ``name``.
|
|
|
|
Portgroup
|
|
---------
|
|
|
|
.. code-block:: python
|
|
'security_policy': {
|
|
'allow_promiscuous': true,
|
|
'mac_changes': false,
|
|
'forged_transmits': true
|
|
},
|
|
'name': 'vmotion-v702',
|
|
'out_shaping': {
|
|
'enabled': true,
|
|
'average_bandwidth': 1500,
|
|
'burst_size': 4096,
|
|
'peak_bandwidth': 1500
|
|
},
|
|
'num_ports': 128,
|
|
'teaming': {
|
|
'port_order': {
|
|
'active': [
|
|
'dvUplink2'
|
|
],
|
|
'standby': [
|
|
'dvUplink1'
|
|
]
|
|
},
|
|
'notify_switches': false,
|
|
'reverse_policy': true,
|
|
'rolling_order': false,
|
|
'policy': 'failover_explicit',
|
|
'failure_criteria': {
|
|
'check_error_percent': true,
|
|
'full_duplex': false,
|
|
'check_duplex': false,
|
|
'percentage': 50,
|
|
'check_speed': 'minimum',
|
|
'speed': 20,
|
|
'check_beacon': true
|
|
}
|
|
},
|
|
'type': 'earlyBinding',
|
|
'vlan_id': 100,
|
|
'description': 'Managed by Salt. Random settings.'
|
|
|
|
Note: The mandatory attributes are: ``name``, ``type``.
|
|
|
|
Dependencies
|
|
============
|
|
|
|
|
|
- pyVmomi Python Module
|
|
|
|
|
|
pyVmomi
|
|
-------
|
|
|
|
PyVmomi can be installed via pip:
|
|
|
|
.. code-block:: bash
|
|
|
|
pip install pyVmomi
|
|
|
|
.. note::
|
|
|
|
Version 6.0 of pyVmomi has some problems with SSL error handling on certain
|
|
versions of Python. If using version 6.0 of pyVmomi, Python 2.7.9,
|
|
or newer must be present. This is due to an upstream dependency
|
|
in pyVmomi 6.0 that is not supported in Python versions 2.7 to 2.7.8. If the
|
|
version of Python is not in the supported range, you will need to install an
|
|
earlier version of pyVmomi. See `Issue #29537`_ for more information.
|
|
|
|
.. _Issue #29537: https://github.com/saltstack/salt/issues/29537
|
|
|
|
Based on the note above, to install an earlier version of pyVmomi than the
|
|
version currently listed in PyPi, run the following:
|
|
|
|
.. code-block:: bash
|
|
|
|
pip install pyVmomi==5.5.0.2014.1.1
|
|
|
|
The 5.5.0.2014.1.1 is a known stable version that this original ESXi State
|
|
Module was developed against.
|
|
'''
|
|
|
|
# Import Python Libs
|
|
from __future__ import absolute_import, print_function, unicode_literals
|
|
import logging
|
|
import traceback
|
|
import sys
|
|
|
|
# Import Salt Libs
|
|
import salt.exceptions
|
|
from salt.ext import six
|
|
from salt.ext.six.moves import range
|
|
|
|
# Import Third Party Libs
|
|
try:
|
|
from pyVmomi import VmomiSupport
|
|
HAS_PYVMOMI = True
|
|
except ImportError:
|
|
HAS_PYVMOMI = False
|
|
|
|
# Get Logging Started
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
def __virtual__():
|
|
if not HAS_PYVMOMI:
|
|
return False, 'State module did not load: pyVmomi not found'
|
|
|
|
# We check the supported vim versions to infer the pyVmomi version
|
|
if 'vim25/6.0' in VmomiSupport.versionMap and \
|
|
sys.version_info > (2, 7) and sys.version_info < (2, 7, 9):
|
|
|
|
return False, ('State module did not load: Incompatible versions '
|
|
'of Python and pyVmomi present. See Issue #29537.')
|
|
return 'dvs'
|
|
|
|
|
|
def mod_init(low):
|
|
'''
|
|
Init function
|
|
'''
|
|
return True
|
|
|
|
|
|
def _get_datacenter_name():
|
|
'''
|
|
Returns the datacenter name configured on the proxy
|
|
|
|
Supported proxies: esxcluster, esxdatacenter
|
|
'''
|
|
|
|
proxy_type = __salt__['vsphere.get_proxy_type']()
|
|
details = None
|
|
if proxy_type == 'esxcluster':
|
|
details = __salt__['esxcluster.get_details']()
|
|
elif proxy_type == 'esxdatacenter':
|
|
details = __salt__['esxdatacenter.get_details']()
|
|
if not details:
|
|
raise salt.exceptions.CommandExecutionError(
|
|
'details for proxy type \'{0}\' not loaded'.format(proxy_type))
|
|
return details['datacenter']
|
|
|
|
|
|
def dvs_configured(name, dvs):
|
|
'''
|
|
Configures a DVS.
|
|
|
|
Creates a new DVS, if it doesn't exist in the provided datacenter or
|
|
reconfigures it if configured differently.
|
|
|
|
dvs
|
|
DVS dict representations (see module sysdocs)
|
|
'''
|
|
datacenter_name = _get_datacenter_name()
|
|
dvs_name = dvs['name'] if dvs.get('name') else name
|
|
log.info('Running state {0} for DVS \'{1}\' in datacenter '
|
|
'\'{2}\''.format(name, dvs_name, datacenter_name))
|
|
changes_required = False
|
|
ret = {'name': name, 'changes': {}, 'result': None, 'comment': None}
|
|
comments = []
|
|
changes = {}
|
|
changes_required = False
|
|
|
|
try:
|
|
#TODO dvs validation
|
|
si = __salt__['vsphere.get_service_instance_via_proxy']()
|
|
dvss = __salt__['vsphere.list_dvss'](dvs_names=[dvs_name],
|
|
service_instance=si)
|
|
if not dvss:
|
|
changes_required = True
|
|
if __opts__['test']:
|
|
comments.append('State {0} will create a new DVS '
|
|
'\'{1}\' in datacenter \'{2}\''
|
|
''.format(name, dvs_name, datacenter_name))
|
|
log.info(comments[-1])
|
|
else:
|
|
dvs['name'] = dvs_name
|
|
__salt__['vsphere.create_dvs'](dvs_dict=dvs,
|
|
dvs_name=dvs_name,
|
|
service_instance=si)
|
|
comments.append('Created a new DVS \'{0}\' in datacenter '
|
|
'\'{1}\''.format(dvs_name, datacenter_name))
|
|
log.info(comments[-1])
|
|
changes.update({'dvs': {'new': dvs}})
|
|
else:
|
|
# DVS already exists. Checking various aspects of the config
|
|
props = ['description', 'contact_email', 'contact_name',
|
|
'lacp_api_version', 'link_discovery_protocol',
|
|
'max_mtu', 'network_resource_control_version',
|
|
'network_resource_management_enabled']
|
|
log.trace('DVS \'{0}\' found in datacenter \'{1}\'. Checking '
|
|
'for any updates in '
|
|
'{2}'.format(dvs_name, datacenter_name, props))
|
|
props_to_original_values = {}
|
|
props_to_updated_values = {}
|
|
current_dvs = dvss[0]
|
|
for prop in props:
|
|
if prop in dvs and dvs[prop] != current_dvs.get(prop):
|
|
props_to_original_values[prop] = current_dvs.get(prop)
|
|
props_to_updated_values[prop] = dvs[prop]
|
|
|
|
# Simple infrastructure traffic resource control compare doesn't
|
|
# work because num_shares is optional if share_level is not custom
|
|
# We need to do a dedicated compare for this property
|
|
infra_prop = 'infrastructure_traffic_resource_pools'
|
|
original_infra_res_pools = []
|
|
updated_infra_res_pools = []
|
|
if infra_prop in dvs:
|
|
if not current_dvs.get(infra_prop):
|
|
updated_infra_res_pools = dvs[infra_prop]
|
|
else:
|
|
for idx in range(len(dvs[infra_prop])):
|
|
if 'num_shares' not in dvs[infra_prop][idx] and \
|
|
current_dvs[infra_prop][idx]['share_level'] != \
|
|
'custom' and \
|
|
'num_shares' in current_dvs[infra_prop][idx]:
|
|
|
|
del current_dvs[infra_prop][idx]['num_shares']
|
|
if dvs[infra_prop][idx] != \
|
|
current_dvs[infra_prop][idx]:
|
|
|
|
original_infra_res_pools.append(
|
|
current_dvs[infra_prop][idx])
|
|
updated_infra_res_pools.append(
|
|
dict(dvs[infra_prop][idx]))
|
|
if updated_infra_res_pools:
|
|
props_to_original_values[
|
|
'infrastructure_traffic_resource_pools'] = \
|
|
original_infra_res_pools
|
|
props_to_updated_values[
|
|
'infrastructure_traffic_resource_pools'] = \
|
|
updated_infra_res_pools
|
|
if props_to_updated_values:
|
|
if __opts__['test']:
|
|
changes_string = ''
|
|
for p in props_to_updated_values:
|
|
if p == 'infrastructure_traffic_resource_pools':
|
|
changes_string += \
|
|
'\tinfrastructure_traffic_resource_pools:\n'
|
|
for idx in range(len(props_to_updated_values[p])):
|
|
d = props_to_updated_values[p][idx]
|
|
s = props_to_original_values[p][idx]
|
|
changes_string += \
|
|
('\t\t{0} from \'{1}\' to \'{2}\'\n'
|
|
''.format(d['key'], s, d))
|
|
else:
|
|
changes_string += \
|
|
('\t{0} from \'{1}\' to \'{2}\'\n'
|
|
''.format(p, props_to_original_values[p],
|
|
props_to_updated_values[p]))
|
|
comments.append(
|
|
'State dvs_configured will update DVS \'{0}\' '
|
|
'in datacenter \'{1}\':\n{2}'
|
|
''.format(dvs_name, datacenter_name, changes_string))
|
|
log.info(comments[-1])
|
|
else:
|
|
__salt__['vsphere.update_dvs'](
|
|
dvs_dict=props_to_updated_values,
|
|
dvs=dvs_name,
|
|
service_instance=si)
|
|
comments.append('Updated DVS \'{0}\' in datacenter \'{1}\''
|
|
''.format(dvs_name, datacenter_name))
|
|
log.info(comments[-1])
|
|
changes.update({'dvs': {'new': props_to_updated_values,
|
|
'old': props_to_original_values}})
|
|
__salt__['vsphere.disconnect'](si)
|
|
except salt.exceptions.CommandExecutionError as exc:
|
|
log.error('Error: {0}\n{1}'.format(exc, traceback.format_exc()))
|
|
if si:
|
|
__salt__['vsphere.disconnect'](si)
|
|
if not __opts__['test']:
|
|
ret['result'] = False
|
|
ret.update({'comment': six.text_type(exc),
|
|
'result': False if not __opts__['test'] else None})
|
|
return ret
|
|
if not comments:
|
|
# We have no changes
|
|
ret.update({'comment': ('DVS \'{0}\' in datacenter \'{1}\' is '
|
|
'correctly configured. Nothing to be done.'
|
|
''.format(dvs_name, datacenter_name)),
|
|
'result': True})
|
|
else:
|
|
ret.update({
|
|
'comment': '\n'.join(comments),
|
|
'changes': changes,
|
|
'result': None if __opts__['test'] else True,
|
|
})
|
|
return ret
|
|
|
|
|
|
def _get_diff_dict(dict1, dict2):
|
|
'''
|
|
Returns a dictionary with the diffs between two dictionaries
|
|
|
|
It will ignore any key that doesn't exist in dict2
|
|
'''
|
|
ret_dict = {}
|
|
for p in dict2.keys():
|
|
if p not in dict1:
|
|
ret_dict.update({p: {'val1': None, 'val2': dict2[p]}})
|
|
elif dict1[p] != dict2[p]:
|
|
if isinstance(dict1[p], dict) and isinstance(dict2[p], dict):
|
|
sub_diff_dict = _get_diff_dict(dict1[p], dict2[p])
|
|
if sub_diff_dict:
|
|
ret_dict.update({p: sub_diff_dict})
|
|
else:
|
|
ret_dict.update({p: {'val1': dict1[p], 'val2': dict2[p]}})
|
|
return ret_dict
|
|
|
|
|
|
def _get_val2_dict_from_diff_dict(diff_dict):
|
|
'''
|
|
Returns a dictionaries with the values stored in val2 of a diff dict.
|
|
'''
|
|
ret_dict = {}
|
|
for p in diff_dict.keys():
|
|
if not isinstance(diff_dict[p], dict):
|
|
raise ValueError('Unexpected diff difct \'{0}\''.format(diff_dict))
|
|
if 'val2' in diff_dict[p].keys():
|
|
ret_dict.update({p: diff_dict[p]['val2']})
|
|
else:
|
|
ret_dict.update(
|
|
{p: _get_val2_dict_from_diff_dict(diff_dict[p])})
|
|
return ret_dict
|
|
|
|
|
|
def _get_val1_dict_from_diff_dict(diff_dict):
|
|
'''
|
|
Returns a dictionaries with the values stored in val1 of a diff dict.
|
|
'''
|
|
ret_dict = {}
|
|
for p in diff_dict.keys():
|
|
if not isinstance(diff_dict[p], dict):
|
|
raise ValueError('Unexpected diff difct \'{0}\''.format(diff_dict))
|
|
if 'val1' in diff_dict[p].keys():
|
|
ret_dict.update({p: diff_dict[p]['val1']})
|
|
else:
|
|
ret_dict.update(
|
|
{p: _get_val1_dict_from_diff_dict(diff_dict[p])})
|
|
return ret_dict
|
|
|
|
|
|
def _get_changes_from_diff_dict(diff_dict):
|
|
'''
|
|
Returns a list of string message of the differences in a diff dict.
|
|
|
|
Each inner message is tabulated one tab deeper
|
|
'''
|
|
changes_strings = []
|
|
for p in diff_dict.keys():
|
|
if not isinstance(diff_dict[p], dict):
|
|
raise ValueError('Unexpected diff difct \'{0}\''.format(diff_dict))
|
|
if sorted(diff_dict[p].keys()) == ['val1', 'val2']:
|
|
# Some string formatting
|
|
from_str = diff_dict[p]['val1']
|
|
if isinstance(diff_dict[p]['val1'], six.string_types):
|
|
from_str = '\'{0}\''.format(diff_dict[p]['val1'])
|
|
elif isinstance(diff_dict[p]['val1'], list):
|
|
from_str = '\'{0}\''.format(', '.join(diff_dict[p]['val1']))
|
|
to_str = diff_dict[p]['val2']
|
|
if isinstance(diff_dict[p]['val2'], six.string_types):
|
|
to_str = '\'{0}\''.format(diff_dict[p]['val2'])
|
|
elif isinstance(diff_dict[p]['val2'], list):
|
|
to_str = '\'{0}\''.format(', '.join(diff_dict[p]['val2']))
|
|
changes_strings.append('{0} from {1} to {2}'.format(
|
|
p, from_str, to_str))
|
|
else:
|
|
sub_changes = _get_changes_from_diff_dict(diff_dict[p])
|
|
if sub_changes:
|
|
changes_strings.append('{0}:'.format(p))
|
|
changes_strings.extend(['\t{0}'.format(c)
|
|
for c in sub_changes])
|
|
return changes_strings
|
|
|
|
|
|
def portgroups_configured(name, dvs, portgroups):
|
|
'''
|
|
Configures portgroups on a DVS.
|
|
|
|
Creates/updates/removes portgroups in a provided DVS
|
|
|
|
dvs
|
|
Name of the DVS
|
|
|
|
portgroups
|
|
Portgroup dict representations (see module sysdocs)
|
|
'''
|
|
datacenter = _get_datacenter_name()
|
|
log.info('Running state {0} on DVS \'{1}\', datacenter '
|
|
'\'{2}\''.format(name, dvs, datacenter))
|
|
changes_required = False
|
|
ret = {'name': name,
|
|
'changes': {},
|
|
'result': None,
|
|
'comment': None}
|
|
comments = []
|
|
changes = {}
|
|
changes_required = False
|
|
|
|
try:
|
|
#TODO portroups validation
|
|
si = __salt__['vsphere.get_service_instance_via_proxy']()
|
|
current_pgs = __salt__['vsphere.list_dvportgroups'](
|
|
dvs=dvs, service_instance=si)
|
|
expected_pg_names = []
|
|
for pg in portgroups:
|
|
pg_name = pg['name']
|
|
expected_pg_names.append(pg_name)
|
|
del pg['name']
|
|
log.info('Checking pg \'{0}\''.format(pg_name))
|
|
filtered_current_pgs = \
|
|
[p for p in current_pgs if p.get('name') == pg_name]
|
|
if not filtered_current_pgs:
|
|
changes_required = True
|
|
if __opts__['test']:
|
|
comments.append('State {0} will create a new portgroup '
|
|
'\'{1}\' in DVS \'{2}\', datacenter '
|
|
'\'{3}\''.format(name, pg_name, dvs,
|
|
datacenter))
|
|
else:
|
|
__salt__['vsphere.create_dvportgroup'](
|
|
portgroup_dict=pg, portgroup_name=pg_name, dvs=dvs,
|
|
service_instance=si)
|
|
comments.append('Created a new portgroup \'{0}\' in DVS '
|
|
'\'{1}\', datacenter \'{2}\''
|
|
''.format(pg_name, dvs, datacenter))
|
|
log.info(comments[-1])
|
|
changes.update({pg_name: {'new': pg}})
|
|
else:
|
|
# Porgroup already exists. Checking the config
|
|
log.trace('Portgroup \'{0}\' found in DVS \'{1}\', datacenter '
|
|
'\'{2}\'. Checking for any updates.'
|
|
''.format(pg_name, dvs, datacenter))
|
|
current_pg = filtered_current_pgs[0]
|
|
diff_dict = _get_diff_dict(current_pg, pg)
|
|
|
|
if diff_dict:
|
|
changes_required = True
|
|
if __opts__['test']:
|
|
changes_strings = \
|
|
_get_changes_from_diff_dict(diff_dict)
|
|
log.trace('changes_strings = '
|
|
'{0}'.format(changes_strings))
|
|
comments.append(
|
|
'State {0} will update portgroup \'{1}\' in '
|
|
'DVS \'{2}\', datacenter \'{3}\':\n{4}'
|
|
''.format(name, pg_name, dvs, datacenter,
|
|
'\n'.join(['\t{0}'.format(c) for c in
|
|
changes_strings])))
|
|
else:
|
|
__salt__['vsphere.update_dvportgroup'](
|
|
portgroup_dict=pg, portgroup=pg_name, dvs=dvs,
|
|
service_instance=si)
|
|
comments.append('Updated portgroup \'{0}\' in DVS '
|
|
'\'{1}\', datacenter \'{2}\''
|
|
''.format(pg_name, dvs, datacenter))
|
|
log.info(comments[-1])
|
|
changes.update(
|
|
{pg_name: {'new':
|
|
_get_val2_dict_from_diff_dict(diff_dict),
|
|
'old':
|
|
_get_val1_dict_from_diff_dict(diff_dict)}})
|
|
# Add the uplink portgroup to the expected pg names
|
|
uplink_pg = __salt__['vsphere.list_uplink_dvportgroup'](
|
|
dvs=dvs, service_instance=si)
|
|
expected_pg_names.append(uplink_pg['name'])
|
|
# Remove any extra portgroups
|
|
for current_pg in current_pgs:
|
|
if current_pg['name'] not in expected_pg_names:
|
|
changes_required = True
|
|
if __opts__['test']:
|
|
comments.append('State {0} will remove '
|
|
'the portgroup \'{1}\' from DVS \'{2}\', '
|
|
'datacenter \'{3}\''
|
|
''.format(name, current_pg['name'], dvs,
|
|
datacenter))
|
|
else:
|
|
__salt__['vsphere.remove_dvportgroup'](
|
|
portgroup=current_pg['name'], dvs=dvs,
|
|
service_instance=si)
|
|
comments.append('Removed the portgroup \'{0}\' from DVS '
|
|
'\'{1}\', datacenter \'{2}\''
|
|
''.format(current_pg['name'], dvs,
|
|
datacenter))
|
|
log.info(comments[-1])
|
|
changes.update({current_pg['name']:
|
|
{'old': current_pg}})
|
|
__salt__['vsphere.disconnect'](si)
|
|
except salt.exceptions.CommandExecutionError as exc:
|
|
log.error('Error: {0}\n{1}'.format(exc, traceback.format_exc()))
|
|
if si:
|
|
__salt__['vsphere.disconnect'](si)
|
|
if not __opts__['test']:
|
|
ret['result'] = False
|
|
ret.update({'comment': exc.strerror,
|
|
'result': False if not __opts__['test'] else None})
|
|
return ret
|
|
if not changes_required:
|
|
# We have no changes
|
|
ret.update({'comment': ('All portgroups in DVS \'{0}\', datacenter '
|
|
'\'{1}\' exist and are correctly configured. '
|
|
'Nothing to be done.'.format(dvs, datacenter)),
|
|
'result': True})
|
|
else:
|
|
ret.update({
|
|
'comment': '\n'.join(comments),
|
|
'changes': changes,
|
|
'result': None if __opts__['test'] else True,
|
|
})
|
|
return ret
|
|
|
|
|
|
def uplink_portgroup_configured(name, dvs, uplink_portgroup):
|
|
'''
|
|
Configures the uplink portgroup on a DVS. The state assumes there is only
|
|
one uplink portgroup.
|
|
|
|
dvs
|
|
Name of the DVS
|
|
|
|
upling_portgroup
|
|
Uplink portgroup dict representations (see module sysdocs)
|
|
|
|
'''
|
|
datacenter = _get_datacenter_name()
|
|
log.info('Running {0} on DVS \'{1}\', datacenter \'{2}\''
|
|
''.format(name, dvs, datacenter))
|
|
changes_required = False
|
|
ret = {'name': name,
|
|
'changes': {},
|
|
'result': None,
|
|
'comment': None}
|
|
comments = []
|
|
changes = {}
|
|
changes_required = False
|
|
|
|
try:
|
|
#TODO portroups validation
|
|
si = __salt__['vsphere.get_service_instance_via_proxy']()
|
|
current_uplink_portgroup = __salt__['vsphere.list_uplink_dvportgroup'](
|
|
dvs=dvs, service_instance=si)
|
|
log.trace('current_uplink_portgroup = '
|
|
'{0}'.format(current_uplink_portgroup))
|
|
diff_dict = _get_diff_dict(current_uplink_portgroup, uplink_portgroup)
|
|
if diff_dict:
|
|
changes_required = True
|
|
if __opts__['test']:
|
|
changes_strings = \
|
|
_get_changes_from_diff_dict(diff_dict)
|
|
log.trace('changes_strings = '
|
|
'{0}'.format(changes_strings))
|
|
comments.append(
|
|
'State {0} will update the '
|
|
'uplink portgroup in DVS \'{1}\', datacenter '
|
|
'\'{2}\':\n{3}'
|
|
''.format(name, dvs, datacenter,
|
|
'\n'.join(['\t{0}'.format(c) for c in
|
|
changes_strings])))
|
|
else:
|
|
__salt__['vsphere.update_dvportgroup'](
|
|
portgroup_dict=uplink_portgroup,
|
|
portgroup=current_uplink_portgroup['name'],
|
|
dvs=dvs,
|
|
service_instance=si)
|
|
comments.append('Updated the uplink portgroup in DVS '
|
|
'\'{0}\', datacenter \'{1}\''
|
|
''.format(dvs, datacenter))
|
|
log.info(comments[-1])
|
|
changes.update(
|
|
{'uplink_portgroup':
|
|
{'new': _get_val2_dict_from_diff_dict(diff_dict),
|
|
'old': _get_val1_dict_from_diff_dict(diff_dict)}})
|
|
__salt__['vsphere.disconnect'](si)
|
|
except salt.exceptions.CommandExecutionError as exc:
|
|
log.error('Error: {0}\n{1}'.format(exc, traceback.format_exc()))
|
|
if si:
|
|
__salt__['vsphere.disconnect'](si)
|
|
if not __opts__['test']:
|
|
ret['result'] = False
|
|
ret.update({'comment': exc.strerror,
|
|
'result': False if not __opts__['test'] else None})
|
|
return ret
|
|
if not changes_required:
|
|
# We have no changes
|
|
ret.update({'comment': ('Uplink portgroup in DVS \'{0}\', datacenter '
|
|
'\'{1}\' is correctly configured. '
|
|
'Nothing to be done.'.format(dvs, datacenter)),
|
|
'result': True})
|
|
else:
|
|
ret.update({
|
|
'comment': '\n'.join(comments),
|
|
'changes': changes,
|
|
'result': None if __opts__['test'] else True,
|
|
})
|
|
return ret
|