Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixed return and logging of password-like props in clear text
Browse files Browse the repository at this point in the history
Details:

* Increased minimum version of zhmcclient to 1.8.2 to pick up fixes for no
  longer logging password-like properties in clear-text.

* Fixed that all password-like input parameters that were written in clear text
  to the module entry log are now blanked out. This affected the following
  modules: zhmc_ldap_server_definition, zhmc_lpar, zhmc_partition, zhmc_user.

* Fixed that all password-like input parameters that were added to the
  module return value in clear text for 'state' values that created or updated
  the resource are now removed from the return value. This affected the
  following modules: zhmc_ldap_server_definition, zhmc_lpar, zhmc_partition.

* The 'hmc_auth' input parameter is no longer completely removed from the
  module entry log, but instead its sensitive items 'password' and 'session_id'
  are now blanked out.

* In support of the above, added common functions blanked_params(),
  blanked_dict() and removed_dict(). Added unit tests for these new functions.

* Improved the end2end tests for the affected modules to check that the module
  output does not contain the password-like properties.

Signed-off-by: Andreas Maier <[email protected]>
andy-maier committed Nov 29, 2024
1 parent 052cfd8 commit 08b4ceb
Showing 47 changed files with 631 additions and 183 deletions.
2 changes: 1 addition & 1 deletion docs/source/modules/zhmc_ldap_server_definition.rst
Original file line number Diff line number Diff line change
@@ -228,7 +228,7 @@ ldap_server_definition
| **type**: str
{property}
Additional properties of the LDAP Server Definition, as described in the data model of the 'LDAP Server Definition' object in the :ref:`HMC API <HMC API>` book. The property names have hyphens (-) as described in that book.
Additional properties of the LDAP Server Definition, as described in the data model of the 'LDAP Server Definition' object in the :ref:`HMC API <HMC API>` book. Write-only properties in the data model are not included. The property names have hyphens (-) as described in that book.

| **type**: raw
2 changes: 1 addition & 1 deletion docs/source/modules/zhmc_lpar.rst
Original file line number Diff line number Diff line change
@@ -560,7 +560,7 @@ lpar
| **type**: str
{property}
Additional properties of the LPAR, as described in the data model of the 'Logical Partition' object in the :ref:`HMC API <HMC API>` book. The property names have hyphens (-) as described in that book.
Additional properties of the LPAR, as described in the data model of the 'Logical Partition' object in the :ref:`HMC API <HMC API>` book. Write-only properties in the data model are not included. The property names have hyphens (-) as described in that book.

| **type**: raw
2 changes: 1 addition & 1 deletion docs/source/modules/zhmc_partition.rst
Original file line number Diff line number Diff line change
@@ -515,7 +515,7 @@ partition
| **type**: str
{property}
Additional properties of the partition, as described in the data model of the 'Partition' object in the :ref:`HMC API <HMC API>` book. The property names have hyphens (-) as described in that book.
Additional properties of the partition, as described in the data model of the 'Partition' object in the :ref:`HMC API <HMC API>` book. Write-only properties in the data model are not included. The property names have hyphens (-) as described in that book.

| **type**: raw
4 changes: 2 additions & 2 deletions docs/source/modules/zhmc_user.rst
Original file line number Diff line number Diff line change
@@ -277,7 +277,7 @@ user
| **type**: str
{property}
Additional properties of the user, as described in the data model of the 'User' object in the :ref:`HMC API <HMC API>` book. The property names have hyphens (-) as described in that book.
Additional properties of the user, as described in the data model of the 'User' object in the :ref:`HMC API <HMC API>` book. Write-only properties in the data model are not included. The property names have hyphens (-) as described in that book.

| **type**: raw
@@ -348,7 +348,7 @@ user
| **type**: dict
{property}
Properties of the LDAP server definition, as described in the data model of the 'LDAP Server Definition' object in the :ref:`HMC API <HMC API>` book. The property names have hyphens (-) as described in that book.
Properties of the LDAP server definition, as described in the data model of the 'LDAP Server Definition' object in the :ref:`HMC API <HMC API>` book. Write-only properties in the data model are not included. The property names have hyphens (-) as described in that book.

| **type**: raw
15 changes: 14 additions & 1 deletion docs/source/release_notes.rst
Original file line number Diff line number Diff line change
@@ -37,7 +37,16 @@ Availability: `AutomationHub`_, `Galaxy`_, `GitHub`_

* Fixed safety issues up to 2024-11-21.

