コード例 #1
0
 def setUp(self):
     old_dict = {
         "a": {"b": 1, "c": 2, "e": "old_value", "f": "old_key"},
         "j": "value",
     }
     new_dict = {
         "a": {"b": 1, "c": 4, "e": "new_value", "g": "new_key"},
         "h": "new_key",
         "i": None,
         "j": "value",
     }
     self.recursive_diff = dictdiffer.recursive_diff(
         old_dict, new_dict, ignore_missing_keys=False
     )
     self.recursive_diff_ign = dictdiffer.recursive_diff(old_dict, new_dict)
コード例 #2
0
 def _get_recursive_difference(self, type):
     '''Returns the recursive diff between dict values'''
     if type == 'intersect':
         return [
             recursive_diff(item['old'], item['new'])
             for item in self._intersect
         ]
     elif type == 'added':
         return [recursive_diff({}, item) for item in self._added]
     elif type == 'removed':
         return [
             recursive_diff(item, {}, ignore_missing_keys=False)
             for item in self._removed
         ]
     elif type == 'all':
         recursive_list = []
         recursive_list.extend([
             recursive_diff(item['old'], item['new'])
             for item in self._intersect
         ])
         recursive_list.extend(
             [recursive_diff({}, item) for item in self._added])
         recursive_list.extend([
             recursive_diff(item, {}, ignore_missing_keys=False)
             for item in self._removed
         ])
         return recursive_list
     else:
         raise ValueError('The given type for recursive list matching '
                          'is not supported.')
