Example #1
0
def ensure_present(params, check_mode):
    """
    Ensure that the HBA exists and has the specified properties.

    Raises:
      ParameterError: An issue with the module parameters.
      StatusError: An issue with the partition status.
      zhmcclient.Error: Any zhmcclient exception can happen.
    """

    host = params['hmc_host']
    userid, password = get_hmc_auth(params['hmc_auth'])
    cpc_name = params['cpc_name']
    partition_name = params['partition_name']
    hba_name = params['name']
    _faked_session = params.get('_faked_session', None)

    changed = False
    result = {}

    try:
        session = get_session(_faked_session, host, userid, password)
        client = zhmcclient.Client(session)
        cpc = client.cpcs.find(name=cpc_name)
        # The default exception handling is sufficient for the above.

        try:
            partition = cpc.partitions.find(name=partition_name)
        except zhmcclient.NotFound:
            if check_mode:
                # Once the partition is created, the HBA will also need to be
                # created. Therefore, we set changed.
                changed = True
                return changed, result
            raise

        try:
            hba = partition.hbas.find(name=hba_name)
            hba.pull_full_properties()
        except zhmcclient.NotFound:
            hba = None

        if not hba:
            # It does not exist. Create it and update it if there are
            # update-only properties.
            if not check_mode:
                create_props, update_props, stop = process_properties(
                    partition, hba, params)
                hba = partition.hbas.create(create_props)
                update2_props = {}
                for name in update_props:
                    if name not in create_props:
                        update2_props[name] = update_props[name]
                if update2_props:
                    hba.update_properties(update2_props)
                # We refresh the properties after the update, in case an
                # input property value gets changed (for example, the
                # partition does that with memory properties).
                hba.pull_full_properties()
            else:
                # TODO: Show props in module result also in check mode.
                pass
            changed = True
        else:
            # It exists. Stop the partition if needed due to the HBA property
            # update requirements, or wait for an updateable partition status,
            # and update the HBA properties.
            create_props, update_props, stop = process_properties(
                partition, hba, params)
            if update_props:
                if not check_mode:
                    # HBA properties can all be updated while the partition is
                    # active, therefore:
                    if stop:
                        raise AssertionError()

                    wait_for_transition_completion(partition)
                    hba.update_properties(update_props)
                    # We refresh the properties after the update, in case an
                    # input property value gets changed (for example, the
                    # partition does that with memory properties).
                    hba.pull_full_properties()
                else:
                    # TODO: Show updated props in mod.result also in chk.mode
                    pass
                changed = True

        if hba:
            result = hba.properties

        return changed, result

    finally:
        session.logoff()
def ensure_present(params, check_mode):
    """
    Ensure that the user role exists and has the specified properties.

    Raises:
      ParameterError: An issue with the module parameters.
      zhmcclient.Error: Any zhmcclient exception can happen.
    """

    host = params['hmc_host']
    userid, password, ca_certs, verify = get_hmc_auth(params['hmc_auth'])
    urole_name = params['name']
    _faked_session = params.get('_faked_session', None)

    changed = False
    result = {}

    session = get_session(
        _faked_session, host, userid, password, ca_certs, verify)
    try:
        client = zhmcclient.Client(session)
        console = client.consoles.console
        # The default exception handling is sufficient for the above.

        try:
            urole = console.user_roles.find(name=urole_name)
        except zhmcclient.NotFound:
            urole = None

        if urole is None:
            # It does not exist. Create it and update it if there are
            # update-only properties.
            create_props, update_props, cur_perms, add_perms, rem_perms = \
                process_properties(client, urole, params)
            update2_props = {}
            for name, value in update_props.items():
                if name not in create_props:
                    update2_props[name] = value
            if not check_mode:
                urole = console.user_roles.create(create_props)
                if update2_props:
                    urole.update_properties(update2_props)
                # We refresh the properties after the update, in case an
                # input property value gets changed.
                urole.pull_full_properties()
            else:
                # Create a User Role object locally
                urole = create_check_mode_urole(
                    client, create_props, update2_props)
            result = dict(urole.properties)
            changed = True

            for perm_key in rem_perms:
                opt_kwargs, obj = rem_perms[perm_key]
                if obj is None:  # resource class
                    kwargs = dict(permitted_object=perm_key)
                else:
                    kwargs = dict(permitted_object=obj)
                kwargs.update(opt_kwargs)
                LOGGER.debug(
                    "Removing permission %r from user role %r",
                    kwargs, urole_name)
                if not check_mode:
                    urole.remove_permission(**kwargs)
                del cur_perms[perm_key]
            for perm_key in add_perms:
                opt_kwargs, obj = add_perms[perm_key]
                if obj is None:  # resource class
                    kwargs = dict(permitted_object=perm_key)
                else:
                    kwargs = dict(permitted_object=obj)
                kwargs.update(opt_kwargs)
                LOGGER.debug(
                    "Adding permission %r to user role %r",
                    kwargs, urole_name)
                if not check_mode:
                    urole.add_permission(**kwargs)
                cur_perms[perm_key] = add_perms[perm_key]

        else:
            # It exists. Update its properties.
            urole.pull_full_properties()
            result = dict(urole.properties)
            create_props, update_props, cur_perms, add_perms, rem_perms = \
                process_properties(client, urole, params)
            if update_props:
                LOGGER.debug(
                    "Existing user role %r needs to get properties "
                    "updated: %r", urole_name, update_props)
                if not check_mode:
                    urole.update_properties(update_props)
                    # We refresh the properties after the update, in case an
                    # input property value gets changed.
                    urole.pull_full_properties()
                    result = dict(urole.properties)
                else:
                    # Update the local User Role object's properties
                    result.update(update_props)
                changed = True

                for perm_key in rem_perms:
                    opt_kwargs, obj = rem_perms[perm_key]
                    if obj is None:  # resource class
                        kwargs = dict(permitted_object=perm_key)
                    else:
                        kwargs = dict(permitted_object=obj)
                    kwargs.update(opt_kwargs)
                    LOGGER.debug(
                        "Removing permission %r from user role %r",
                        kwargs, urole_name)
                    if not check_mode:
                        urole.remove_permission(**kwargs)
                    del cur_perms[perm_key]
                for perm_key in add_perms:
                    opt_kwargs, obj = add_perms[perm_key]
                    if obj is None:  # resource class
                        kwargs = dict(permitted_object=perm_key)
                    else:
                        kwargs = dict(permitted_object=obj)
                    kwargs.update(opt_kwargs)
                    LOGGER.debug(
                        "Adding permission %r to user role %r",
                        kwargs, urole_name)
                    if not check_mode:
                        urole.add_permission(**kwargs)
                    cur_perms[perm_key] = add_perms[perm_key]

        if not urole:
            raise AssertionError()

        # Process artificial properties

        result['permissions'] = result_permissions(cur_perms)

        sys_urole_uri = result['associated-system-defined-user-role-uri']
        if sys_urole_uri:
            sys_urole_name = urole_uri_to_name(console, sys_urole_uri)
        else:
            sys_urole_name = None
        result['associated-system-defined-user-role-name'] = sys_urole_name

        return changed, result

    finally:
        session.logoff()
def perform_list(params):
    """
    List the partitions and return a subset of properties.

    Raises:
      ParameterError: An issue with the module parameters.
      zhmcclient.Error: Any zhmcclient exception can happen.
    """

    host = params['hmc_host']
    userid, password, ca_certs, verify = get_hmc_auth(params['hmc_auth'])
    cpc_name = params.get('cpc_name', None)
    _faked_session = params.get('_faked_session', None)  # No default specified

    session = get_session(_faked_session, host, userid, password, ca_certs,
                          verify)
    try:
        client = zhmcclient.Client(session)

        # The "List Permitted Partitions" operation was added in HMC
        # version 2.14.0. The operation depends only on the HMC version and not
        # on the SE/CPC version, so it is supported e.g. for a 2.14 HMC managing
        # a z13 CPC.
        hmc_version = client.query_api_version()['hmc-version']
        hmc_version_info = [int(x) for x in hmc_version.split('.')]
        if hmc_version_info < [2, 14, 0]:
            # List the partitions in the traditional way
            if cpc_name:
                LOGGER.debug("Listing partitions of CPC %s", cpc_name)
                cpc = client.cpcs.find(name=cpc_name)
                partitions = cpc.partitions.list()
            else:
                LOGGER.debug("Listing partitions of all managed CPCs")
                cpcs = client.cpcs.list()
                partitions = []
                for cpc in cpcs:
                    partitions.extend(cpc.partitions.list())
        else:
            # List the partitions using the new operation
            if cpc_name:
                LOGGER.debug("Listing permitted partitions of CPC %s",
                             cpc_name)
                filter_args = {'cpc-name': cpc_name}
            else:
                LOGGER.debug(
                    "Listing permitted partitions of all managed CPCs")
                filter_args = None
            partitions = client.consoles.console.list_permitted_partitions(
                filter_args=filter_args)
        # The default exception handling is sufficient for the above.

        se_versions = {}
        partition_list = []
        for partition in partitions:

            # se-version has been added to the result of List Permitted
            # Partitions in HMC/SE 2.14.1. Before that, it triggers the
            # retrieval of CPC properties.
            parent_cpc = partition.manager.cpc
            try:
                se_version = se_versions[parent_cpc.name]
            except KeyError:
                try:
                    se_version = partition.properties['se-version']
                except KeyError:
                    se_version = parent_cpc.get_property('se-version')
                se_versions[parent_cpc.name] = se_version

            partition_properties = {
                "name":
                partition.name,
                "cpc_name":
                parent_cpc.name,
                "se_version":
                se_version,
                "status":
                partition.get_property('status'),
                "has_unacceptable_status":
                partition.get_property('has-unacceptable-status'),
            }
            partition_list.append(partition_properties)

        return partition_list

    finally:
        session.logoff()