* Increased zhmcclient version to 1.18.0 to pick up fixes. (issue #1074)
* Increased zhmcclient version to 1.18.2 to pick up fixes. (issue #1074)

* Fixed that all password-like input parameters that were written in clear text
to the module entry log are now blanked out. This affected the following
modules: zhmc_ldap_server_definition, zhmc_lpar, zhmc_partition, zhmc_user.

* Fixed that all password-like input parameters that were added to the
module return value in clear text for 'state' values that created or updated
the resource are now removed from the return value. This affected the
following modules: zhmc_ldap_server_definition, zhmc_lpar, zhmc_partition.

* Sanity test: Fixed the sanity test on AutomationHub which failed because the
"compile" and "import" tests were run for all target node Python versions,
@@ -67,6 +76,10 @@ Availability: `AutomationHub`_, `Galaxy`_, `GitHub`_

* Support for ansible-core 2.18, by adding an ignore file for the sanity tests.

* The 'hmc_auth' input parameter is no longer completely removed from the
module entry log, but instead its sensitive items 'password' and 'session_id'
are now blanked out.

**Cleanup:**

* Removed the unnecessary .pylintrc file from the distribution archive of the
4 changes: 2 additions & 2 deletions minimum-constraints-install.txt
Original file line number Diff line number Diff line change
@@ -38,7 +38,7 @@ requests==2.32.2

pytz==2019.1

zhmcclient==1.18.0
zhmcclient==1.18.2


# Indirect dependencies for install that are needed for some reason (must be consistent with requirements.txt)
@@ -57,7 +57,7 @@ packaging==22.0
PyYAML==6.0.2

python-dateutil==2.8.2
jsonschema==4.18.1
jsonschema==4.18.2
urllib3==1.26.19


78 changes: 77 additions & 1 deletion plugins/module_utils/common.py
Original file line number Diff line number Diff line change
@@ -1423,7 +1423,7 @@ def params_deepcopy(params):
an optional '_faked_session' item with a value that cannot be copied.
Parameters:
params (dict): Module input parameters.
params (dict): Module input parameters. Must not be None.
Returns:
dict: Deep copy of params, where possible.
@@ -1435,3 +1435,79 @@ def params_deepcopy(params):
except TypeError:
copy_params[key] = value
return copy_params


def blanked_params(params, blanked_properties=None):
"""
Return a copy of the module input parameters, with the following items
blanked out:
* params['properties'][...] according to the blanked_properties list
* params['hmc_auth']['password']
* params['hmc_auth']['session_id']
Parameters:
params (dict): Module input parameters. Must not be None.
blanked_properties (Sequence): List of property names that will be
blanked out in the 'properties' item of the module input parameters.
Property names that are not in the input properties will be ignored.
Returns:
dict: Deep copy of the input parameters, with blanked out values.
"""
# The params['properties'] dict and the params['hmc_auth'] dict in the
# return value will be copies of the corresponding input items, and
# therefore it is sufficient to make a shallow copy of params.
copied_params = dict(params)
if 'properties' in copied_params and copied_params['properties'] \
and blanked_properties:
copied_params['properties'] = \
blanked_dict(copied_params['properties'], blanked_properties)
if 'hmc_auth' in copied_params:
copied_params['hmc_auth'] = \
blanked_dict(copied_params['hmc_auth'], ['password', 'session_id'])
return copied_params


def blanked_dict(properties, blanked_properties):
"""
Return a shallow copy of the input properties, where the values of the
specified properties have been blanked out.
Parameters:
properties (Mapping): Input properties. Must not be None.
blanked_properties (Sequence): List of property names that will be
blanked out. Property names that are not in the input properties
will be ignored. Must not be None.
Returns:
dict: Shallow copy of the input properties, with blanked out values.
"""
copied_properties = dict(properties)
for pname in blanked_properties:
if pname in copied_properties:
copied_properties[pname] = BLANKED_OUT
return copied_properties


def removed_dict(properties, removed_properties):
"""
Return a shallow copy of the input properties, where the specified
properties have been removed.
Parameters:
properties (Mapping): Input properties. Must not be None.
removed_properties (Sequence): List of property names that will be
removed. Property names that are not in the input properties
will be ignored. Must not be None.
Returns:
dict: Shallow copy of the input properties, with removed properties.
"""
copied_properties = dict(properties)
for pname in removed_properties:
try:
del copied_properties[pname]
except KeyError:
pass
return copied_properties
8 changes: 4 additions & 4 deletions plugins/modules/zhmc_adapter.py
Original file line number Diff line number Diff line change
@@ -350,7 +350,7 @@
from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, ParameterError, to_unicode, \
process_normal_property, eq_hex, missing_required_lib, \
common_fail_on_import_errors, parse_hmc_host # noqa: E402
common_fail_on_import_errors, parse_hmc_host, blanked_params # noqa: E402

try:
import urllib3
@@ -966,9 +966,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

try:

8 changes: 4 additions & 4 deletions plugins/modules/zhmc_adapter_list.py
Original file line number Diff line number Diff line change
@@ -279,7 +279,7 @@

from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, ParameterError, \
missing_required_lib, parse_hmc_host # noqa: E402
missing_required_lib, parse_hmc_host, blanked_params # noqa: E402

try:
import urllib3
@@ -474,9 +474,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

changed = False
try:
8 changes: 4 additions & 4 deletions plugins/modules/zhmc_console.py
Original file line number Diff line number Diff line change
@@ -237,7 +237,7 @@

from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, ParameterError, missing_required_lib, \
common_fail_on_import_errors, parse_hmc_host # noqa: E402
common_fail_on_import_errors, parse_hmc_host, blanked_params # noqa: E402

try:
import urllib3
@@ -413,9 +413,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

try:

9 changes: 5 additions & 4 deletions plugins/modules/zhmc_cpc.py
Original file line number Diff line number Diff line change
@@ -416,7 +416,8 @@
from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, StatusError, ParameterError, to_unicode, \
process_normal_property, missing_required_lib, \
common_fail_on_import_errors, pull_properties, parse_hmc_host # noqa: E402
common_fail_on_import_errors, pull_properties, parse_hmc_host, \
blanked_params # noqa: E402

try:
import urllib3
@@ -899,9 +900,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

try:

8 changes: 4 additions & 4 deletions plugins/modules/zhmc_cpc_capacity.py
Original file line number Diff line number Diff line change
@@ -451,7 +451,7 @@
from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, missing_required_lib, \
common_fail_on_import_errors, parse_hmc_host, \
underscore_properties # noqa: E402
underscore_properties, blanked_params # noqa: E402

try:
import urllib3
@@ -835,9 +835,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

try:

8 changes: 4 additions & 4 deletions plugins/modules/zhmc_cpc_list.py
Original file line number Diff line number Diff line change
@@ -222,7 +222,7 @@

from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, missing_required_lib, \
common_fail_on_import_errors, parse_hmc_host # noqa: E402
common_fail_on_import_errors, parse_hmc_host, blanked_params # noqa: E402

try:
import urllib3
@@ -330,9 +330,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

changed = False
try:
8 changes: 4 additions & 4 deletions plugins/modules/zhmc_crypto_attachment.py
Original file line number Diff line number Diff line change
@@ -374,7 +374,7 @@

from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, ParameterError, missing_required_lib, \
common_fail_on_import_errors, parse_hmc_host # noqa: E402
common_fail_on_import_errors, parse_hmc_host, blanked_params # noqa: E402


try:
@@ -1091,9 +1091,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

try:

8 changes: 4 additions & 4 deletions plugins/modules/zhmc_hba.py
Original file line number Diff line number Diff line change
@@ -246,7 +246,7 @@
from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, ParameterError, wait_for_transition_completion, \
eq_hex, to_unicode, process_normal_property, missing_required_lib, \
common_fail_on_import_errors, parse_hmc_host # noqa: E402
common_fail_on_import_errors, parse_hmc_host, blanked_params # noqa: E402

try:
import urllib3
@@ -627,9 +627,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

try:

25 changes: 18 additions & 7 deletions plugins/modules/zhmc_ldap_server_definition.py
Original file line number Diff line number Diff line change
@@ -212,6 +212,7 @@
description: "Additional properties of the LDAP Server Definition, as
described in the data model of the 'LDAP Server Definition' object in
the R(HMC API,HMC API) book.
Write-only properties in the data model are not included.
The property names have hyphens (-) as described in that book."
type: raw
sample:
@@ -244,7 +245,8 @@
from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, ParameterError, to_unicode, \
process_normal_property, missing_required_lib, \
common_fail_on_import_errors, parse_hmc_host # noqa: E402
common_fail_on_import_errors, parse_hmc_host, blanked_params, \
blanked_dict, removed_dict # noqa: E402

try:
import urllib3
@@ -325,6 +327,11 @@ def casefold(txt):
'class': (False, False, False, None, None, None),
}

# Write-only properties (blanked out in logs and removed in output)
WRITEONLY_PROPERTIES_USCORE = ['bind_password']
WRITEONLY_PROPERTIES_HYPHEN = [p.replace('_', '-')
for p in WRITEONLY_PROPERTIES_USCORE]


def process_properties(lsd, params):
"""
@@ -521,9 +528,11 @@ def ensure_present(params, check_mode):
raise AssertionError("Unexpected "
"create_props: %r" % create_props)
if update_props:
LOGGER.debug(
"Existing LDAP Server Definition %r needs to get "
"properties updated: %r", lsd_name, update_props)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug(
"Existing LDAP Server Definition %r needs to get "
"properties updated: %r", lsd_name,
blanked_dict(update_props, WRITEONLY_PROPERTIES_USCORE))
if not check_mode:
lsd.update_properties(update_props)
# We refresh the properties after the update, in case an
@@ -539,6 +548,8 @@ def ensure_present(params, check_mode):
if not lsd:
raise AssertionError()

result = removed_dict(result, WRITEONLY_PROPERTIES_HYPHEN)

return changed, result

finally:
@@ -669,9 +680,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params, WRITEONLY_PROPERTIES_USCORE))

try:

8 changes: 4 additions & 4 deletions plugins/modules/zhmc_ldap_server_definition_list.py
Original file line number Diff line number Diff line change
@@ -162,7 +162,7 @@

from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, missing_required_lib, \
common_fail_on_import_errors, parse_hmc_host # noqa: E402
common_fail_on_import_errors, parse_hmc_host, blanked_params # noqa: E402

try:
import urllib3
@@ -246,9 +246,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

changed = False
try:
21 changes: 17 additions & 4 deletions plugins/modules/zhmc_lpar.py
Original file line number Diff line number Diff line change
@@ -454,6 +454,7 @@
description: "Additional properties of the LPAR, as described in
the data model of the 'Logical Partition' object in the
R(HMC API,HMC API) book.
Write-only properties in the data model are not included.
The property names have hyphens (-) as described in that book."
type: raw
sample:
@@ -620,7 +621,8 @@
hmc_auth_parameter, Error, ParameterError, StatusError, \
ensure_lpar_inactive, ensure_lpar_active, ensure_lpar_loaded, to_unicode, \
process_normal_property, missing_required_lib, \
common_fail_on_import_errors, pull_properties, parse_hmc_host # noqa: E402
common_fail_on_import_errors, pull_properties, parse_hmc_host, \
blanked_params, removed_dict # noqa: E402

try:
import urllib3
@@ -781,6 +783,11 @@
'request_origin': (False, False, False, None, None, None),
}

# Write-only properties (blanked out in logs and removed in output)
WRITEONLY_PROPERTIES_USCORE = ['ssc_master_pw', 'zaware_master_pw']
WRITEONLY_PROPERTIES_HYPHEN = [p.replace('_', '-')
for p in WRITEONLY_PROPERTIES_USCORE]


def process_properties(lpar, params):
"""
@@ -1094,6 +1101,9 @@ def ensure_active(params, check_mode):

add_artificial_properties(lpar_properties, lpar)

lpar_properties = removed_dict(
lpar_properties, WRITEONLY_PROPERTIES_HYPHEN)

return changed, lpar_properties

finally:
@@ -1153,6 +1163,9 @@ def ensure_loaded(params, check_mode):

add_artificial_properties(lpar_properties, lpar)

lpar_properties = removed_dict(
lpar_properties, WRITEONLY_PROPERTIES_HYPHEN)

return changed, lpar_properties

finally:
@@ -1323,9 +1336,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params, WRITEONLY_PROPERTIES_USCORE))