コード例 #3
0
ファイル: pbm.py プロジェクト: arizvisa/saltstack-salt
def default_vsan_policy_configured(name, policy):
    """
    Configures the default VSAN policy on a vCenter.
    The state assumes there is only one default VSAN policy on a vCenter.

    policy
        Dict representation of a policy
    """
    # TODO Refactor when recurse_differ supports list_differ
    # It's going to make the whole thing much easier
    policy_copy = copy.deepcopy(policy)
    proxy_type = __salt__["vsphere.get_proxy_type"]()
    log.trace("proxy_type = {0}".format(proxy_type))
    # All allowed proxies have a shim execution module with the same
    # name which implementes a get_details function
    # All allowed proxies have a vcenter detail
    vcenter = __salt__["{0}.get_details".format(proxy_type)]()["vcenter"]
    log.info("Running {0} on vCenter " "'{1}'".format(name, vcenter))
    log.trace("policy = {0}".format(policy))
    changes_required = False
    ret = {"name": name, "changes": {}, "result": None, "comment": None}
    comments = []
    changes = {}
    changes_required = False
    si = None

    try:
        # TODO policy schema validation
        si = __salt__["vsphere.get_service_instance_via_proxy"]()
        current_policy = __salt__["vsphere.list_default_vsan_policy"](si)
        log.trace("current_policy = {0}".format(current_policy))
        # Building all diffs between the current and expected policy
        # XXX We simplify the comparison by assuming we have at most 1
        # sub_profile
        if policy.get("subprofiles"):
            if len(policy["subprofiles"]) > 1:
                raise ArgumentValueError("Multiple sub_profiles ({0}) are not "
                                         "supported in the input policy")
            subprofile = policy["subprofiles"][0]
            current_subprofile = current_policy["subprofiles"][0]
            capabilities_differ = list_diff(
                current_subprofile["capabilities"],
                subprofile.get("capabilities", []),
                key="id",
            )
            del policy["subprofiles"]
            if subprofile.get("capabilities"):
                del subprofile["capabilities"]
            del current_subprofile["capabilities"]
            # Get the subprofile diffs without the capability keys
            subprofile_differ = recursive_diff(current_subprofile,
                                               dict(subprofile))

        del current_policy["subprofiles"]
        policy_differ = recursive_diff(current_policy, policy)
        if policy_differ.diffs or capabilities_differ.diffs or subprofile_differ.diffs:

            if ("name" in policy_differ.new_values
                    or "description" in policy_differ.new_values):

                raise ArgumentValueError(
                    "'name' and 'description' of the default VSAN policy "
                    "cannot be updated")
            changes_required = True
            if __opts__["test"]:
                str_changes = []
                if policy_differ.diffs:
                    str_changes.extend([
                        change
                        for change in policy_differ.changes_str.split("\n")
                    ])
                if subprofile_differ.diffs or capabilities_differ.diffs:
                    str_changes.append("subprofiles:")
                    if subprofile_differ.diffs:
                        str_changes.extend([
                            "  {0}".format(change) for change in
                            subprofile_differ.changes_str.split("\n")
                        ])
                    if capabilities_differ.diffs:
                        str_changes.append("  capabilities:")
                        str_changes.extend([
                            "  {0}".format(change) for change in
                            capabilities_differ.changes_str2.split("\n")
                        ])
                comments.append(
                    "State {0} will update the default VSAN policy on "
                    "vCenter '{1}':\n{2}"
                    "".format(name, vcenter, "\n".join(str_changes)))
            else:
                __salt__["vsphere.update_storage_policy"](
                    policy=current_policy["name"],
                    policy_dict=policy_copy,
                    service_instance=si,
                )
                comments.append("Updated the default VSAN policy in vCenter "
                                "'{0}'".format(vcenter))
            log.info(comments[-1])

            new_values = policy_differ.new_values
            new_values["subprofiles"] = [subprofile_differ.new_values]
            new_values["subprofiles"][0][
                "capabilities"] = capabilities_differ.new_values
            if not new_values["subprofiles"][0]["capabilities"]:
                del new_values["subprofiles"][0]["capabilities"]
            if not new_values["subprofiles"][0]:
                del new_values["subprofiles"]
            old_values = policy_differ.old_values
            old_values["subprofiles"] = [subprofile_differ.old_values]
            old_values["subprofiles"][0][
                "capabilities"] = capabilities_differ.old_values
            if not old_values["subprofiles"][0]["capabilities"]:
                del old_values["subprofiles"][0]["capabilities"]
            if not old_values["subprofiles"][0]:
                del old_values["subprofiles"]
            changes.update({
                "default_vsan_policy": {
                    "new": new_values,
                    "old": old_values
                }
            })
            log.trace(changes)
        __salt__["vsphere.disconnect"](si)
    except CommandExecutionError as exc:
        log.error("Error: {}".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": ("Default VSAN policy in vCenter "
                        "'{0}' is correctly configured. "
                        "Nothing to be done.".format(vcenter)),
            "result":
            True,
        })
    else:
        ret.update({
            "comment": "\n".join(comments),
            "changes": changes,
            "result": None if __opts__["test"] else True,
        })
    return ret