def ensure_present(params, check_mode):
    """
    Ensure that the storage group exists and has the specified properties.

    Storage volumes are not subject of this function, they are handled by the
    zhmc_storage_volume.py module.

    Raises:
      ParameterError: An issue with the module parameters.
      zhmcclient.Error: Any zhmcclient exception can happen.
    """

    host = params['hmc_host']
    userid, password, ca_certs, verify = get_hmc_auth(params['hmc_auth'])
    cpc_name = params['cpc_name']
    storage_group_name = params['name']
    expand = params['expand']
    _faked_session = params.get('_faked_session', None)

    changed = False
    result = {}

    session = get_session(_faked_session, host, userid, password, ca_certs,
                          verify)
    try:
        client = zhmcclient.Client(session)
        console = client.consoles.console
        cpc = client.cpcs.find(name=cpc_name)
        # The default exception handling is sufficient for the above.

        try:
            storage_group = console.storage_groups.find(
                name=storage_group_name)
        except zhmcclient.NotFound:
            storage_group = None

        if storage_group is None:
            # It does not exist. Create it and update it if there are
            # update-only properties.
            if not check_mode:
                create_props, update_props = \
                    process_properties(cpc, storage_group, params)
                storage_group = console.storage_groups.create(create_props)
                update2_props = {}
                for name, value in update_props.items():
                    if name not in create_props:
                        update2_props[name] = value
                if update2_props:
                    storage_group.update_properties(update2_props)
                # We refresh the properties after the update, in case an
                # input property value gets changed.
                storage_group.pull_full_properties()
            else:
                # TODO: Show props in module result also in check mode.
                pass
            changed = True
        else:
            # It exists. Update its properties.
            storage_group.pull_full_properties()
            create_props, update_props = \
                process_properties(cpc, storage_group, params)
            if create_props:
                raise AssertionError("Unexpected "
                                     "create_props: %r" % create_props)
            if update_props:
                if not check_mode:
                    storage_group.update_properties(update_props)
                    # We refresh the properties after the update, in case an
                    # input property value gets changed.
                    storage_group.pull_full_properties()
                else:
                    # TODO: Show updated props in mod.result also in chk.mode
                    pass
                changed = True

        if not check_mode:
            if not storage_group:
                raise AssertionError()
            result = dict(storage_group.properties)
            add_artificial_properties(result, storage_group, expand)

        return changed, result

    finally:
        session.logoff()
def ensure_detached(params, check_mode):
    """
    Ensure that the target partition has no adapters and no domains attached.

    Raises:
      ParameterError: An issue with the module parameters.
      Error: Other errors during processing.
      zhmcclient.Error: Any zhmcclient exception can happen.
    """

    # Note: Defaults specified in argument_spec will be set in params dict
    host = params['hmc_host']
    userid, password = get_hmc_auth(params['hmc_auth'])
    cpc_name = params['cpc_name']
    partition_name = params['partition_name']
    faked_session = params.get('faked_session', None)  # No default specified

    changed = False
    result = dict()
    result_changes = dict()

    try:
        session = get_session(faked_session, host, userid, password)
        client = zhmcclient.Client(session)
        cpc = client.cpcs.find(name=cpc_name)
        partition = cpc.partitions.find(name=partition_name)
        # The default exception handling is sufficient for the above.

        # Determine all crypto adapters of any crypto type
        filter_args = {
            'adapter-family': 'crypto',
        }
        all_adapters = cpc.adapters.list(filter_args=filter_args,
                                         full_properties=True)

        cc = partition.get_property('crypto-configuration')
        # The 'crypto-configuration' property is None or:
        # {
        #   'crypto-adapter-uris': ['/api/...', ...],
        #   'crypto-domain-configurations': [
        #     {'domain-index': 15, 'access-mode': 'control-usage'},
        #     ...
        #   ]
        # }
        if cc:
            attached_adapter_uris = cc['crypto-adapter-uris']
            remove_adapters = []
            remove_adapter_names = []
            for a in all_adapters:
                if a.uri in attached_adapter_uris:
                    remove_adapters.append(a)
                    remove_adapter_names.append(a.name)

            remove_domains = []
            for dc in cc['crypto-domain-configurations']:
                di = dc['domain-index']
                remove_domains.append(di)

            LOGGER.debug(
                "Detaching adapters {!r} and domains {!r} from target "
                "partition {!r}".format(remove_adapter_names, remove_domains,
                                        partition.name))

            if not check_mode:
                try:
                    partition.decrease_crypto_config(remove_adapters,
                                                     remove_domains)
                except zhmcclient.Error as exc:
                    raise Error(
                        "Detaching adapters {!r} and domains {!r} from "
                        "target partition {!r} failed: {}".format(
                            remove_adapter_names, remove_domains,
                            partition.name, exc))

            changed = True
            result_changes['removed-adapters'] = remove_adapter_names
            result_changes['removed-domains'] = remove_domains

        if not check_mode:
            # This is not optimal because it does not produce a result
            # in check mode, but because the actual config is determined,
            # instead of the artificially calculated one, it seems better
            # to return no config than the unchanged actual config.
            result.update(get_partition_config(partition, all_adapters))

        return changed, result, result_changes

    finally:
        session.logoff()
def test_zhmc_password_rule_absent_present(ansible_mod_cls, desc,
                                           initial_pwrule_props, input_state,
                                           input_props, exp_pwrule_props,
                                           exp_changed, check_mode,
                                           hmc_session):  # noqa: F811, E501
    """
    Test the zhmc_password_rule module with state=absent/present.
    """

    hd = hmc_session.hmc_definition
    hmc_host = hd.host
    hmc_auth = dict(userid=hd.userid,
                    password=hd.password,
                    ca_certs=hd.ca_certs,
                    verify=hd.verify)

    faked_session = hmc_session if hd.mock_file else None

    client = zhmcclient.Client(hmc_session)
    console = client.consoles.console

    # Create a password rule name that does not exist
    pwrule_name = new_pwrule_name()

    where = "password rule '{u}'".format(u=pwrule_name)

    # Create initial password rule, if specified so
    if initial_pwrule_props is not None:
        pwrule_props = STD_PWRULE_PROPERTIES.copy()
        pwrule_props.update(initial_pwrule_props)
        pwrule_props['name'] = pwrule_name
        try:
            console.password_rules.create(pwrule_props)
        except zhmcclient.HTTPError as exc:
            if exc.http_status == 403 and exc.reason == 1:
                # User is not permitted to create password rules
                pytest.skip("HMC user '{u}' is not permitted to create "
                            "initial test password rule".format(u=hd.userid))
    else:
        pwrule_props = None

    try:

        # Prepare module input parameters (must be all required + optional)
        params = {
            'hmc_host': hmc_host,
            'hmc_auth': hmc_auth,
            'name': pwrule_name,
            'state': input_state,
            'log_file': LOG_FILE,
            '_faked_session': faked_session,
        }
        if input_props is not None:
            params['properties'] = input_props
        else:
            params['properties'] = {}

        mod_obj = mock_ansible_module(ansible_mod_cls, params, check_mode)

        # Exercise the code to be tested
        with pytest.raises(SystemExit) as exc_info:
            zhmc_password_rule.main()
        exit_code = exc_info.value.args[0]

        assert exit_code == 0, \
            "{w}: Module failed with exit code {e} and message:\n{m}". \
            format(w=where, e=exit_code, m=get_failure_msg(mod_obj))

        changed, output_props = get_module_output(mod_obj)
        if changed != exp_changed:
            pwrule_props_sorted = \
                OrderedDict(sorted(pwrule_props.items(), key=lambda x: x[0])) \
                if pwrule_props is not None else None
            input_props_sorted = \
                OrderedDict(sorted(input_props.items(), key=lambda x: x[0])) \
                if input_props is not None else None
            output_props_sorted = \
                OrderedDict(sorted(output_props.items(), key=lambda x: x[0])) \
                if output_props is not None else None
            raise AssertionError(
                "Unexpected change flag returned: actual: {0}, expected: {1}\n"
                "Initial password rule properties:\n{2}\n"
                "Module input properties:\n{3}\n"
                "Resulting password rule properties:\n{4}".format(
                    changed, exp_changed,
                    pformat(pwrule_props_sorted.items(), indent=2),
                    pformat(input_props_sorted.items(), indent=2),
                    pformat(output_props_sorted.items(), indent=2)))
        if input_state == 'present':
            assert_pwrule_props(output_props, where)

    finally:
        # Delete password rule, if it exists
        try:
            # We invalidate the name cache of our client, because the password rule
            # was possibly deleted by the Ansible module and not through our
            # client instance.
            console.password_rules.invalidate_cache()
            pwrule = console.password_rules.find_by_name(pwrule_name)
        except zhmcclient.NotFound:
            pwrule = None
        if pwrule:
            pwrule.delete()