try:

8 changes: 4 additions & 4 deletions plugins/modules/zhmc_lpar_command.py
Original file line number Diff line number Diff line change
@@ -211,7 +211,7 @@

from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, NotificationThread, missing_required_lib, \
common_fail_on_import_errors, parse_hmc_host # noqa: E402
common_fail_on_import_errors, parse_hmc_host, blanked_params # noqa: E402

try:
import urllib3
@@ -424,9 +424,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

changed = True
try:
8 changes: 4 additions & 4 deletions plugins/modules/zhmc_lpar_list.py
Original file line number Diff line number Diff line change
@@ -237,7 +237,7 @@

from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, ParameterError, missing_required_lib, \
common_fail_on_import_errors, parse_hmc_host # noqa: E402
common_fail_on_import_errors, parse_hmc_host, blanked_params # noqa: E402

try:
import urllib3
@@ -422,9 +422,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

changed = False
try:
8 changes: 4 additions & 4 deletions plugins/modules/zhmc_lpar_messages.py
Original file line number Diff line number Diff line change
@@ -286,7 +286,7 @@

from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, missing_required_lib, \
common_fail_on_import_errors, parse_hmc_host # noqa: E402
common_fail_on_import_errors, parse_hmc_host, blanked_params # noqa: E402

try:
import urllib3
@@ -448,9 +448,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