コード例 #4
0
ファイル: pbm.py プロジェクト: morinap/salt-1
def storage_policies_configured(name, policies):
    '''
    Configures storage policies on a vCenter.

    policies
        List of dict representation of the required storage policies
    '''
    comments = []
    changes = []
    changes_required = False
    ret = {'name': name, 'changes': {}, 'result': None, 'comment': None}
    log.trace('policies = %s', policies)
    si = None
    try:
        proxy_type = __salt__['vsphere.get_proxy_type']()
        log.trace('proxy_type = %s', proxy_type)
        # All allowed proxies have a shim execution module with the same
        # name which implementes a get_details function
        # All allowed proxies have a vcenter detail
        vcenter = __salt__['{0}.get_details'.format(proxy_type)]()['vcenter']
        log.info('Running state \'%s\' on vCenter \'%s\'', name, vcenter)
        si = __salt__['vsphere.get_service_instance_via_proxy']()
        current_policies = __salt__['vsphere.list_storage_policies'](
            policy_names=[policy['name'] for policy in policies],
            service_instance=si)
        log.trace('current_policies = %s', current_policies)
        # TODO Refactor when recurse_differ supports list_differ
        # It's going to make the whole thing much easier
        for policy in policies:
            policy_copy = copy.deepcopy(policy)
            filtered_policies = [
                p for p in current_policies if p['name'] == policy['name']
            ]
            current_policy = filtered_policies[0] \
                    if filtered_policies else None

            if not current_policy:
                changes_required = True
                if __opts__['test']:
                    comments.append('State {0} will create the storage policy '
                                    '\'{1}\' on vCenter \'{2}\''
                                    ''.format(name, policy['name'], vcenter))
                else:
                    __salt__['vsphere.create_storage_policy'](
                        policy['name'], policy, service_instance=si)
                    comments.append('Created storage policy \'{0}\' on '
                                    'vCenter \'{1}\''.format(
                                        policy['name'], vcenter))
                    changes.append({'new': policy, 'old': None})
                log.trace(comments[-1])
                # Continue with next
                continue

            # Building all diffs between the current and expected policy
            # XXX We simplify the comparison by assuming we have at most 1
            # sub_profile
            if policy.get('subprofiles'):
                if len(policy['subprofiles']) > 1:
                    raise ArgumentValueError(
                        'Multiple sub_profiles ({0}) are not '
                        'supported in the input policy')
                subprofile = policy['subprofiles'][0]
                current_subprofile = current_policy['subprofiles'][0]
                capabilities_differ = list_diff(
                    current_subprofile['capabilities'],
                    subprofile.get('capabilities', []),
                    key='id')
                del policy['subprofiles']
                if subprofile.get('capabilities'):
                    del subprofile['capabilities']
                del current_subprofile['capabilities']
                # Get the subprofile diffs without the capability keys
                subprofile_differ = recursive_diff(current_subprofile,
                                                   dict(subprofile))

            del current_policy['subprofiles']
            policy_differ = recursive_diff(current_policy, policy)
            if policy_differ.diffs or capabilities_differ.diffs or \
               subprofile_differ.diffs:

                changes_required = True
                if __opts__['test']:
                    str_changes = []
                    if policy_differ.diffs:
                        str_changes.extend([
                            change
                            for change in policy_differ.changes_str.split('\n')
                        ])
                    if subprofile_differ.diffs or \
                        capabilities_differ.diffs:

                        str_changes.append('subprofiles:')
                        if subprofile_differ.diffs:
                            str_changes.extend([
                                '  {0}'.format(change) for change in
                                subprofile_differ.changes_str.split('\n')
                            ])
                        if capabilities_differ.diffs:
                            str_changes.append('  capabilities:')
                            str_changes.extend([
                                '  {0}'.format(change) for change in
                                capabilities_differ.changes_str2.split('\n')
                            ])
                    comments.append(
                        'State {0} will update the storage policy \'{1}\''
                        ' on vCenter \'{2}\':\n{3}'
                        ''.format(name, policy['name'], vcenter,
                                  '\n'.join(str_changes)))
                else:
                    __salt__['vsphere.update_storage_policy'](
                        policy=current_policy['name'],
                        policy_dict=policy_copy,
                        service_instance=si)
                    comments.append('Updated the storage policy \'{0}\''
                                    'in vCenter \'{1}\''
                                    ''.format(policy['name'], vcenter))
                log.info(comments[-1])

                # Build new/old values to report what was changed
                new_values = policy_differ.new_values
                new_values['subprofiles'] = [subprofile_differ.new_values]
                new_values['subprofiles'][0]['capabilities'] = \
                        capabilities_differ.new_values
                if not new_values['subprofiles'][0]['capabilities']:
                    del new_values['subprofiles'][0]['capabilities']
                if not new_values['subprofiles'][0]:
                    del new_values['subprofiles']
                old_values = policy_differ.old_values
                old_values['subprofiles'] = [subprofile_differ.old_values]
                old_values['subprofiles'][0]['capabilities'] = \
                        capabilities_differ.old_values
                if not old_values['subprofiles'][0]['capabilities']:
                    del old_values['subprofiles'][0]['capabilities']
                if not old_values['subprofiles'][0]:
                    del old_values['subprofiles']
                changes.append({'new': new_values, 'old': old_values})
            else:
                # No diffs found - no updates required
                comments.append('Storage policy \'{0}\' is up to date. '
                                'Nothing to be done.'.format(policy['name']))
        __salt__['vsphere.disconnect'](si)
    except CommandExecutionError as exc:
        log.error('Error: %s', 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 storage policy in vCenter '
                        '\'{0}\' is correctly configured. '
                        'Nothing to be done.'.format(vcenter)),
            'result':
            True
        })
    else:
        ret.update({
            'comment': '\n'.join(comments),
            'changes': {
                'storage_policies': changes
            },
            'result': None if __opts__['test'] else True,
        })
    return ret