def ensure_stopped(params, check_mode):
    """
    Ensure that the partition exists, is stopped, and has the specified
    properties.

    Raises:
      ParameterError: An issue with the module parameters.
      StatusError: An issue with the partition status.
      zhmcclient.Error: Any zhmcclient exception can happen.
    """

    host = params['hmc_host']
    userid, password = get_hmc_auth(params['hmc_auth'])
    cpc_name = params['cpc_name']
    partition_name = params['name']
    faked_session = params.get('faked_session', None)

    changed = False
    result = {}

    try:
        session = get_session(faked_session, host, userid, password)
        client = zhmcclient.Client(session)
        cpc = client.cpcs.find(name=cpc_name)
        # The default exception handling is sufficient for the above.

        try:
            partition = cpc.partitions.find(name=partition_name)
            partition.pull_full_properties()
        except zhmcclient.NotFound:
            partition = None

        if not partition:
            # It does not exist. Create it and update it if there are
            # update-only properties.
            if not check_mode:
                create_props, update_props, stop, crypto_changes = \
                    process_properties(cpc, partition, params)
                partition = cpc.partitions.create(create_props)
                update2_props = {}
                for name in update_props:
                    if name not in create_props:
                        update2_props[name] = update_props[name]
                if update2_props:
                    partition.update_properties(update2_props)
                if crypto_changes:
                    change_crypto_config(partition, crypto_changes, check_mode)
            changed = True
        else:
            # It exists. Stop it and update its properties.
            create_props, update_props, stop, crypto_changes = \
                process_properties(cpc, partition, params)
            changed |= stop_partition(partition, check_mode)
            if update_props:
                if not check_mode:
                    partition.update_properties(update_props)
                changed = True
            if crypto_changes:
                changed |= change_crypto_config(partition, crypto_changes,
                                                check_mode)

        if partition and not check_mode:
            partition.pull_full_properties()
            status = partition.get_property('status')
            if status not in ('stopped'):
                raise StatusError(
                    "Could not get partition {!r} into a stopped state, "
                    "status is: {!r}".format(partition.name, status))

        if partition:
            result = partition.properties

        return changed, result

    finally:
        session.logoff()
Example #8
0
def ensure_present(params, check_mode):
    """
    Ensure that the user exists and has the specified properties.

    Raises:
      ParameterError: An issue with the module parameters.
      zhmcclient.Error: Any zhmcclient exception can happen.
    """

    host = params['hmc_host']
    userid, password, ca_certs, verify = get_hmc_auth(params['hmc_auth'])
    user_name = params['name']
    expand = params['expand']
    _faked_session = params.get('_faked_session', None)

    changed = False
    result = {}

    session = get_session(
        _faked_session, host, userid, password, ca_certs, verify)
    try:
        client = zhmcclient.Client(session)
        console = client.consoles.console
        # The default exception handling is sufficient for the above.

        try:
            user = console.users.find(name=user_name)
        except zhmcclient.NotFound:
            user = None

        if user is None:
            # It does not exist. Create it and update it if there are
            # update-only properties.
            create_props, update_props, add_roles, rem_roles = \
                process_properties(console, user, params)
            update2_props = {}
            for name, value in update_props.items():
                if name not in create_props:
                    update2_props[name] = value
            if not check_mode:
                user = console.users.create(create_props)
                if update2_props:
                    user.update_properties(update2_props)
                # We refresh the properties after the update, in case an
                # input property value gets changed.
                user.pull_full_properties()
            else:
                # Create a User object locally
                user = create_check_mode_user(
                    console, create_props, update2_props)
            result = dict(user.properties)
            changed = True
            for role in add_roles:
                LOGGER.debug(
                    "Adding role %r to user %r", role.name, user_name)
                if not check_mode:
                    user.add_user_role(role)
                if 'user-roles' not in result:
                    result['user-roles'] = []
                result['user-roles'].append(role.uri)
            if rem_roles:
                raise AssertionError(
                    "Unexpected attempt to remove user roles {0!r} from newly "
                    "created user {1!r}".format(rem_roles, user.name))
        else:
            # It exists. Update its properties.
            user.pull_full_properties()
            result = dict(user.properties)
            create_props, update_props, add_roles, rem_roles = \
                process_properties(console, user, params)
            if create_props:
                raise AssertionError("Unexpected "
                                     "create_props: %r" % create_props)
            if update_props:
                LOGGER.debug(
                    "Existing user %r needs to get properties updated: %r",
                    user_name, update_props)
                if not check_mode:
                    user.update_properties(update_props)
                    # We refresh the properties after the update, in case an
                    # input property value gets changed.
                    user.pull_full_properties()
                    result = dict(user.properties)
                else:
                    # Update the local User object's properties
                    result.update(update_props)
                changed = True
            for role in add_roles:
                LOGGER.debug(
                    "Adding role %r to user %r", role.name, user_name)
                if not check_mode:
                    user.add_user_role(role)
                if 'user-roles' not in result:
                    result['user-roles'] = []
                result['user-roles'].append(role.uri)
                changed = True
            for role in rem_roles:
                LOGGER.debug(
                    "Removing role %r from user %r", role.name, user_name)
                if not check_mode:
                    user.remove_user_role(role)
                if 'user-roles' not in result:
                    raise AssertionError(
                        "User {0!r} unexpectedly does not have a "
                        "'user-roles' property".format(user.name))
                result['user-roles'].remove(role.uri)
                changed = True

        if not user:
            raise AssertionError()

        add_artificial_properties(result, console, user, expand, check_mode)

        return changed, result

    finally:
        session.logoff()
Example #9
0
def setup_cpc(capsys, hmc_creds, fake_data, rt_config=None):
    """
    Set up and return some objects for the CPC that is to be used for testing.

    This function uses the get_test_cpc() function to determine the CPC to be
    used for testing. If no CPC has been defined, this function sets up a faked
    CPC using the zhmcclient mock support.

    Parameters:

      capsys: The pytest 'capsys' fixture the testcase function must specify as
        an argument and pass to this functionhere.

      hmc_creds (HmcCredentials): HMC credentials with CPC data.

      fake_data (dict): Input data in case a mock environment needs to be set
        up. The dict has the following keys:

        * hmc_host (string): Hostname or IP address of the faked HMC.

        * hmc_name (string): HMC name of the faked HMC.

        * hmc_version (string): HMC version of the faked HMC.

        * api_version (string): API version of the faked HMC.

        * cpc_properties (dict): Properties for the faked CPC. 'name' must be
          set.

      rt_config (zhmcclient.RetryTimeoutConfig): Retry / timeout config
        to override the default values. The default values used by this
        function are the global defaults defined for the zhmcclient package,
        whereby connection retries, connection timeout, operation timeout, and
        status timeout have been shortened. The resulting default values should
        be good for most function testcases.

    Returns:

      tuple: Tuple with the objects thathave been set up:

        * cpc_name (string): Name of the CPC to be used (some fake name or
          the real name that has been set up).

        * session (zhmcclient.Session or zhmcclient_mock-FakedSession):
          zhmcclient session object (faked or real) to be used for accessing
          the HMC managing that CPC.

        * client (zhmcclient.Client):
          zhmcclient Client object to be used for accessing the HMC managing
          that CPC.

        * cpc (zhmcclient.Cpc): Cpc resource object representing the CPC to be
          used (faked or real).

        * faked_cpc (zhmcclient_mock.FakedCpc): FakedCpc object in case a
          mock environment was set up (so the caller can add resources to it),
          or otherwise `None`.
    """

    cpc_name = get_test_cpc()

    if cpc_name is None:

        # No test CPC defined in the environment -> use mock support and
        # add a faked CPC.

        cpc_properties = fake_data['cpc_properties']
        cpc_name = cpc_properties['name']

        info(capsys, "Testing with faked CPC %r (ZHMC_TEST_CPC env.var. "
             "not set)", cpc_name)

        session = zhmcclient_mock.FakedSession(fake_data['hmc_host'],
                                               fake_data['hmc_name'],
                                               fake_data['hmc_version'],
                                               fake_data['api_version'])

        faked_cpc = session.hmc.cpcs.add(cpc_properties)

    else:
        # A test CPC is defined in the environment -> use it!

        info(capsys, "Testing with CPC %r", cpc_name)

        eff_rt_config = DEFAULT_RT_CONFIG
        if rt_config:
            eff_rt_config.override_with(rt_config)

        cpc_item = hmc_creds.get_cpc_item(cpc_name)

        assert cpc_item, "HMC credentials file not found: {!r}".\
            format(hmc_creds.filepath)

        session = zhmcclient.Session(cpc_item['hmc_host'],
                                     cpc_item['hmc_userid'],
                                     cpc_item['hmc_password'],
                                     retry_timeout_config=eff_rt_config)

        faked_cpc = None

    client = zhmcclient.Client(session)

    cpc = client.cpcs.find(name=cpc_name)

    return cpc_name, session, client, cpc, faked_cpc