changed = False
try:
8 changes: 4 additions & 4 deletions plugins/modules/zhmc_nic.py
Original file line number Diff line number Diff line change
@@ -279,7 +279,7 @@
from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, ParameterError, wait_for_transition_completion, \
eq_hex, eq_mac, to_unicode, process_normal_property, missing_required_lib, \
common_fail_on_import_errors, parse_hmc_host # noqa: E402
common_fail_on_import_errors, parse_hmc_host, blanked_params # noqa: E402

try:
import urllib3
@@ -753,9 +753,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

try:

8 changes: 4 additions & 4 deletions plugins/modules/zhmc_nic_list.py
Original file line number Diff line number Diff line change
@@ -196,7 +196,7 @@

from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, missing_required_lib, \
common_fail_on_import_errors, parse_hmc_host # noqa: E402
common_fail_on_import_errors, parse_hmc_host, blanked_params # noqa: E402

try:
import urllib3
@@ -302,9 +302,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

changed = False
try:
19 changes: 15 additions & 4 deletions plugins/modules/zhmc_partition.py
Original file line number Diff line number Diff line change
@@ -414,6 +414,7 @@
"{property}":
description: "Additional properties of the partition, as described in
the data model of the 'Partition' object in the R(HMC API,HMC API) book.
Write-only properties in the data model are not included.
The property names have hyphens (-) as described in that book."
type: raw
hbas:
@@ -625,7 +626,8 @@
hmc_auth_parameter, Error, ParameterError, StatusError, stop_partition, \
start_partition, wait_for_transition_completion, eq_hex, to_unicode, \
process_normal_property, missing_required_lib, ImageError, \
common_fail_on_import_errors, pull_properties, parse_hmc_host # noqa: E402
common_fail_on_import_errors, pull_properties, parse_hmc_host, \
blanked_params, removed_dict # noqa: E402

try:
import urllib3
@@ -1042,6 +1044,11 @@ def required_type_ssc(partition_properties):
False, []),
}

# Write-only properties (blanked out in logs and removed in output)
WRITEONLY_PROPERTIES_USCORE = ['boot_ftp_password', 'ssc_master_pw']
WRITEONLY_PROPERTIES_HYPHEN = [p.replace('_', '-')
for p in WRITEONLY_PROPERTIES_USCORE]