コード例 #5
0
ファイル: pbm.py プロジェクト: morinap/salt-1
def default_vsan_policy_configured(name, policy):
    '''
    Configures the default VSAN policy on a vCenter.
    The state assumes there is only one default VSAN policy on a vCenter.

    policy
        Dict representation of a policy
    '''
    # TODO Refactor when recurse_differ supports list_differ
    # It's going to make the whole thing much easier
    policy_copy = copy.deepcopy(policy)
    proxy_type = __salt__['vsphere.get_proxy_type']()
    log.trace('proxy_type = %s', proxy_type)
    # All allowed proxies have a shim execution module with the same
    # name which implementes a get_details function
    # All allowed proxies have a vcenter detail
    vcenter = __salt__['{0}.get_details'.format(proxy_type)]()['vcenter']
    log.info('Running %s on vCenter \'%s\'', name, vcenter)
    log.trace('policy = %s', policy)
    changes_required = False
    ret = {'name': name, 'changes': {}, 'result': None, 'comment': None}
    comments = []
    changes = {}
    changes_required = False
    si = None

    try:
        #TODO policy schema validation
        si = __salt__['vsphere.get_service_instance_via_proxy']()
        current_policy = __salt__['vsphere.list_default_vsan_policy'](si)
        log.trace('current_policy = %s', current_policy)
        # Building all diffs between the current and expected policy
        # XXX We simplify the comparison by assuming we have at most 1
        # sub_profile
        if policy.get('subprofiles'):
            if len(policy['subprofiles']) > 1:
                raise ArgumentValueError('Multiple sub_profiles ({0}) are not '
                                         'supported in the input policy')
            subprofile = policy['subprofiles'][0]
            current_subprofile = current_policy['subprofiles'][0]
            capabilities_differ = list_diff(current_subprofile['capabilities'],
                                            subprofile.get('capabilities', []),
                                            key='id')
            del policy['subprofiles']
            if subprofile.get('capabilities'):
                del subprofile['capabilities']
            del current_subprofile['capabilities']
            # Get the subprofile diffs without the capability keys
            subprofile_differ = recursive_diff(current_subprofile,
                                               dict(subprofile))

        del current_policy['subprofiles']
        policy_differ = recursive_diff(current_policy, policy)
        if policy_differ.diffs or capabilities_differ.diffs or \
           subprofile_differ.diffs:

            if 'name' in policy_differ.new_values or \
               'description' in policy_differ.new_values:

                raise ArgumentValueError(
                    '\'name\' and \'description\' of the default VSAN policy '
                    'cannot be updated')
            changes_required = True
            if __opts__['test']:
                str_changes = []
                if policy_differ.diffs:
                    str_changes.extend([
                        change
                        for change in policy_differ.changes_str.split('\n')
                    ])
                if subprofile_differ.diffs or capabilities_differ.diffs:
                    str_changes.append('subprofiles:')
                    if subprofile_differ.diffs:
                        str_changes.extend([
                            '  {0}'.format(change) for change in
                            subprofile_differ.changes_str.split('\n')
                        ])
                    if capabilities_differ.diffs:
                        str_changes.append('  capabilities:')
                        str_changes.extend([
                            '  {0}'.format(change) for change in
                            capabilities_differ.changes_str2.split('\n')
                        ])
                comments.append(
                    'State {0} will update the default VSAN policy on '
                    'vCenter \'{1}\':\n{2}'
                    ''.format(name, vcenter, '\n'.join(str_changes)))
            else:
                __salt__['vsphere.update_storage_policy'](
                    policy=current_policy['name'],
                    policy_dict=policy_copy,
                    service_instance=si)
                comments.append('Updated the default VSAN policy in vCenter '
                                '\'{0}\''.format(vcenter))
            log.info(comments[-1])

            new_values = policy_differ.new_values
            new_values['subprofiles'] = [subprofile_differ.new_values]
            new_values['subprofiles'][0]['capabilities'] = \
                    capabilities_differ.new_values
            if not new_values['subprofiles'][0]['capabilities']:
                del new_values['subprofiles'][0]['capabilities']
            if not new_values['subprofiles'][0]:
                del new_values['subprofiles']
            old_values = policy_differ.old_values
            old_values['subprofiles'] = [subprofile_differ.old_values]
            old_values['subprofiles'][0]['capabilities'] = \
                    capabilities_differ.old_values
            if not old_values['subprofiles'][0]['capabilities']:
                del old_values['subprofiles'][0]['capabilities']
            if not old_values['subprofiles'][0]:
                del old_values['subprofiles']
            changes.update({
                'default_vsan_policy': {
                    'new': new_values,
                    'old': old_values
                }
            })
            log.trace(changes)
        __salt__['vsphere.disconnect'](si)
    except CommandExecutionError as exc:
        log.error('Error: %s', 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': ('Default VSAN policy in vCenter '
                        '\'{0}\' is correctly configured. '
                        'Nothing to be done.'.format(vcenter)),
            'result':
            True
        })
    else:
        ret.update({
            'comment': '\n'.join(comments),
            'changes': changes,
            'result': None if __opts__['test'] else True,
        })
    return ret
