From a35e1d3b9212cc6f99bd37d324b1a83ecb73db69 Mon Sep 17 00:00:00 2001 From: Andreas Maier Date: Sun, 5 Nov 2023 09:23:01 +0100 Subject: [PATCH] Added support for creation and deletion of activation profiles on z16 Signed-off-by: Andreas Maier --- docs/changes.rst | 5 ++ tests/end2end/test_activation_profile.py | 96 +++++++++++++++++++++++- tests/end2end/utils.py | 25 ++++++ zhmcclient/_activation_profile.py | 70 +++++++++++++++++ 4 files changed, 194 insertions(+), 2 deletions(-) diff --git a/docs/changes.rst b/docs/changes.rst index 4977477e5..09f1f5ab4 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -134,6 +134,11 @@ Released: not yet cache. Otherwise, it retrieves the properties from the HMC in the fastest possible way, considering property filtering if supported. +* Added support for creation and deletion of activation profiles on z16. + This requires the SE to have a code level that has the + 'create-delete-activation-profiles' API feature enabled. + (issue #1329) + **Cleanup:** **Known issues:** diff --git a/tests/end2end/test_activation_profile.py b/tests/end2end/test_activation_profile.py index cfb6eb844..db69e1b81 100644 --- a/tests/end2end/test_activation_profile.py +++ b/tests/end2end/test_activation_profile.py @@ -20,16 +20,19 @@ from __future__ import absolute_import, print_function +import warnings + import pytest from requests.packages import urllib3 +import zhmcclient # pylint: disable=line-too-long,unused-import from zhmcclient.testutils import hmc_definition, hmc_session # noqa: F401, E501 from zhmcclient.testutils import classic_mode_cpcs # noqa: F401, E501 # pylint: enable=line-too-long,unused-import -from .utils import skip_warn, pick_test_resources, runtest_find_list, \ - runtest_get_properties +from .utils import skip_warn, pick_test_resources, TEST_PREFIX, \ + runtest_find_list, runtest_get_properties, standard_activation_profile_props urllib3.disable_warnings() @@ -46,6 +49,95 @@ ACTPROF_VOLATILE_PROPS = [] +@pytest.mark.parametrize( + "profile_type", ['reset', 'image', 'load'] +) +def test_actprof_crud(classic_mode_cpcs, profile_type): # noqa: F811 + # pylint: disable=redefined-outer-name + """ + Test create, read, update and delete an activation profile. + """ + if not classic_mode_cpcs: + pytest.skip("HMC definition does not include any CPCs in classic mode") + + for cpc in classic_mode_cpcs: + assert not cpc.dpm_enabled + + actprof_mgr = getattr(cpc, profile_type + '_activation_profiles') + + print("Testing on CPC {c}".format(c=cpc.name)) + + actprof_name = TEST_PREFIX + ' ' + profile_type + \ + ' activation profile prof1' + actprof_name_new = actprof_name + ' new' + + # Ensure a clean starting point for this test + try: + actprof = actprof_mgr.find(name=actprof_name) + except zhmcclient.NotFound: + pass + else: + warnings.warn( + "Deleting test activation profile from previous run: {p!r} on " + "CPC {c}".format(p=actprof_name, c=cpc.name), UserWarning) + actprof.delete() + try: + actprof = actprof_mgr.find(name=actprof_name_new) + except zhmcclient.NotFound: + pass + else: + warnings.warn( + "Deleting test activation profile from previous run: {p!r} on " + "CPC {c}".format(p=actprof_name_new, c=cpc.name), UserWarning) + actprof.delete() + + # Test creating the activation profile + + actprof_input_props = standard_activation_profile_props( + cpc, actprof_name, profile_type) + + # The code to be tested + actprof = actprof_mgr.create(actprof_input_props) + + for pn, exp_value in actprof_input_props.items(): + assert actprof.properties[pn] == exp_value, \ + "Unexpected value for property {!r}".format(pn) + actprof.pull_full_properties() + for pn, exp_value in actprof_input_props.items(): + assert actprof.properties[pn] == exp_value, \ + "Unexpected value for property {!r}".format(pn) + + # Test updating a property of the activation profile + + new_desc = "Updated activation profile description." + + # The code to be tested + actprof.update_properties(dict(description=new_desc)) + + assert actprof.properties['description'] == new_desc + actprof.pull_full_properties() + assert actprof.properties['description'] == new_desc + + # Test renaming the activation profile + + # The code to be tested + actprof.update_properties(dict(name=actprof_name_new)) + + assert actprof.properties['name'] == actprof_name_new + actprof.pull_full_properties() + assert actprof.properties['name'] == actprof_name_new + with pytest.raises(zhmcclient.NotFound): + actprof_mgr.find(name=actprof_name) + + # Test deleting the activation profile + + # The code to be tested + actprof.delete() + + with pytest.raises(zhmcclient.NotFound): + actprof_mgr.find(name=actprof_name_new) + + @pytest.mark.parametrize( "profile_type", ['reset', 'image', 'load'] ) diff --git a/tests/end2end/utils.py b/tests/end2end/utils.py index e4bc913ab..83f62d325 100644 --- a/tests/end2end/utils.py +++ b/tests/end2end/utils.py @@ -687,6 +687,31 @@ def standard_partition_props(cpc, part_name): return part_input_props +def standard_activation_profile_props(cpc, profile_name, profile_type): + """ + Return the input properties for a standard activation profile in the + specified CPC. + """ + actprof_input_props = { + 'name': profile_name, + 'description': 'Test {} activation profile for zhmcclient end2end ' + 'tests'.format(profile_type), + } + if profile_type == 'image': + if cpc.prop('processor-count-ifl'): + actprof_input_props['number-shared-ifl-processors'] = 1 + elif cpc.prop('processor-count-general-purpose'): + actprof_input_props['number-shared-general-purpose-processors'] = 1 + else: + actprof_input_props['number-shared-general-purpose-processors'] = 1 + warnings.warn( + "CPC {c} shows neither IFL nor CP processors, specifying 1 CP " + "for image activation profile creation.". + format(c=cpc.name), End2endTestWarning) + + return actprof_input_props + + def skip_warn(msg): """ Issue an End2endTestWarning and skip the current pytest testcase with the diff --git a/zhmcclient/_activation_profile.py b/zhmcclient/_activation_profile.py index 0cbe31b62..cc576936b 100644 --- a/zhmcclient/_activation_profile.py +++ b/zhmcclient/_activation_profile.py @@ -221,6 +221,53 @@ def list(self, full_properties=False, filter_args=None, list_uri, result_prop, full_properties, filter_args, additional_properties) + @logged_api_call + def create(self, properties): + """ + Create and configure an Activation Profiles on this CPC, of the profile + type managed by this object. + + Supported only on z16 and later CPCs. + + Authorization requirements: + + * Object-access permission to this CPC. + * Task permission to the "Customize/Delete Activation Profiles" task. + + Parameters: + + properties (dict): Initial property values. + Allowable properties are defined in section 'Request body contents' + in section 'Create Reset/Image/Load Activation Profile' in the + :term:`HMC API` book. + + Returns: + + Partition: + The resource object for the new Activation Profile. + The object will have its 'element-uri' property set as returned by + the HMC, and will also have the input properties set. + + Raises: + + :exc:`~zhmcclient.HTTPError` + :exc:`~zhmcclient.ParseError` + :exc:`~zhmcclient.AuthError` + :exc:`~zhmcclient.ConnectionError` + """ + ap_selector = self._profile_type + '-activation-profiles' + uri = '{}/{}'.format(self.cpc.uri, ap_selector) + result = self.session.post(uri, body=properties) + # There should not be overlaps, but just in case there are, the + # returned props should overwrite the input props: + props = copy.deepcopy(properties) + props.update(result) + name = props.get(self._name_prop, None) + uri = props[self._uri_prop] + profile = ActivationProfile(self, uri, name, props) + self._name_uri_cache.update(name, uri) + return profile + class ActivationProfile(BaseResource): """ @@ -250,6 +297,29 @@ def __init__(self, manager, uri, name=None, properties=None): .format(ActivationProfileManager, type(manager)) super(ActivationProfile, self).__init__(manager, uri, name, properties) + @logged_api_call + def delete(self): + """ + Delete this Activation Profile. + + Supported only on z16 and later CPCs. + + Authorization requirements: + + * Task permission to the "Customize/Delete Activation Profiles" task. + + Raises: + + :exc:`~zhmcclient.HTTPError` + :exc:`~zhmcclient.ParseError` + :exc:`~zhmcclient.AuthError` + :exc:`~zhmcclient.ConnectionError` + """ + # pylint: disable=protected-access + self.manager.session.delete(self.uri, resource=self) + self.manager._name_uri_cache.delete( + self.get_properties_local(self.manager._name_prop, None)) + @logged_api_call def update_properties(self, properties): """