def storage_mgmt_enabled(cpc):
"""
@@ -1876,6 +1883,8 @@ def ensure_active(params, check_mode):
add_artificial_properties(
result, partition, expand_storage_groups, expand_crypto_adapters)

result = removed_dict(result, WRITEONLY_PROPERTIES_HYPHEN)

return changed, result

finally:
@@ -1974,6 +1983,8 @@ def ensure_stopped(params, check_mode):
add_artificial_properties(
result, partition, expand_storage_groups, expand_crypto_adapters)

result = removed_dict(result, WRITEONLY_PROPERTIES_HYPHEN)

return changed, result

finally:
@@ -2231,9 +2242,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params, WRITEONLY_PROPERTIES_USCORE))

try:

8 changes: 4 additions & 4 deletions plugins/modules/zhmc_partition_command.py
Original file line number Diff line number Diff line change
@@ -211,7 +211,7 @@

from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, NotificationThread, missing_required_lib, \
common_fail_on_import_errors, parse_hmc_host # noqa: E402
common_fail_on_import_errors, parse_hmc_host, blanked_params # noqa: E402

try:
import urllib3
@@ -425,9 +425,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

changed = True
try:
8 changes: 4 additions & 4 deletions plugins/modules/zhmc_partition_list.py
Original file line number Diff line number Diff line change
@@ -234,7 +234,7 @@

from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, ParameterError, missing_required_lib, \
common_fail_on_import_errors, parse_hmc_host # noqa: E402
common_fail_on_import_errors, parse_hmc_host, blanked_params # noqa: E402

try:
import urllib3
@@ -415,9 +415,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

changed = False
try:
8 changes: 4 additions & 4 deletions plugins/modules/zhmc_partition_messages.py
Original file line number Diff line number Diff line change
@@ -261,7 +261,7 @@

from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, missing_required_lib, \
common_fail_on_import_errors, parse_hmc_host # noqa: E402
common_fail_on_import_errors, parse_hmc_host, blanked_params # noqa: E402

try:
import urllib3
@@ -413,9 +413,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

changed = False
try:
8 changes: 4 additions & 4 deletions plugins/modules/zhmc_password_rule.py
Original file line number Diff line number Diff line change
@@ -263,7 +263,7 @@
from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, ParameterError, to_unicode, \
process_normal_property, missing_required_lib, \
common_fail_on_import_errors, parse_hmc_host # noqa: E402
common_fail_on_import_errors, parse_hmc_host, blanked_params # noqa: E402

try:
import urllib3
@@ -671,9 +671,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

try:

8 changes: 4 additions & 4 deletions plugins/modules/zhmc_password_rule_list.py
Original file line number Diff line number Diff line change
@@ -176,7 +176,7 @@

from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, missing_required_lib, \
common_fail_on_import_errors, parse_hmc_host # noqa: E402
common_fail_on_import_errors, parse_hmc_host, blanked_params # noqa: E402

try:
import urllib3
@@ -266,9 +266,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

changed = False
try:
8 changes: 4 additions & 4 deletions plugins/modules/zhmc_session.py
Original file line number Diff line number Diff line change
@@ -221,7 +221,7 @@

from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, ParameterError, \
missing_required_lib, parse_hmc_host # noqa: E402
missing_required_lib, parse_hmc_host, blanked_params # noqa: E402

try:
import urllib3
@@ -353,9 +353,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

# We do not count session creation or deletion as a change
changed = False
8 changes: 4 additions & 4 deletions plugins/modules/zhmc_storage_group.py
Original file line number Diff line number Diff line change
@@ -580,7 +580,7 @@
from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, ParameterError, to_unicode, \
process_normal_property, missing_required_lib, \
common_fail_on_import_errors, parse_hmc_host # noqa: E402
common_fail_on_import_errors, parse_hmc_host, blanked_params # noqa: E402

try:
import urllib3
@@ -1142,9 +1142,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

try:

8 changes: 4 additions & 4 deletions plugins/modules/zhmc_storage_group_attachment.py
Original file line number Diff line number Diff line change
@@ -227,7 +227,7 @@

from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, missing_required_lib, \
common_fail_on_import_errors, parse_hmc_host # noqa: E402
common_fail_on_import_errors, parse_hmc_host, blanked_params # noqa: E402

try:
import urllib3
@@ -455,9 +455,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

try:

8 changes: 4 additions & 4 deletions plugins/modules/zhmc_storage_volume.py
Original file line number Diff line number Diff line change
@@ -278,7 +278,7 @@
from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, ParameterError, eq_hex, to_unicode, \
process_normal_property, missing_required_lib, \
common_fail_on_import_errors, parse_hmc_host # noqa: E402
common_fail_on_import_errors, parse_hmc_host, blanked_params # noqa: E402

try:
import urllib3
@@ -704,9 +704,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

try:

42 changes: 18 additions & 24 deletions plugins/modules/zhmc_user.py
Original file line number Diff line number Diff line change
@@ -249,6 +249,7 @@
"{property}":
description: "Additional properties of the user, as described in the
data model of the 'User' object in the R(HMC API,HMC API) book.
Write-only properties in the data model are not included.
The property names have hyphens (-) as described in that book."
type: raw
user-role-names:
@@ -324,6 +325,7 @@
description: "Properties of the LDAP server definition, as described
in the data model of the 'LDAP Server Definition' object in the
R(HMC API,HMC API) book.
Write-only properties in the data model are not included.
The property names have hyphens (-) as described in that book."
type: raw
sample:
@@ -380,8 +382,8 @@
from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, ParameterError, to_unicode, \
process_normal_property, missing_required_lib, \
common_fail_on_import_errors, parse_hmc_host, BLANKED_OUT, \
params_deepcopy # noqa: E402
common_fail_on_import_errors, parse_hmc_host, blanked_params, \
blanked_dict, removed_dict # noqa: E402

try:
import urllib3
@@ -493,6 +495,11 @@
'user_role_objects': (False, False, False, None, None, None),
}

# Write-only properties (blanked out in logs and removed in output)
WRITEONLY_PROPERTIES_USCORE = ['password']
WRITEONLY_PROPERTIES_HYPHEN = [p.replace('_', '-')
for p in WRITEONLY_PROPERTIES_USCORE]


def process_properties(console, user, params):
"""
@@ -986,14 +993,11 @@ def ensure_present(params, check_mode):
raise AssertionError("Unexpected "
"create_props: %r" % create_props)
if update_props:
logged_props = dict(update_props)
if 'password' in logged_props:
# This is not a hard-coded password. Added # nosec to avoid
# generating false positive in bandit
logged_props['password'] = BLANKED_OUT # nosec
LOGGER.debug(
"Existing user %r needs to get properties updated: %r",
user_name, logged_props)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug(
"Existing user %r needs to get properties updated: %r",
user_name,
blanked_dict(update_props, WRITEONLY_PROPERTIES_USCORE))
if not check_mode:
user.update_properties(update_props)
# We refresh the properties after the update, in case an
@@ -1030,10 +1034,7 @@ def ensure_present(params, check_mode):

add_artificial_properties(result, console, user, expand)

if 'password' in result:
# This is not a hard-coded password. Added # nosec to avoid
# generating false positive in bandit
result['password'] = BLANKED_OUT # nosec
result = removed_dict(result, WRITEONLY_PROPERTIES_HYPHEN)

return changed, result

@@ -1168,16 +1169,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

# We need to deepcopy the input parameters, because the dict in which we
# blank out the password is at the second level. With a shallow copy,
# that would blank out the password in the original params.
_params = params_deepcopy(module.params)
del _params['hmc_auth']
if _params['properties'] and 'password' in _params['properties']:
# This is not a hard-coded password. Added # nosec to avoid
# generating false positive in bandit
_params['properties']['password'] = BLANKED_OUT # nosec
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params, WRITEONLY_PROPERTIES_USCORE))

try:

8 changes: 4 additions & 4 deletions plugins/modules/zhmc_user_list.py
Original file line number Diff line number Diff line change
@@ -181,7 +181,7 @@

from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, missing_required_lib, \
common_fail_on_import_errors, parse_hmc_host # noqa: E402
common_fail_on_import_errors, parse_hmc_host, blanked_params # noqa: E402

try:
import urllib3
@@ -271,9 +271,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

changed = False
try:
8 changes: 4 additions & 4 deletions plugins/modules/zhmc_user_pattern.py
Original file line number Diff line number Diff line change
@@ -291,7 +291,7 @@
from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, ParameterError, to_unicode, \
process_normal_property, missing_required_lib, underscore_properties, \
common_fail_on_import_errors, parse_hmc_host # noqa: E402
common_fail_on_import_errors, parse_hmc_host, blanked_params # noqa: E402

try:
import urllib3
@@ -944,9 +944,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

try:

8 changes: 4 additions & 4 deletions plugins/modules/zhmc_user_pattern_list.py
Original file line number Diff line number Diff line change
@@ -197,7 +197,7 @@
from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, missing_required_lib, \
underscore_properties_list, common_fail_on_import_errors, \
parse_hmc_host # noqa: E402
parse_hmc_host, blanked_params # noqa: E402

try:
import urllib3
@@ -276,9 +276,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