コード例 #6
0
def cluster_configured(name, cluster_config):
    '''
    Configures a cluster. Creates a new cluster, if it doesn't exist on the
    vCenter or reconfigures it if configured differently

    Supported proxies: esxdatacenter, esxcluster

    name
        Name of the state. If the state is run in by an ``esxdatacenter``
        proxy, it will be the name of the cluster.

    cluster_config
        Configuration applied to the cluster.
        Complex datastructure following the ESXClusterConfigSchema.
        Valid example is:

    .. code-block::yaml

        drs:
            default_vm_behavior: fullyAutomated
            enabled: true
            vmotion_rate: 3
        ha:
            admission_control
            _enabled: false
            default_vm_settings:
                isolation_response: powerOff
                restart_priority: medium
            enabled: true
            hb_ds_candidate_policy: userSelectedDs
            host_monitoring: enabled
            options:
                - key: das.ignoreinsufficienthbdatastore
                  value: 'true'
            vm_monitoring: vmMonitoringDisabled
        vm_swap_placement: vmDirectory
        vsan:
            auto_claim_storage: false
            compression_enabled: true
            dedup_enabled: true
            enabled: true

    '''
    proxy_type = __salt__['vsphere.get_proxy_type']()
    if proxy_type == 'esxdatacenter':
        cluster_name, datacenter_name = \
                name, __salt__['esxdatacenter.get_details']()['datacenter']
    elif proxy_type == 'esxcluster':
        cluster_name, datacenter_name = \
                __salt__['esxcluster.get_details']()['cluster'], \
                __salt__['esxcluster.get_details']()['datacenter']
    else:
        raise salt.exceptions.CommandExecutionError('Unsupported proxy {0}'
                                                    ''.format(proxy_type))
    log.info('Running {0} for cluster \'{1}\' in datacenter '
             '\'{2}\''.format(name, cluster_name, datacenter_name))
    cluster_dict = cluster_config
    log.trace('cluster_dict =  {0}'.format(cluster_dict))
    changes_required = False
    ret = {'name': name,
           'changes': {}, 'result': None, 'comment': 'Default'}
    comments = []
    changes = {}
    changes_required = False

    try:
        log.trace('Validating cluster_configured state input')
        schema = ESXClusterConfigSchema.serialize()
        log.trace('schema = {0}'.format(schema))
        try:
            jsonschema.validate(cluster_dict, schema)
        except jsonschema.exceptions.ValidationError as exc:
            raise salt.exceptions.InvalidESXClusterPayloadError(exc)
        current = None
        si = __salt__['vsphere.get_service_instance_via_proxy']()
        try:
            current = __salt__['vsphere.list_cluster'](datacenter_name,
                                                       cluster_name,
                                                       service_instance=si)
        except salt.exceptions.VMwareObjectRetrievalError:
            changes_required = True
            if __opts__['test']:
                comments.append('State {0} will create cluster '
                                '\'{1}\' in datacenter \'{2}\'.'
                                ''.format(name, cluster_name, datacenter_name))
                log.info(comments[-1])
                __salt__['vsphere.disconnect'](si)
                ret.update({'result': None,
                            'comment': '\n'.join(comments)})
                return ret
            log.trace('Creating cluster \'{0}\' in datacenter \'{1}\'. '
                      ''.format(cluster_name, datacenter_name))
            __salt__['vsphere.create_cluster'](cluster_dict,
                                               datacenter_name,
                                               cluster_name,
                                               service_instance=si)
            comments.append('Created cluster \'{0}\' in datacenter \'{1}\''
                            ''.format(cluster_name, datacenter_name))
            log.info(comments[-1])
            changes.update({'new': cluster_dict})
        if current:
            # Cluster already exists
            # We need to handle lists sepparately
            ldiff = None
            if 'ha' in cluster_dict and 'options' in cluster_dict['ha']:
                ldiff = list_diff(current.get('ha', {}).get('options', []),
                                  cluster_dict.get('ha', {}).get('options', []),
                                  'key')
                log.trace('options diffs = {0}'.format(ldiff.diffs))
                # Remove options if exist
                del cluster_dict['ha']['options']
                if 'ha' in current and 'options' in current['ha']:
                    del current['ha']['options']
            diff = recursive_diff(current, cluster_dict)
            log.trace('diffs = {0}'.format(diff.diffs))
            if not (diff.diffs or (ldiff and ldiff.diffs)):
                # No differences
                comments.append('Cluster \'{0}\' in datacenter \'{1}\' is up '
                                'to date. Nothing to be done.'
                                ''.format(cluster_name, datacenter_name))
                log.info(comments[-1])
            else:
                changes_required = True
                changes_str = ''
                if diff.diffs:
                    changes_str = '{0}{1}'.format(changes_str,
                                                  diff.changes_str)
                if ldiff and ldiff.diffs:
                    changes_str = '{0}\nha:\n  options:\n{1}'.format(
                        changes_str,
                        '\n'.join(['  {0}'.format(l) for l in
                                   ldiff.changes_str2.split('\n')]))
                # Apply the changes
                if __opts__['test']:
                    comments.append(
                        'State {0} will update cluster \'{1}\' '
                        'in datacenter \'{2}\':\n{3}'
                        ''.format(name, cluster_name,
                                  datacenter_name, changes_str))
                else:
                    new_values = diff.new_values
                    old_values = diff.old_values
                    if ldiff and ldiff.new_values:
                        dictupdate.update(
                            new_values, {'ha': {'options': ldiff.new_values}})
                    if ldiff and ldiff.old_values:
                        dictupdate.update(
                            old_values, {'ha': {'options': ldiff.old_values}})
                    log.trace('new_values = {0}'.format(new_values))
                    __salt__['vsphere.update_cluster'](new_values,
                                                       datacenter_name,
                                                       cluster_name,
                                                       service_instance=si)
                    comments.append('Updated cluster \'{0}\' in datacenter '
                                    '\'{1}\''.format(cluster_name,
                                                     datacenter_name))
                    log.info(comments[-1])
                    changes.update({'new': new_values,
                                    'old': old_values})
        __salt__['vsphere.disconnect'](si)
        ret_status = True
        if __opts__['test'] and changes_required:
            ret_status = None
        ret.update({'result': ret_status,
                    'comment': '\n'.join(comments),
                    'changes': changes})
        return ret
    except salt.exceptions.CommandExecutionError as exc:
        log.error('Error: {0}\n{1}'.format(exc, traceback.format_exc()))
        if si:
            __salt__['vsphere.disconnect'](si)
        ret.update({
            'result': False,
            'comment': six.text_type(exc)})
        return ret