def ensure_present(params, check_mode):
    """
    Ensure that the user exists and has the specified properties.

    Storage volumes are not subject of this function, they are handled by the
    zhmc_storage_volume.py module.

    Raises:
      ParameterError: An issue with the module parameters.
      zhmcclient.Error: Any zhmcclient exception can happen.
    """

    host = params['hmc_host']
    userid, password = get_hmc_auth(params['hmc_auth'])
    user_name = params['name']
    expand = params['expand']
    faked_session = params.get('faked_session', None)

    changed = False
    result = {}

    try:
        session = get_session(faked_session, host, userid, password)
        client = zhmcclient.Client(session)
        console = client.consoles.console
        # The default exception handling is sufficient for the above.

        try:
            user = console.users.find(name=user_name)
        except zhmcclient.NotFound:
            user = None

        if user is None:
            # It does not exist. Create it and update it if there are
            # update-only properties.
            create_props, update_props = process_properties(
                console, user, params)
            update2_props = {}
            for name in update_props:
                if name not in create_props:
                    update2_props[name] = update_props[name]
            if not check_mode:
                user = console.users.create(create_props)
                if update2_props:
                    user.update_properties(update2_props)
                # We refresh the properties after the update, in case an
                # input property value gets changed.
                user.pull_full_properties()
            else:
                # Create a User object locally
                user = create_check_mode_user(console, create_props,
                                              update2_props)
            changed = True
        else:
            # It exists. Update its properties.
            user.pull_full_properties()
            create_props, update_props = process_properties(
                console, user, params)
            assert not create_props, \
                "Unexpected create_props: %r" % create_props
            if update_props:
                LOGGER.debug(
                    "Existing user {!r} needs to get properties updated: {!r}".
                    format(user_name, update_props))
                if not check_mode:
                    user.update_properties(update_props)
                    # We refresh the properties after the update, in case an
                    # input property value gets changed.
                    user.pull_full_properties()
                else:
                    # Update the local User object's properties
                    user.properties.update(update_props)
                changed = True

        assert user
        add_artificial_properties(console, user, expand, check_mode)
        result = user.properties

        return changed, result

    finally:
        session.logoff()
Example #11
0
def ensure_present(params, check_mode):
    """
    Ensure that the storage volume is defined and has the specified properties.

    Raises:
      ParameterError: An issue with the module parameters.
      zhmcclient.Error: Any zhmcclient exception can happen.
    """

    host = params['hmc_host']
    userid, password, ca_certs, verify = get_hmc_auth(params['hmc_auth'])
    cpc_name = params['cpc_name']
    storage_group_name = params['storage_group_name']
    storage_volume_name = params['name']
    _faked_session = params.get('_faked_session', None)

    changed = False
    result = {}

    session = get_session(_faked_session, host, userid, password, ca_certs,
                          verify)
    try:
        client = zhmcclient.Client(session)
        console = client.consoles.console
        cpc = client.cpcs.find(name=cpc_name)
        storage_group = console.storage_groups.find(name=storage_group_name)
        # The default exception handling is sufficient for the above.

        sg_cpc = storage_group.cpc
        if sg_cpc.uri != cpc.uri:
            raise ParameterError(
                "Storage group {0!r} is not associated with the specified "
                "CPC {1!r}, but with CPC {2!r}.".format(
                    storage_group_name, cpc.name, sg_cpc.name))

        try:
            storage_volume = storage_group.storage_volumes.find(
                name=storage_volume_name)
        except zhmcclient.NotFound:
            storage_volume = None
        except zhmcclient.NoUniqueMatch:
            # The name of storage volumes within their storage group is not
            # enforced to be unique.
            raise

        if storage_volume is None:
            # It does not exist. Create it and update it if there are
            # update-only properties.
            if not check_mode:
                create_props, update_props = \
                    process_properties(cpc, storage_group, storage_volume,
                                       params)
                storage_volume = storage_group.storage_volumes.create(
                    create_props)
                update2_props = {}
                for name, value in update_props.items():
                    if name not in create_props:
                        update2_props[name] = value
                if update2_props:
                    storage_volume.update_properties(update2_props)
                # We refresh the properties after the update, in case an
                # input property value gets changed.
                storage_volume.pull_full_properties()
            else:
                # TODO: Show props in module result also in check mode.
                pass
            changed = True
        else:
            # It exists. Update its properties.
            storage_volume.pull_full_properties()
            create_props, update_props = \
                process_properties(cpc, storage_group, storage_volume, params)
            if create_props:
                raise AssertionError("Unexpected "
                                     "create_props: %r" % create_props)
            if update_props:
                if not check_mode:
                    storage_volume.update_properties(update_props)
                    # We refresh the properties after the update, in case an
                    # input property value gets changed.
                    storage_volume.pull_full_properties()
                else:
                    # TODO: Show updated props in mod.result also in chk.mode
                    storage_volume.pull_full_properties()
                changed = True

        if not check_mode:
            if not storage_volume:
                raise AssertionError()

        if storage_volume:
            result = dict(storage_volume.properties)
            add_artificial_properties(result, storage_volume)

        return changed, result

    finally:
        session.logoff()
Example #12
0
def cmd_lpar_list(cmd_ctx, cpc_name, options):
    # pylint: disable=missing-function-docstring

    client = zhmcclient.Client(cmd_ctx.session)

    if client.version_info() >= (2, 20):  # Starting with HMC 2.14.0
        # This approach is faster than going through the CPC.
        # In addition, starting with HMC API version 3.6 (an update to
        # HMC 2.15.0), this approach supports users that do not have object
        # access permission to the CPC.
        filter_args = {}
        if cpc_name:
            filter_args['cpc-name'] = cpc_name
        lpars = client.consoles.console.list_permitted_lpars(
            filter_args=filter_args)
    else:
        filter_args = {}
        if cpc_name:
            filter_args['name'] = cpc_name
        try:
            cpcs = client.cpcs.list(filter_args=filter_args)
        except zhmcclient.Error as exc:
            raise click_exception(exc, cmd_ctx.error_format)
        lpars = []
        for cpc in cpcs:
            try:
                lpars.extend(cpc.lpars.list())
            except zhmcclient.Error as exc:
                raise click_exception(exc, cmd_ctx.error_format)

    if options['type']:
        click.echo("The --type option is deprecated and type information "
                   "is now always shown.")

    # Prepare the additions dict of dicts. It contains additional
    # (=non-resource) property values by property name and by resource URI.
    # Depending on options, some of them will not be populated.
    additions = {}
    additions['cpc'] = {}

    show_list = [
        'name',
        'cpc',
    ]
    if not options['names_only']:
        show_list.extend([
            'status',
            'activation-mode',
            'os-type',
            'workload-manager-enabled',
        ])
    if options['uri']:
        show_list.extend([
            'object-uri',
        ])

    for lpar in lpars:
        cpc = lpar.manager.parent
        additions['cpc'][lpar.uri] = cpc.name

    try:
        print_resources(cmd_ctx,
                        lpars,
                        cmd_ctx.output_format,
                        show_list,
                        additions,
                        all=options['all'])
    except zhmcclient.Error as exc:
        raise click_exception(exc, cmd_ctx.error_format)
Example #13
0
def ensure_present(params, check_mode):
    """
    Ensure that the specified Hipersockets adapter exists and has the
    specified properties set.

    Raises:
      ParameterError: An issue with the module parameters.
      Error: Other errors during processing.
      zhmcclient.Error: Any zhmcclient exception can happen.
    """

    # Note: Defaults specified in argument_spec will be set in params dict
    host = params['hmc_host']
    userid, password = get_hmc_auth(params['hmc_auth'])
    cpc_name = params['cpc_name']
    adapter_name = params['name']
    faked_session = params.get('faked_session', None)  # No default specified

    changed = False

    try:
        session = get_session(faked_session, host, userid, password)
        client = zhmcclient.Client(session)
        cpc = client.cpcs.find(name=cpc_name)
        # The default exception handling is sufficient for the above.

        try:
            adapter = cpc.adapters.find(name=adapter_name)
        except zhmcclient.NotFound:
            adapter = None

        if not adapter:
            # It does not exist. The only possible adapter type
            # that can be created is a Hipersockets adapter, but before
            # creating one we check the 'type' input property to verify that
            # the intention is really Hipersockets creation, and not just a
            # mispelled name.
            input_props = params.get('properties', None)
            if input_props is None:
                adapter_type = None
            else:
                adapter_type = input_props.get('type', None)
            if adapter_type is None:
                raise ParameterError(
                    "Input property 'type' missing when creating "
                    "Hipersockets adapter {!r} (must specify 'hipersockets')".
                    format(adapter_name))
            if adapter_type != 'hipersockets':
                raise ParameterError(
                    "Input property 'type' specifies {!r} when creating "
                    "Hipersockets adapter {!r} (must specify 'hipersockets').".
                    format(adapter_type, adapter_name))

            create_props, update_props = process_properties(adapter, params)

            # This is specific to Hipersockets: There are no update-only
            # properties, so any remaining such property is an input error
            invalid_update_props = {}
            for name in update_props:
                if name not in create_props:
                    invalid_update_props[name] = update_props[name]
            if invalid_update_props:
                raise ParameterError(
                    "Invalid input properties specified when creating "
                    "Hipersockets adapter {!r}: {!r}".format(
                        adapter_name, invalid_update_props))

            # While the 'type' input property is required for verifying
            # the intention, it is not allowed as input for the
            # Create Hipersocket HMC operation.
            del create_props['type']

            if not check_mode:
                adapter = cpc.adapters.create_hipersocket(create_props)
                adapter.pull_full_properties()
                result = adapter.properties  # from actual values
            else:
                adapter = None
                result = dict()
                result.update(create_props)  # from input values
            changed = True
        else:
            # It does exist.
            # Update its properties and change adapter and crypto type, if
            # needed.

            adapter.pull_full_properties()
            result = adapter.properties

            create_props, update_props, chg_adapter_type, chg_crypto_type = \
                process_properties(adapter, params)

            if update_props:
                if not check_mode:
                    adapter.update_properties(update_props)
                else:
                    result.update(update_props)  # from input values
                changed = True

            if chg_adapter_type:
                if not check_mode:
                    adapter.change_adapter_type(chg_adapter_type)
                else:
                    result['type'] = chg_adapter_type
                changed = True

            if chg_crypto_type:
                if not check_mode:
                    adapter.change_crypto_type(chg_crypto_type)
                else:
                    result['crypto-type'] = chg_crypto_type
                changed = True

            if changed and not check_mode:
                adapter.pull_full_properties()
                result = adapter.properties  # from actual values

        if adapter:
            ports = adapter.ports.list()
            result_ports = list()
            for port in ports:
                port.pull_full_properties()
                result_ports.append(port.properties)
            result['ports'] = result_ports
        else:
            # For now, we return no ports when creating in check mode
            result['ports'] = dict()

        return changed, result

    finally:
        session.logoff()