changed = False
try:
8 changes: 4 additions & 4 deletions plugins/modules/zhmc_user_role.py
Original file line number Diff line number Diff line change
@@ -452,7 +452,7 @@
from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, ParameterError, to_unicode, \
process_normal_property, missing_required_lib, \
common_fail_on_import_errors, parse_hmc_host # noqa: E402
common_fail_on_import_errors, parse_hmc_host, blanked_params # noqa: E402

try:
import urllib3
@@ -1321,9 +1321,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

try:

8 changes: 4 additions & 4 deletions plugins/modules/zhmc_user_role_list.py
Original file line number Diff line number Diff line change
@@ -181,7 +181,7 @@

from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, missing_required_lib, \
common_fail_on_import_errors, parse_hmc_host # noqa: E402
common_fail_on_import_errors, parse_hmc_host, blanked_params # noqa: E402

try:
import urllib3
@@ -271,9 +271,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

changed = False
try:
8 changes: 4 additions & 4 deletions plugins/modules/zhmc_versions.py
Original file line number Diff line number Diff line change
@@ -245,7 +245,7 @@

from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, missing_required_lib, \
common_fail_on_import_errors, parse_hmc_host # noqa: E402
common_fail_on_import_errors, parse_hmc_host, blanked_params # noqa: E402

try:
import urllib3
@@ -368,9 +368,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

try:

8 changes: 4 additions & 4 deletions plugins/modules/zhmc_virtual_function.py
Original file line number Diff line number Diff line change
@@ -241,7 +241,7 @@
from ..module_utils.common import log_init, open_session, close_session, \
hmc_auth_parameter, Error, ParameterError, wait_for_transition_completion, \
eq_hex, to_unicode, process_normal_property, missing_required_lib, \
common_fail_on_import_errors, parse_hmc_host # noqa: E402
common_fail_on_import_errors, parse_hmc_host, blanked_params # noqa: E402

try:
import urllib3
@@ -605,9 +605,9 @@ def main():

module.params['hmc_host'] = parse_hmc_host(module.params['hmc_host'])

_params = dict(module.params)
del _params['hmc_auth']
LOGGER.debug("Module entry: params: %r", _params)
if LOGGER.isEnabledFor(logging.DEBUG):
LOGGER.debug("Module entry: params: %r",
blanked_params(module.params))

try:

6 changes: 4 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -40,7 +40,7 @@ requests>=2.32.2
pytz>=2019.1

# zhmcclient @ git+https://github.com/zhmcclient/python-zhmcclient.git@master
zhmcclient>=1.18.0
zhmcclient>=1.18.2


# Indirect dependencies for install that are needed for some reason (must be consistent with minimum-constraints-install.txt)
@@ -74,6 +74,8 @@ PyYAML>=6.0.2
python-dateutil>=2.8.2

# jsonschema
jsonschema>=4.18.1
jsonschema>=4.18.2
# TODO: Python 3.13 support requires pyo3-ffi fixing its issue with Python 3.13
# (see https://github.com/PyO3/pyo3/issues/4038#issuecomment-2156363013)

urllib3>=1.26.19
42 changes: 37 additions & 5 deletions tests/end2end/test_zhmc_ldap_server_definition.py
Original file line number Diff line number Diff line change
@@ -57,7 +57,6 @@
'search_distinguished_name': 'test_user{0}',
}


# A standard test LDAP server definition, as the input properties for
# LDAPServerDefinitionManager.create() (i.e. using dashes, and limited to valid
# input parameters)
@@ -67,6 +66,16 @@
'primary-hostname-ipaddr': '10.11.12.13',
'search-distinguished-name': 'test_user{0}',
}
STD_LSD_HMC_EXP_PROPS = dict(STD_LSD_HMC_INPUT_PROPS)

# LDAP server definition with bind data
STD_LSD_MODULE_INPUT_PROPS_WITH_BIND = dict(STD_LSD_MODULE_INPUT_PROPS)
STD_LSD_MODULE_INPUT_PROPS_WITH_BIND['bind_password'] = "Bumerang9x"
STD_LSD_MODULE_INPUT_PROPS_WITH_BIND['bind_distinguished_name'] = "bind_dn"
STD_LSD_HMC_INPUT_PROPS_WITH_BIND = dict(STD_LSD_HMC_INPUT_PROPS)
STD_LSD_HMC_INPUT_PROPS_WITH_BIND['bind-distinguished-name'] = "bind_dn"
STD_LSD_HMC_EXP_PROPS_WITH_BIND = dict(STD_LSD_HMC_INPUT_PROPS_WITH_BIND)
STD_LSD_HMC_INPUT_PROPS_WITH_BIND['bind-password'] = "Bumerang9x"


def new_lsd_name():
@@ -135,6 +144,10 @@ def assert_lsd_props(lsd_props, exp_lsd_props, where):
where_prop = where + f", property {prop_name!r}"
assert act_value == exp_value, where_prop

# Assert that none of the write-only properties is in the output object
for prop_name in zhmc_ldap_server_definition.WRITEONLY_PROPERTIES_HYPHEN:
assert prop_name not in lsd_props, where


