Beispiel #1
0
def bridge_create(br, may_exist=True, parent=None, vlan=None):
    '''
    Creates a new bridge.

    Args:
        br: A string - bridge name
        may_exist: Bool, if False - attempting to create a bridge that exists returns False.
        parent: String, the name of the parent bridge (if the bridge shall be
            created as a fake bridge). If specified, vlan must also be
            specified.
        vlan: Int, the VLAN ID of the bridge (if the bridge shall be created as
            a fake bridge). If specified, parent must also be specified.

    Returns:
        True on success, else False.

    .. versionadded:: 2016.3.0

    CLI Example:
    .. code-block:: bash

        salt '*' openvswitch.bridge_create br0
    '''
    param_may_exist = _param_may_exist(may_exist)
    if parent is not None and vlan is None:
        raise ArgumentValueError(
            'If parent is specified, vlan must also be specified.')
    if vlan is not None and parent is None:
        raise ArgumentValueError(
            'If vlan is specified, parent must also be specified.')
    param_parent = '' if parent is None else ' {0}'.format(parent)
    param_vlan = '' if vlan is None else ' {0}'.format(vlan)
    cmd = 'ovs-vsctl {1}add-br {0}{2}{3}'.format(br, param_may_exist, param_parent,
                                           param_vlan)
    result = __salt__['cmd.run_all'](cmd)
    return _retcode_to_bool(result['retcode'])
Beispiel #2
0
def _get_files(name=False, type="states", return_type="args") -> List:
    """
    Determine if modules/states directories or files are requested

    return_type = names ==  names_only=True
    return_type = args == names_only=Fals
    return_type = docs
    """
    dirs = []
    found_files = []

    if type == "modules":
        dirs.append(os.path.join(__opts__["extension_modules"], "modules"))
        dirs.append(os.path.join(__grains__["saltpath"], "modules"))
    elif type == "states":
        dirs.append(os.path.join(__opts__["extension_modules"], "states"))
        dirs.append(os.path.join(__grains__["saltpath"], "states"))

    if name:
        if "." in name:
            if return_type != "docs":
                # Only docs support module.function syntax
                raise ArgumentValueError("Function name given")
            else:
                name = name.split(".")[0]
        for dir in dirs:
            # Process custom dirs first so custom results are returned
            file_path = os.path.join(dir, name + ".py")
            if os.path.exists(file_path):
                found_files.append(file_path)
                return found_files
    else:
        for dir in reversed(dirs):
            # Process custom dirs last so they are displayed
            try:
                for module_py in os.listdir(dir):
                    if module_py.endswith(
                            ".py") and module_py != "__init__.py":
                        found_files.append(os.path.join(dir, module_py))
            except FileNotFoundError:
                pass
    return found_files
Beispiel #3
0
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 = {0}".format(policies))
    si = None
    try:
        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 state '{0}' on vCenter "
                 "'{1}'".format(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 = {0}".format(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: {0}".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 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
Beispiel #4
0
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
Beispiel #5
0
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
Beispiel #6
0
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