Example #14
0
def ensure_set(params, check_mode):
    """
    Identify the target adapter (that must exist) and ensure that the specified
    properties are set on the adapter.

    Raises:
      ParameterError: An issue with the module parameters.
      Error: Other errors during processing.
      zhmcclient.Error: Any zhmcclient exception can happen.
    """

    # Note: Defaults specified in argument_spec will be set in params dict
    host = params['hmc_host']
    userid, password = get_hmc_auth(params['hmc_auth'])
    cpc_name = params['cpc_name']
    adapter_name = params['name']
    adapter_match = params['match']
    faked_session = params.get('faked_session', None)  # No default specified

    changed = False

    try:
        session = get_session(faked_session, host, userid, password)
        client = zhmcclient.Client(session)
        cpc = client.cpcs.find(name=cpc_name)
        adapter = identify_adapter(cpc, adapter_name, adapter_match)
        # The default exception handling is sufficient for the above.

        adapter.pull_full_properties()
        result = adapter.properties

        # It was identified by name or match properties, so it does exist.
        # Update its properties and change adapter and crypto type, if
        # needed.
        create_props, update_props, chg_adapter_type, chg_crypto_type = \
            process_properties(adapter, params)

        if update_props:
            if not check_mode:
                adapter.update_properties(update_props)
            else:
                result.update(update_props)  # from input values
            changed = True

        if chg_adapter_type:
            if not check_mode:
                adapter.change_adapter_type(chg_adapter_type)
            else:
                result['type'] = chg_adapter_type
            changed = True

        if chg_crypto_type:
            if not check_mode:
                adapter.change_crypto_type(chg_crypto_type)
            else:
                result['crypto-type'] = chg_crypto_type
            changed = True

        if changed and not check_mode:
            adapter.pull_full_properties()
            result = adapter.properties  # from actual values

        ports = adapter.ports.list()
        result_ports = list()
        for port in ports:
            # TODO: Disabling the following line mitigates the recent issue
            #       with HTTP error 404,4 when retrieving port properties.
            # port.pull_full_properties()
            result_ports.append(port.properties)
        result['ports'] = result_ports

        return changed, result

    finally:
        session.logoff()
Example #15
0
def cmd_character_rule_add(cmd_ctx, password_rule_name, options):
    # pylint: disable=missing-function-docstring

    client = zhmcclient.Client(cmd_ctx.session)
    console = client.consoles.console

    password_rule = find_password_rule(cmd_ctx, console, password_rule_name)
    character_rules = password_rule.get_property('character-rules')
    size = len(character_rules)

    before = options.pop('before')
    after = options.pop('after')
    last = options.pop('last')
    if (bool(before is not None) + bool(after is not None) + last) > 1:
        raise click.ClickException(
            "Only one of --before, --after and --last can be specified.")

    name_map = {
        'min': 'min-characters',
        'max': 'max-characters',
        'custom': None,
    }

    org_options = original_options(options)
    cr_properties = options_to_properties(org_options, name_map)

    # Add custom-character-sets array
    custom_char_sets = []
    for chars, control in options['custom']:
        custom_char_set = {
            'character-set': chars,
            'inclusion': control,
        }
        custom_char_sets.append(custom_char_set)
    cr_properties['custom-character-sets'] = custom_char_sets

    new_character_rules = list(character_rules)
    if before is not None:
        if before < 0 or before >= max(size, 1):
            raise click.ClickException(
                "Invalid --before index {i} for character rules of password "
                "rule '{r}'".format(i=before, r=password_rule_name))
        new_character_rules.insert(before, cr_properties)
    elif after is not None:
        if after < 0 or after >= max(size, 1):
            raise click.ClickException(
                "Invalid --after index {i} for character rules of password "
                "rule '{r}'".format(i=after, r=password_rule_name))
        new_character_rules.insert(after + 1, cr_properties)
    else:  # last = default
        new_character_rules.insert(size, cr_properties)

    properties = {'character-rules': new_character_rules}

    try:
        password_rule.update_properties(properties)
    except zhmcclient.Error as exc:
        raise click_exception(exc, cmd_ctx.error_format)

    cmd_ctx.spinner.stop()
    where = 'after' if after is not None else 'before'
    index = after if after is not None else before
    click.echo("Password rule '{r}' has been updated to add character rule "
               "{w} index {i}.".format(r=password_rule_name, w=where, i=index))
Example #16
0
def cmd_nic_update(cmd_ctx, cpc_name, partition_name, nic_name, options):

    client = zhmcclient.Client(cmd_ctx.session)
    nic = find_nic(cmd_ctx, client, cpc_name, partition_name, nic_name)

    name_map = {
        # The following options are handled in this function:
        'adapter': None,
        'port': None,
        'virtual-switch': None,
    }
    options = original_options(options)
    properties = options_to_properties(options, name_map)

    required_roce_option_names = (
        'adapter',
        'port')
    if any([options[name] for name in required_roce_option_names]):
        missing_option_names = [name for name in required_roce_option_names
                                if options[name] is None]
        if missing_option_names:
            raise_click_exception("ROCE adapter specified, but misses the "
                                  "following options: %s" %
                                  ', '.join(missing_option_names),
                                  cmd_ctx.error_format)

        adapter_name = options['adapter']
        try:
            adapter = nic.manager.partition.manager.cpc.adapters.find(
                name=adapter_name)
        except zhmcclient.NotFound:
            raise_click_exception("Could not find adapter %s in CPC %s." %
                                  (adapter_name, cpc_name),
                                  cmd_ctx.error_format)

        port_name = options['port']
        try:
            port = adapter.ports.find(name=port_name)
        except zhmcclient.NotFound:
            raise_click_exception("Could not find port %s on adapter %s in "
                                  "CPC %s." %
                                  (port_name, adapter_name, cpc_name),
                                  cmd_ctx.error_format)
        properties['network-adapter-port-uri'] = port.uri

    elif options['virtual-switch'] is not None:
        vswitch_name = options['virtual-switch']
        try:
            vswitch = nic.manager.partition.manager.cpc.virtual_switches.find(
                name=vswitch_name)
        except zhmcclient.NotFound:
            raise_click_exception("Could not find virtual switch %s in "
                                  "CPC %s." %
                                  (vswitch_name, cpc_name),
                                  cmd_ctx.error_format)
        properties['virtual-switch-uri'] = vswitch.uri
    else:
        # The backing adapter port or virtual switch is not being updated.
        pass

    if not properties:
        cmd_ctx.spinner.stop()
        click.echo("No properties specified for updating NIC %s." % nic_name)
        return

    try:
        nic.update_properties(properties)
    except zhmcclient.Error as exc:
        raise_click_exception(exc, cmd_ctx.error_format)

    cmd_ctx.spinner.stop()
    if 'name' in properties and properties['name'] != nic_name:
        click.echo("NIC %s has been renamed to %s and was updated." %
                   (nic_name, properties['name']))
    else:
        click.echo("NIC %s has been updated." % nic_name)
def create_metrics_context(session, yaml_metric_groups, hmc_version):
    """
    Creating a context is mandatory for reading metrics from the Z HMC.
    Takes the session, the metric_groups dictionary from the metrics YAML file
    for fetch/do not fetch information, and the name of the YAML file for error
    output.

    Returns a tuple(context, resources), where context is the metric context
      and resources is a dict(key: metric group name, value: list of
      auto-enabled resource objects for the metric group).

    Raises: zhmccclient exceptions
    """
    fetched_hmc_metric_groups = []
    fetched_res_metric_groups = []
    for metric_group in yaml_metric_groups:
        mg_dict = yaml_metric_groups[metric_group]
        mg_type = mg_dict.get("type", 'hmc')
        # fetch is required in the metrics schema:
        fetch = mg_dict["fetch"]
        # if is optional in the metrics schema:
        if fetch and "if" in mg_dict:
            fetch = eval_condition(mg_dict["if"], hmc_version)
        if fetch:
            if mg_type == 'hmc':
                fetched_hmc_metric_groups.append(metric_group)
            else:
                assert mg_type == 'resource'  # ensured by enum
                fetched_res_metric_groups.append(metric_group)

    client = zhmcclient.Client(session)

    verbose("Creating a metrics context on the HMC for HMC metric groups:")
    for metric_group in fetched_hmc_metric_groups:
        verbose("  {}".format(metric_group))
    context = client.metrics_contexts.create({
        "anticipated-frequency-seconds":
        15,
        "metric-groups":
        fetched_hmc_metric_groups
    })

    verbose("Retrieving resources from the HMC for resource metric groups:")
    resources = {}
    for metric_group in fetched_res_metric_groups:
        verbose("  {}".format(metric_group))
        try:
            resource_path = yaml_metric_groups[metric_group]['resource']
        except KeyError:
            new_exc = ImproperExit(
                "Missing 'resource' item in resource metric group {} in "
                "metrics file".format(metric_group))
            new_exc.__cause__ = None  # pylint: disable=invalid-name
            raise new_exc
        if resource_path == 'cpc':
            resources[metric_group] = []
            cpcs = client.cpcs.list()
            for cpc in cpcs:
                verbose("Enabling auto-update for CPC {}".format(cpc.name))
                cpc.enable_auto_update()
                resources[metric_group].append(cpc)
        elif resource_path == 'cpc.partition':
            resources[metric_group] = []
            cpcs = client.cpcs.list()
            for cpc in cpcs:
                partitions = cpc.partitions.list()
                for partition in partitions:
                    verbose("Enabling auto-update for partition {}.{}".format(
                        cpc.name, partition.name))
                    partition.enable_auto_update()
                    resources[metric_group].append(partition)
        elif resource_path == 'cpc.logical-partition':
            resources[metric_group] = []
            cpcs = client.cpcs.list()
            for cpc in cpcs:
                lpars = cpc.lpars.list()
                for lpar in lpars:
                    verbose("Enabling auto-update for LPAR {}.{}".format(
                        cpc.name, lpar.name))
                    lpar.enable_auto_update()
                    resources[metric_group].append(lpar)
        else:
            new_exc = ImproperExit(
                "Invalid 'resource' item in resource metric group {} in "
                "metrics file: {}".format(metric_group, resource_path))
            new_exc.__cause__ = None  # pylint: disable=invalid-name
            raise new_exc

    return context, resources