@pytest.mark.parametrize(
"diff_case", [
@@ -220,19 +233,27 @@ def test_zhmc_lsd_facts(
# - exp_changed (bool): Boolean for expected 'changed' flag.

(
"Present with non-existing LDAP server definition",
"Present with non-existing LDAP server definition, without password",
None,
'present',
STD_LSD_MODULE_INPUT_PROPS,
STD_LSD_HMC_INPUT_PROPS,
STD_LSD_HMC_EXP_PROPS,
True,
),
(
"Present with non-existing LDAP server definition, with password",
None,
'present',
STD_LSD_MODULE_INPUT_PROPS_WITH_BIND,
STD_LSD_HMC_EXP_PROPS_WITH_BIND,
True,
),
(
"Present with existing LDAP server definition, no properties changed",
{},
'present',
None,
STD_LSD_HMC_INPUT_PROPS,
STD_LSD_HMC_EXP_PROPS,
False,
),
(
@@ -242,7 +263,18 @@ def test_zhmc_lsd_facts(
},
'present',
STD_LSD_MODULE_INPUT_PROPS,
STD_LSD_HMC_INPUT_PROPS,
STD_LSD_HMC_EXP_PROPS,
True,
),
(
"Present with existing LDAP server definition, some properties "
"changed, with password",
{
'description': 'bla',
},
'present',
STD_LSD_MODULE_INPUT_PROPS_WITH_BIND,
STD_LSD_HMC_EXP_PROPS_WITH_BIND,
True,
),
(
4 changes: 4 additions & 0 deletions tests/end2end/test_zhmc_lpar.py
Original file line number Diff line number Diff line change
@@ -172,6 +172,10 @@ def assert_lpar_props(act_props, exp_props, where):
f"Actual: {act_value!r}")
assert act_value == exp_value, where_prop

# Assert that none of the write-only properties is in the output object
for prop_name in zhmc_lpar.WRITEONLY_PROPERTIES_HYPHEN:
assert prop_name not in act_props, where


def ensure_lpar_status(logger, lpar, iap, status):
"""
23 changes: 15 additions & 8 deletions tests/end2end/test_zhmc_partition.py
Original file line number Diff line number Diff line change
@@ -115,6 +115,7 @@
'initial-memory': MIN_MEMORY,
'maximum-memory': MIN_MEMORY,
}
STD_LINUX_PARTITION_HMC_EXP_PROPS = dict(STD_LINUX_PARTITION_HMC_INPUT_PROPS)
STD_SSC_PARTITION_HMC_INPUT_PROPS = {
# 'name': updated upon use
'description': "zhmc test partition",
@@ -126,6 +127,8 @@
'ssc-master-userid': 'sscuser',
'ssc-master-pw': 'Need2ChangeSoon!',
}
STD_SSC_PARTITION_HMC_EXP_PROPS = dict(STD_SSC_PARTITION_HMC_INPUT_PROPS)
del STD_SSC_PARTITION_HMC_EXP_PROPS['ssc-master-pw']


def storage_mgmt_enabled(cpc):
@@ -499,6 +502,10 @@ def assert_partition_props(act_props, exp_props, where):
exp_boot_sv_name = exp_props['boot-storage-volume-name']
assert act_props['boot-storage-volume-name'] == exp_boot_sv_name

# Assert that none of the write-only properties is in the output object
for prop_name in zhmc_partition.WRITEONLY_PROPERTIES_HYPHEN:
assert prop_name not in act_props, where


PARTITION_FACTS_TESTCASES = [
# The list items are tuples with the following items:
@@ -727,7 +734,7 @@ def test_zhmc_partition_facts(
'stopped',
STD_LINUX_PARTITION_MODULE_INPUT_PROPS,
None,
STD_LINUX_PARTITION_HMC_INPUT_PROPS,
STD_LINUX_PARTITION_HMC_EXP_PROPS,
True,
True,
),
@@ -739,7 +746,7 @@ def test_zhmc_partition_facts(
'stopped',
None,
None,
STD_LINUX_PARTITION_HMC_INPUT_PROPS,
STD_LINUX_PARTITION_HMC_EXP_PROPS,
False,
True,
),
@@ -751,7 +758,7 @@ def test_zhmc_partition_facts(
'stopped',
None,
None,
STD_LINUX_PARTITION_HMC_INPUT_PROPS,
STD_LINUX_PARTITION_HMC_EXP_PROPS,
True,
True,
),
@@ -791,7 +798,7 @@ def test_zhmc_partition_facts(
'stopped',
STD_LINUX_PARTITION_MODULE_INPUT_PROPS,
None,
STD_LINUX_PARTITION_HMC_INPUT_PROPS,
STD_LINUX_PARTITION_HMC_EXP_PROPS,
True,
True,
),
@@ -802,7 +809,7 @@ def test_zhmc_partition_facts(
'stopped',
STD_SSC_PARTITION_MODULE_INPUT_PROPS,
None,
STD_SSC_PARTITION_HMC_INPUT_PROPS,
STD_SSC_PARTITION_HMC_EXP_PROPS,
True,
True,
),
@@ -818,7 +825,7 @@ def test_zhmc_partition_facts(
'stopped',
None,
None,
STD_SSC_PARTITION_HMC_INPUT_PROPS,
STD_SSC_PARTITION_HMC_EXP_PROPS,
False,
True,
),
@@ -830,7 +837,7 @@ def test_zhmc_partition_facts(
'active',
None,
None, # Code ignores "HTTPError: 409,131"
STD_SSC_PARTITION_HMC_INPUT_PROPS,
STD_SSC_PARTITION_HMC_EXP_PROPS,
True,
True,
),
@@ -844,7 +851,7 @@ def test_zhmc_partition_facts(
'stopped',
STD_SSC_PARTITION_MODULE_INPUT_PROPS,
None,
STD_SSC_PARTITION_HMC_INPUT_PROPS,
STD_SSC_PARTITION_HMC_EXP_PROPS,
True,
True,
),
4 changes: 4 additions & 0 deletions tests/end2end/test_zhmc_user.py
Original file line number Diff line number Diff line change
@@ -224,6 +224,10 @@ def assert_user_props(user_props, expand, where):
if expand:
assert 'user-role-objects' in user_props, where

# Assert that none of the write-only properties is in the output object
for prop_name in zhmc_user.WRITEONLY_PROPERTIES_HYPHEN:
assert prop_name not in user_props, where


@pytest.mark.parametrize(
"check_mode", [
280 changes: 280 additions & 0 deletions tests/unit/test_common.py
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@
__metaclass__ = type

import re
from copy import deepcopy
from collections.abc import Sequence, Mapping, Set
from types import ModuleType
import pytest
@@ -548,3 +549,282 @@ def test_common_params_deepcopy(desc, in_params):
params = common.params_deepcopy(in_params)

assert_disparate_equal(params, in_params)


COMMON_BLANKED_PARAMS_TESTCASES = [
# Testcases for test_common_blanked_params()
# The list items are tuples with the following items:
# - desc (string): description of the testcase.
# - in_params (dict): Input params. Must not be None
# - blanked_properties (list): Properties to be blanked out, may be None

(
"Params without hmc_auth or properties",
{
'state': 'bla',
},
None
),
(
"Params with hmc_auth that does not have sensitive items",
{
'state': 'bla',
'hmc_auth': {'userid': 'user'},
},
None
),
(
"Params with hmc_auth that does have all sensitive items",
{
'state': 'bla',
'hmc_auth': {
'userid': 'user',
'password': 'pass',
'session_id': 'sid',
},
},
None
),
(
"Params with properties but without blanked props specified",
{
'state': 'bla',
'properties': {
'name': 'foo',
},
},
None
),
(
"Params with properties being None",
{
'state': 'bla',
'properties': None,
},
None
),
(
"Params with properties with different blanked props specified",
{
'state': 'bla',
'properties': {
'name': 'foo',
},
},
['password']
),
(
"Params with properties with one blanked props specified",
{
'state': 'bla',
'properties': {
'name': 'foo',
'password': 'pass',
},
},
['password']
),
(
"Params with properties with one blanked prop and excess blanked prop",
{
'state': 'bla',
'properties': {
'name': 'foo',
'password': 'pass',
},
},
['password', 'extra']
),
]

BLANKED_PROPS_HMC_AUTH = ['password', 'session_id']


@pytest.mark.parametrize(
"desc, in_params, blanked_properties",
COMMON_BLANKED_PARAMS_TESTCASES)
def test_common_blanked_params(desc, in_params, blanked_properties):
# pylint: disable=unused-argument
"""
Test the blanked_params() function.
"""

saved_params = common.params_deepcopy(in_params)

# The code to be tested
act_params = common.blanked_params(in_params, blanked_properties)

# Check that the input parameters have not been changed
assert_disparate_equal(in_params, saved_params)

# Check that all dict items are still there.
in_keys = sorted(in_params.keys())
act_keys = sorted(act_params.keys())
assert act_keys == in_keys

# Check that the 'hmc_auth' item, if present, has its sensitive items
# blanked out.
if 'hmc_auth' in act_params:
hmc_auth = act_params['hmc_auth']
for pname in BLANKED_PROPS_HMC_AUTH:
if pname in hmc_auth:
assert hmc_auth[pname] == common.BLANKED_OUT

# Check that the 'properties' item, if present, has its sensitive items
# blanked out.
if 'properties' in act_params and act_params['properties'] and \
blanked_properties:
properties = act_params['properties']
for pname in blanked_properties:
if pname in properties:
assert properties[pname] == common.BLANKED_OUT


COMMON_BLANKED_DICT_TESTCASES = [
# Testcases for test_common_blanked_dict()
# The list items are tuples with the following items:
# - desc (string): description of the testcase.
# - in_dict (dict): Input dict. Must not be None
# - blanked_properties (list): Prop to be blanked out. Must not be None

(
"Empty dict and empty blanked props",
{},
[]
),
(
"Empty dict and one excess blanked prop",
{},
['foo']
),
(
"Dict and empty blanked props",
{
'p1': 'v1',
'p2': None,
},
[]
),
(
"Dict and one matching blanked prop",
{
'p1': 'v1',
'p2': None,
},
['p1']
),
(
"Dict and one matching and one excess blanked prop",
{
'p1': 'v1',
'p2': None,
},
['p1', 'foo']
),
]


@pytest.mark.parametrize(
"desc, in_dict, blanked_properties",
COMMON_BLANKED_DICT_TESTCASES)
def test_common_blanked_dict(desc, in_dict, blanked_properties):
# pylint: disable=unused-argument
"""
Test the blanked_dict() function.
"""

saved_dict = deepcopy(in_dict)

# The code to be tested
act_dict = common.blanked_dict(in_dict, blanked_properties)

# Check that the input dict has not been changed
assert_disparate_equal(in_dict, saved_dict)

# Check that the returned dict did not get additional keys
for pname in act_dict.keys():
assert pname in in_dict

# Check that the specified items have been blanked out, and that all other
# items have unchanged values.
for pname, in_value in in_dict.items():
assert pname in act_dict
act_value = act_dict[pname]
if pname in blanked_properties:
assert act_value == common.BLANKED_OUT
else:
assert act_value == in_value


COMMON_REMOVED_DICT_TESTCASES = [
# Testcases for test_common_removed_dict()
# The list items are tuples with the following items:
# - desc (string): description of the testcase.
# - in_dict (dict): Input dict. Must not be None
# - removed_properties (list): Properties to be removed. Must not be None

(
"Empty dict and empty removed props",
{},
[]
),
(
"Empty dict and one excess removed prop",
{},
['foo']
),
(
"Dict and empty removed props",
{
'p1': 'v1',
'p2': None,
},
[]
),
(
"Dict and one matching removed prop",
{
'p1': 'v1',
'p2': None,
},
['p1']
),
(
"Dict and one matching and one excess removed prop",
{
'p1': 'v1',
'p2': None,
},
['p1', 'foo']
),
]


@pytest.mark.parametrize(
"desc, in_dict, removed_properties",
COMMON_REMOVED_DICT_TESTCASES)
def test_common_removed_dict(desc, in_dict, removed_properties):
# pylint: disable=unused-argument
"""
Test the removed_dict() function.
"""

saved_dict = deepcopy(in_dict)

# The code to be tested
act_dict = common.removed_dict(in_dict, removed_properties)

# Check that the input dict has not been changed
assert_disparate_equal(in_dict, saved_dict)

# Check that the returned dict did not get additional keys
for pname in act_dict.keys():
assert pname in in_dict

# Check that the specified items have been removed, and that all other
# items have unchanged values.
for pname, in_value in in_dict.items():
if pname in removed_properties:
assert pname not in act_dict
else:
assert act_dict[pname] == in_value

0 comments on commit 08b4ceb

Please sign in to comment.