Example #18
0
def test_zhmc_partition_list(ansible_mod_cls, check_mode, with_cpc,
                             dpm_mode_cpcs):  # noqa: F811, E501
    """
    Test the zhmc_partition_list module with DPM mode CPCs.
    """
    if not dpm_mode_cpcs:
        pytest.skip("HMC definition does not include any CPCs in DPM mode")

    for cpc in dpm_mode_cpcs:
        assert cpc.dpm_enabled

        session = cpc.manager.session
        hd = session.hmc_definition
        hmc_host = hd.host
        hmc_auth = dict(userid=hd.userid,
                        password=hd.password,
                        ca_certs=hd.ca_certs,
                        verify=hd.verify)

        client = zhmcclient.Client(session)
        console = client.consoles.console

        faked_session = session if hd.mock_file else None

        # Determine the expected partitions on the HMC
        if DEBUG:
            print("Debug: Listing expected partitions")
        hmc_version = client.query_api_version()['hmc-version']
        hmc_version_info = [int(x) for x in hmc_version.split('.')]
        if hmc_version_info < [2, 14, 0]:
            # List the LPARs in the traditional way
            if with_cpc:
                exp_partitions = cpc.partitions.list()
            else:
                cpcs_ = client.cpcs.list()
                exp_partitions = []
                for cpc_ in cpcs_:
                    exp_partitions.extend(cpc_.partitions.list())
        else:
            # List the LPARs using the new operation
            if with_cpc:
                filter_args = {'cpc-name': cpc.name}
            else:
                filter_args = None
            exp_partitions = console.list_permitted_partitions(
                filter_args=filter_args)
        exp_partition_dict = {}
        se_versions = {}
        for partition in exp_partitions:
            if DEBUG:
                print("Debug: Getting expected properties of partition {p!r} "
                      "on CPC {c!r}".format(p=partition.name, c=cpc.name))
            partition.pull_full_properties()
            cpc = partition.manager.parent
            try:
                se_version = se_versions[cpc.name]
            except KeyError:
                if DEBUG:
                    print("Debug: Getting expected se-version of CPC {c!r}".
                          format(c=cpc.name))
                se_version = cpc.get_property('se-version')
                se_versions[cpc.name] = se_version
            exp_properties = {}
            exp_properties.update(partition.properties)
            exp_properties['cpc-name'] = cpc.name
            exp_properties['se-version'] = se_version
            exp_cpc_part_name = (cpc.name, partition.name)
            exp_partition_dict[exp_cpc_part_name] = exp_properties

        # Prepare module input parameters (must be all required + optional)
        params = {
            'hmc_host': hmc_host,
            'hmc_auth': hmc_auth,
            'log_file': LOG_FILE,
            '_faked_session': faked_session,
        }
        if with_cpc:
            params['cpc_name'] = cpc.name

        # Prepare mocks for AnsibleModule object
        mod_obj = mock_ansible_module(ansible_mod_cls, params, check_mode)

        # Exercise the code to be tested
        with pytest.raises(SystemExit) as exc_info:
            zhmc_partition_list.main()
        exit_code = exc_info.value.args[0]

        # Assert module exit code
        assert exit_code == 0, \
            "Module failed with exit code {e} and message:\n{m}". \
            format(e=exit_code, m=get_failure_msg(mod_obj))

        # Assert module output
        changed, partition_list = get_module_output(mod_obj)
        assert changed is False

        assert_partition_list(partition_list, exp_partition_dict)
def ensure_active(params, check_mode):
    """
    Ensure that the partition exists, is active or degraded, and has the
    specified properties.

    Raises:
      ParameterError: An issue with the module parameters.
      StatusError: An issue with the partition status.
      zhmcclient.Error: Any zhmcclient exception can happen.
    """

    host = params['hmc_host']
    userid, password = get_hmc_auth(params['hmc_auth'])
    cpc_name = params['cpc_name']
    partition_name = params['name']
    faked_session = params.get('faked_session', None)

    changed = False
    result = {}

    try:
        session = get_session(faked_session, host, userid, password)
        client = zhmcclient.Client(session)
        cpc = client.cpcs.find(name=cpc_name)
        # The default exception handling is sufficient for the above.

        try:
            partition = cpc.partitions.find(name=partition_name)
            partition.pull_full_properties()
        except zhmcclient.NotFound:
            partition = None

        if not partition:
            # It does not exist. Create it and update it if there are
            # update-only properties.
            if not check_mode:
                create_props, update_props, stop, crypto_changes = \
                    process_properties(cpc, partition, params)
                partition = cpc.partitions.create(create_props)
                update2_props = {}
                for name in update_props:
                    if name not in create_props:
                        update2_props[name] = update_props[name]
                if update2_props:
                    partition.update_properties(update2_props)
                # We refresh the properties after the update, in case an
                # input property value gets changed (for example, the
                # partition does that with memory properties).
                partition.pull_full_properties()
                if crypto_changes:
                    change_crypto_config(partition, crypto_changes, check_mode)
            else:
                # TODO: Show props in module result also in check mode.
                pass
            changed = True
        else:
            # It exists. Stop if needed due to property update requirements,
            # or wait for an updateable partition status, and update its
            # properties.
            create_props, update_props, stop, crypto_changes = \
                process_properties(cpc, partition, params)
            if update_props:
                if not check_mode:
                    if stop:
                        stop_partition(partition, check_mode)
                    else:
                        wait_for_transition_completion(partition)
                    partition.update_properties(update_props)
                    # We refresh the properties after the update, in case an
                    # input property value gets changed (for example, the
                    # partition does that with memory properties).
                    partition.pull_full_properties()
                else:
                    # TODO: Show updated props in mod.result also in chk.mode
                    pass
                changed = True
            if crypto_changes:
                changed |= change_crypto_config(partition, crypto_changes,
                                                check_mode)

        if partition:
            changed |= start_partition(partition, check_mode)

        if partition and not check_mode:
            partition.pull_full_properties()
            status = partition.get_property('status')
            if status not in ('active', 'degraded'):
                raise StatusError(
                    "Could not get partition {!r} into an active state, "
                    "status is: {!r}".format(partition.name, status))

        if partition:
            result = partition.properties

        return changed, result

    finally:
        session.logoff()
Example #20
0
def cmd_vstorageresource_list(cmd_ctx, stogrp_name, options):
    # pylint: disable=missing-function-docstring

    client = zhmcclient.Client(cmd_ctx.session)
    stogrp = find_storagegroup(cmd_ctx, client, stogrp_name)
    cpc = stogrp.cpc

    try:
        vsrs = stogrp.virtual_storage_resources.list()
    except zhmcclient.Error as exc:
        raise click_exception(exc, cmd_ctx.error_format)

    show_list = [
        'name',
        'storagegroup',
    ]
    if not options['names_only']:
        show_list.extend([
            'device-number',
            'partition',
            'adapter',
            'port',
            'wwpn',
            'wwpn-status',
        ])
    if options['uri']:
        show_list.extend([
            'element-uri',
        ])

    sg_additions = {}
    partition_additions = {}
    adapter_additions = {}
    port_additions = {}
    wwpn_additions = {}
    wwpn_status_additions = {}
    for vsr in vsrs:
        try:
            sg_additions[vsr.uri] = stogrp_name
            partition_uri = vsr.prop('partition-uri')
            partition = cpc.partitions.find(**{'object-uri': partition_uri})
            partition_additions[vsr.uri] = partition.name
            port_uri = vsr.prop('adapter-port-uri')
            adapter_uri = re.match(r'^(.*)/storage-ports/.*$', port_uri). \
                group(1)
            adapter = cpc.adapters.find(**{'object-uri': adapter_uri})
            port = adapter.ports.find(**{'element-uri': port_uri})
            adapter_additions[vsr.uri] = adapter.name
            port_additions[vsr.uri] = port.name
            wwpn_info = vsr.prop('world-wide-port-name-info')
            wwpn_additions[vsr.uri] = wwpn_info['world-wide-port-name']
            wwpn_status_additions[vsr.uri] = wwpn_info['status']
        except zhmcclient.Error as exc:
            raise click_exception(exc, cmd_ctx.error_format)

    additions = {
        'storagegroup': sg_additions,
        'partition': partition_additions,
        'adapter': adapter_additions,
        'port': port_additions,
        'wwpn': wwpn_additions,
        'wwpn-status': wwpn_status_additions,
    }

    try:
        print_resources(cmd_ctx,
                        vsrs,
                        cmd_ctx.output_format,
                        show_list,
                        additions,
                        all=options['all'])
    except zhmcclient.Error as exc:
        raise click_exception(exc, cmd_ctx.error_format)
Example #21
0
cred = hmccreds.get(hmc, None)
if cred is None:
    print("Credentials for HMC %s not found in credentials file %s" %
          (hmc, hmccreds_file))
    sys.exit(1)

userid = cred['userid']
password = cred['password']

try:
    print(__doc__)

    print("Using HMC %s with userid %s ..." % (hmc, userid))
    session = zhmcclient.Session(hmc, userid, password)
    cl = zhmcclient.Client(session)

    timestats = example.get("timestats", None)
    if timestats:
        session.time_stats_keeper.enable()

    metric_groups = [
        'cpc-usage-overview',  # Only in classic mode
        'logical-partition-usage',  # Only in classic mode
        'channel-usage',  # Only in classic mode
        'dpm-system-usage-overview',  # Only in DPM mode
        'partition-usage',  # Only in DPM mode
        'adapter-usage',  # Only in DPM mode
        'crypto-usage',  # Only in DPM mode
        'flash-memory-usage',  # Only in DPM mode
        'roce-usage',  # Only in DPM mode
def test_user_absent_present(ansible_mod_cls, desc, initial_user_props,
                             initial_related_names, input_state, input_props,
                             exp_user_props, exp_changed, check_mode,
                             hmc_session):  # noqa: F811, E501
    """
    Test the zhmc_user module with all combinations of absent & present state.
    """
    expand = False  # Expansion is tested elsewhere
    hd = hmc_session.hmc_definition
    client = zhmcclient.Client(hmc_session)
    console = client.consoles.console

    # Create a user name that does not exist
    user_name = new_user_name()

    # Create initial user, if specified so
    if initial_user_props is not None:
        user_props = STD_USER_PROPERTIES.copy()
        user_props.update(initial_user_props)
        user_props['name'] = user_name
        if user_props['authentication-type'] == 'local':
            assert 'password' in user_props
            assert 'password_rule_name' in initial_related_names
            password_rule_name = initial_related_names['password_rule_name']
            password_rule = console.password_rules.find_by_name(
                password_rule_name)
            user_props['password-rule-uri'] = password_rule.uri
        if user_props['authentication-type'] == 'ldap':
            assert 'ldap_server_definition_name' in initial_related_names
            ldap_srv_def_name = \
                initial_related_names['ldap_server_definition_name']
            ldap_srv_def = console.ldap_server_definitions.find_by_name(
                ldap_srv_def_name)
            user_props['ldap-server-definition-uri'] = ldap_srv_def.uri
        console.users.create(user_props)
    else:
        user_props = None

    try:

        params = {
            'hmc_host': hd.hmc_host,
            'hmc_auth': dict(userid=hd.hmc_userid, password=hd.hmc_password),
            'name': user_name,
            'state': input_state,
            'expand': expand,
            'log_file': LOG_FILE,
            'faked_session': None,
        }
        if input_props is not None:
            params['properties'] = input_props

        mod_obj = mock_ansible_module(ansible_mod_cls, params, check_mode)

        # Exercise the code to be tested
        with pytest.raises(SystemExit) as exc_info:
            zhmc_user.main()
        exit_code = exc_info.value.args[0]

        assert exit_code == 0, \
            "Module unexpectedly failed with this message:\n{}". \
            format(get_failure_msg(mod_obj))

        changed, output_props = get_module_output(mod_obj)
        if changed != exp_changed:
            user_props_sorted = \
                OrderedDict(sorted(user_props.items(), key=lambda x: x[0])) \
                if user_props is not None else None
            input_props_sorted = \
                OrderedDict(sorted(input_props.items(), key=lambda x: x[0])) \
                if input_props is not None else None
            output_props_sorted = \
                OrderedDict(sorted(output_props.items(), key=lambda x: x[0])) \
                if output_props is not None else None
            raise AssertionError(
                "Unexpected change flag returned: actual: {}, expected: {}\n"
                "Initial user properties:\n{}\n"
                "Module input properties:\n{}\n"
                "Resulting user properties:\n{}".format(
                    changed, exp_changed,
                    pformat(user_props_sorted.items(), indent=2),
                    pformat(input_props_sorted.items(), indent=2),
                    pformat(output_props_sorted.items(), indent=2)))
        if input_state == 'present':
            assert_user_props(output_props, expand)

    finally:
        # Delete user, if it exists
        try:
            # We invalidate the name cache of our client, because the user
            # was possibly deleted by the Ansible module and not through our
            # client instance.
            console.users.invalidate_cache()
            user = console.users.find_by_name(user_name)
        except zhmcclient.NotFound:
            user = None
        if user:
            user.delete()
Example #23
0
def ensure_active(params, check_mode):
    """
    Ensure the CPC is active, and then set the properties.

    Raises:
      ParameterError: An issue with the module parameters.
      Error: Other errors during processing.
      zhmcclient.Error: Any zhmcclient exception can happen.
    """

    # Note: Defaults specified in argument_spec will be set in params dict
    host = params['hmc_host']
    userid, password, ca_certs, verify = get_hmc_auth(params['hmc_auth'])
    cpc_name = params['name']
    activation_profile_name = params.get('activation_profile_name', None)
    _faked_session = params.get('_faked_session', None)  # No default specified

    changed = False

    session = get_session(_faked_session, host, userid, password, ca_certs,
                          verify)
    try:
        client = zhmcclient.Client(session)
        cpc = client.cpcs.find(name=cpc_name)
        # The default exception handling is sufficient for the above.

        # Activate the CPC
        cpc_status = cpc.get_property('status')
        if cpc_status in ('not-operating', 'no-power'):
            # CPC is inactive
            if not check_mode:
                cpc_dpm_enabled = cpc.get_property('dpm-enabled')
                if cpc_dpm_enabled:
                    cpc.start()
                else:
                    if not activation_profile_name:
                        raise ParameterError(
                            "CPC {0!r} is in classic mode and activation "
                            "requires the 'activation_profile_name' parameter "
                            "to be specified".format(cpc_name))
                    cpc.activate(
                        activation_profile_name=activation_profile_name,
                        force=True)
            changed = True
        elif cpc_status in ('active', 'operating', 'exceptions',
                            'service-required', 'degraded', 'acceptable',
                            'service'):
            # CPC is already active
            pass
        else:
            # cpc_status in ('not-communicating', 'status-check')
            # or any new future status values.
            raise StatusError(
                "CPC {0!r} cannot be activated because it is in status {1!r}".
                format(cpc_name, cpc_status))

        # Set the properties
        cpc.pull_full_properties()
        result = dict(cpc.properties)
        update_props = process_properties(cpc, params)
        if update_props:
            if not check_mode:
                cpc.update_properties(update_props)
            # Some updates of CPC properties are not reflected in a new
            # retrieval of properties until after a few seconds (usually the
            # second retrieval).
            # Therefore, we construct the modified result based upon the input
            # changes, and not based upon newly retrieved properties.
            result.update(update_props)
            changed = True
        add_artificial_properties(result, cpc)

        return changed, result

    finally:
        session.logoff()
def ensure_attached(params, check_mode):
    """
    Ensure that the specified crypto adapters and crypto domains are attached
    to the target partition.

    Raises:
      ParameterError: An issue with the module parameters.
      Error: Other errors during processing.
      zhmcclient.Error: Any zhmcclient exception can happen.
    """

    # Note: Defaults specified in argument_spec will be set in params dict
    host = params['hmc_host']
    userid, password = get_hmc_auth(params['hmc_auth'])
    cpc_name = params['cpc_name']
    partition_name = params['partition_name']
    adapter_count = params['adapter_count']
    domain_range = params['domain_range']
    access_mode = params['access_mode']
    crypto_type = params['crypto_type']
    faked_session = params.get('faked_session', None)  # No default specified

    try:
        assert len(domain_range) == 2, \
            "len(domain_range)={}".format(len(domain_range))
        domain_range_lo = int(domain_range[0])
        domain_range_hi = int(domain_range[1])
    except (ValueError, AssertionError):
        raise ParameterError(
            "The 'domain_range' parameter must be a list containing two "
            "integer numbers, but is: {!r}".format(domain_range))

    hmc_crypto_type = CRYPTO_TYPES_MOD2HMC[crypto_type]
    hmc_access_mode = ACCESS_MODES_MOD2HMC[access_mode]

    changed = False
    result = dict()
    result_changes = dict()

    try:
        session = get_session(faked_session, host, userid, password)
        client = zhmcclient.Client(session)
        cpc = client.cpcs.find(name=cpc_name)
        partition = cpc.partitions.find(name=partition_name)
        # The default exception handling is sufficient for the above.

        # Determine all crypto adapters of the specified crypto type.
        filter_args = {
            'adapter-family': 'crypto',
            'crypto-type': hmc_crypto_type,
        }
        all_adapters = cpc.adapters.list(filter_args=filter_args,
                                         full_properties=True)
        if not all_adapters:
            raise Error(
                "No crypto adapters of type {!r} found on CPC {!r} ".format(
                    crypto_type, cpc_name))

        # All crypto adapters in a CPC have the same number of domains
        # (otherwise the concept of attaching domains across all attached
        # adapters cannot work). Therefore, the max number of domains can be
        # gathered from any adapter.
        max_domains = all_adapters[0].maximum_crypto_domains

        # Parameter checking on domain range.
        # (can be done only now because it requires the max_domains).
        if domain_range_hi == -1:
            domain_range_hi = max_domains - 1
        if domain_range_lo > domain_range_hi:
            raise ParameterError(
                "In the 'domain_range' parameter, the lower boundary (={}) "
                "of the range must be less than the higher boundary (={})".
                format(domain_range_lo, domain_range_hi))

        # Parameter checking on adapter count.
        # (can be done only now because it requires the number of adapters).
        if adapter_count == -1:
            adapter_count = len(all_adapters)
        if adapter_count < 1:
            raise ParameterError(
                "The 'adapter_count' parameter must be at least 1, but is: {}".
                format(adapter_count))
        if adapter_count > len(all_adapters):
            raise ParameterError(
                "The 'adapter_count' parameter must not exceed the number of "
                "{} crypto adapters of type {!r} in CPC {!r}, but is {}".
                format(len(all_adapters), crypto_type, cpc_name,
                       adapter_count))

        #
        # Get current crypto config of the target partition.
        #

        # Domains attached to the partition, as a dict with:
        #   key: domain index
        #   value: access mode
        attached_domains = dict()

        # Adapters attached to the partition, as a list of Adapter objects:
        attached_adapters = list()

        # Adapters not attached to the partition, as a list of Adapter objects:
        detached_adapters = list()

        _attached_adapter_uris = list()  # URIs of attached adapters
        cc = partition.get_property('crypto-configuration')
        if cc:
            _attached_adapter_uris = cc['crypto-adapter-uris']
            for dc in cc['crypto-domain-configurations']:
                di = int(dc['domain-index'])
                am = dc['access-mode']
                LOGGER.debug("Crypto config of partition {!r}: "
                             "Domain {} is attached in {!r} mode".format(
                                 partition.name, di, am))
                attached_domains[di] = am
        for a in all_adapters:
            if a.uri in _attached_adapter_uris:
                LOGGER.debug("Crypto config of partition {!r}: "
                             "Adapter {!r} is attached".format(
                                 partition.name, a.name))
                attached_adapters.append(a)
            else:
                LOGGER.debug("Crypto config of partition {!r}: "
                             "Adapter {!r} is not attached".format(
                                 partition.name, a.name))
                detached_adapters.append(a)
        del _attached_adapter_uris

        #
        # Get the current crypto config of all partitions of the CPC.
        #
        # This is needed because finding out whether an adapter has the right
        # domains available by simply attaching it to the target partition
        # and reacting to the returned status does not work for stopped
        # partitions.
        #

        # All partition of the CPC, as a dict:
        #   key: partition URI
        #   value: Partition object
        all_partitions = cpc.partitions.list()
        all_partitions = dict(
            zip([p.uri for p in all_partitions], all_partitions))

        # Crypto config of all partitions of the CPC, as a dict with:
        #   key: adapter URI
        #   value: dict:
        #     key: domain index (for attached domains)
        #     value: list of tuple(access mode, partition URI)
        all_crypto_config = dict()

        for p_uri in all_partitions:
            p = all_partitions[p_uri]
            cc = p.get_property('crypto-configuration')
            # The 'crypto-configuration' property is None or:
            # {
            #   'crypto-adapter-uris': ['/api/...', ...],
            #   'crypto-domain-configurations': [
            #     {'domain-index': 15, 'access-mode': 'control-usage'},
            #     ...
            #   ]
            # }
            if cc:
                _adapter_uris = cc['crypto-adapter-uris']
                for dc in cc['crypto-domain-configurations']:
                    di = int(dc['domain-index'])
                    am = dc['access-mode']
                    for a_uri in _adapter_uris:
                        if a_uri not in all_crypto_config:
                            all_crypto_config[a_uri] = dict()
                        domains_dict = all_crypto_config[a_uri]  # mutable
                        if di not in domains_dict:
                            domains_dict[di] = list()
                        domains_dict[di].append((am, p.uri))

        #
        # Determine the domains to be attached to the target partition
        #

        desired_domains = list(range(domain_range_lo, domain_range_hi + 1))
        add_domains = list()  # List of domain index numbers to be attached
        for di in desired_domains:
            if di not in attached_domains:
                # This domain is not attached to the target partition
                add_domains.append(di)
            elif attached_domains[di] != hmc_access_mode:
                # This domain is attached to the target partition but not in
                # the desired access mode. The access mode could be extended
                # from control to control+usage, but that is not implemented
                # by this code here.
                raise Error(
                    "Domain {} is currently attached in {!r} mode to target "
                    "partition {!r}, but requested was {!r} mode".format(
                        di, ACCESS_MODES_HMC2MOD[attached_domains[di]],
                        partition.name, access_mode))
            else:
                # This domain is attached to the target partition in the
                # desired access mode
                pass

        # Create the domain config structure for the domains to be attached
        add_domain_config = list()
        for di in add_domains:
            add_domain_config.append({
                'domain-index': di,
                'access-mode': hmc_access_mode
            })

        # Check that the domains to be attached to the partition are available
        # on the currently attached adapters
        for a in attached_adapters:
            domains_dict = all_crypto_config[a.uri]
            for di in add_domains:
                if di in domains_dict:
                    for am, p_uri in domains_dict[di]:
                        if am != 'control' and hmc_access_mode != 'control':
                            # Multiple attachments conflict only when both are
                            # in usage mode
                            p = all_partitions[p_uri]
                            raise Error(
                                "Domain {} cannot be attached in {!r} mode to "
                                "target partition {!r} because it is already "
                                "attached in {!r} mode to partition {!r}".
                                format(di, access_mode, partition.name,
                                       ACCESS_MODES_HMC2MOD[am], p.name))

        # Make sure the desired number of adapters is attached to the partition
        # and the desired domains are attached.
        # The HMC enforces the following for non-empty crypto configurations of
        # a partition:
        # - In the resulting config, the partition needs to have at least one
        #   adapter attached.
        # - In the resulting config, the partition needs to have at least one
        #   domain attached in usage mode.
        # As a result, on an empty crypto config, the first adapter and the
        # first domain(s) need to be attached at the same time.
        result_changes['added-adapters'] = []
        result_changes['added-domains'] = []
        missing_count = max(0, adapter_count - len(attached_adapters))
        assert missing_count <= len(detached_adapters), \
            "missing_count={}, len(detached_adapters)={}".\
            format(missing_count, len(detached_adapters))
        if missing_count == 0 and add_domain_config:
            # Adapters already sufficient, but domains to be attached

            LOGGER.debug(
                "Adapters sufficient - attaching domains {!r} in {!r} mode to "
                "target partition {!r}".format(add_domains, access_mode,
                                               partition.name))

            if not check_mode:
                try:
                    partition.increase_crypto_config([], add_domain_config)
                except zhmcclient.Error as exc:
                    raise Error(
                        "Attaching domains {!r} in {!r} mode to target "
                        "partition {!r} failed: {}".format(
                            add_domains, access_mode, partition.name, exc))

            changed = True
            result_changes['added-domains'].extend(add_domains)

        elif missing_count > 0:
            # Adapters need to be attached

            for adapter in detached_adapters:
                if missing_count == 0:
                    break

                # Check that the adapter has all needed domains available
                conflicting_domains = dict()
                if adapter.uri in all_crypto_config:
                    domains_dict = all_crypto_config[adapter.uri]
                    for di in desired_domains:
                        if di in domains_dict:
                            # The domain is already attached to some
                            # partition(s) in some access mode
                            for am, p_uri in domains_dict[di]:
                                if am == 'control':
                                    # An attachment in control mode does not
                                    # prevent additional attachments
                                    continue
                                if p_uri == partition.uri and \
                                        am == hmc_access_mode:
                                    # This is our target partition, and the
                                    # domain is already attached in the desired
                                    # mode.
                                    continue
                                p = all_partitions[p_uri]
                                conflicting_domains[di] = (am, p.name)

                if conflicting_domains:
                    LOGGER.debug(
                        "Skipping adapter {!r} because the following of its "
                        "domains are already attached to other partitions: "
                        "{!r}".format(adapter.name, conflicting_domains))
                    continue

                LOGGER.debug(
                    "Attaching adapter {!r} and domains {!r} in {!r} mode to "
                    "target partition {!r}".format(adapter.name, add_domains,
                                                   access_mode,
                                                   partition.name))

                if not check_mode:
                    try:
                        partition.increase_crypto_config([adapter],
                                                         add_domain_config)
                    except zhmcclient.Error as exc:
                        raise Error(
                            "Attaching adapter {!r} and domains {!r} in {!r} "
                            "mode to target partition {!r} failed: {}".format(
                                adapter.name, add_domains, access_mode,
                                partition.name, exc))

                changed = True
                result_changes['added-adapters'].append(adapter.name)
                result_changes['added-domains'].extend(add_domains)

                # Don't try to add again for next adapter:
                add_domain_config = []
                add_domains = []

                missing_count -= 1

            if missing_count > 0:
                # Because adapters may be skipped, it is possible that there
                # are not enough adapters
                raise Error(
                    "Did not find enough crypto adapters with attachable "
                    "domains - missing adapters: {}; Requested domains: {}, "
                    "Access mode: {}".format(missing_count, desired_domains,
                                             access_mode))

        if not check_mode:
            # This is not optimal because it does not produce a result
            # in check mode, but because the actual config is determined,
            # instead of the artificially calculated one, it seems better
            # to return no config than the unchanged actual config.
            result.update(get_partition_config(partition, all_adapters))

        return changed, result, result_changes

    finally:
        session.logoff()