Skip to content

Commit

Permalink
Added support for creation and deletion of activation profiles on z16
Browse files Browse the repository at this point in the history
Details:

* Added a create() method to zhmcclient.ActivationProfileManager.

  At this point, the method deals with the fact that the implementation
  does not return any data, and builds the resource URI from the
  provided name (this is documented differently in the API book).

  The method also deals with the fact that all three create
  operations take 'profile-name' as input for the profile name (this is
  documented as 'name' for image and load profiles).

* Added a delete() method to zhmcclient.ActivationProfile.

* Added end2end testcases for create, delete and update.

Signed-off-by: Andreas Maier <[email protected]>
  • Loading branch information
andy-maier committed Nov 12, 2023
1 parent d529b71 commit 9b84948
Show file tree
Hide file tree
Showing 3 changed files with 213 additions and 5 deletions.
5 changes: 5 additions & 0 deletions docs/changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,11 @@ Released: not yet
Job.check_for_completion() and Job.wait_for_completion() already existed.
(issue #1299)

* 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:**
Expand Down
128 changes: 123 additions & 5 deletions tests/end2end/test_activation_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,26 @@

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
runtest_get_properties, setup_logging, End2endTestWarning

urllib3.disable_warnings()

# Logging for zhmcclient HMC interactions and test functions
LOGGING = False
LOG_FILE = 'test_profile.log'

# Properties in minimalistic ActivationProfile objects (e.g. find_by_name())
ACTPROF_MINIMAL_PROPS = ['element-uri', 'name']

Expand All @@ -46,6 +53,117 @@
ACTPROF_VOLATILE_PROPS = []


def standard_activation_profile_props(cpc, profile_name, profile_type):
"""
Return the input properties for creating standard activation profile in the
specified CPC.
"""
actprof_input_props = {
'profile-name': profile_name,
'description': (
'{} profile for zhmcclient end2end tests'.format(profile_type)),
}
if profile_type == 'image':
# We provide the minimum set of properties needed to create a profile.
if cpc.prop('processor-count-ifl'):
actprof_input_props['number-shared-ifl-processors'] = 1
actprof_input_props['operating-mode'] = 'linux-only'
elif cpc.prop('processor-count-general-purpose'):
actprof_input_props['number-shared-general-purpose-processors'] = 1
actprof_input_props['operating-mode'] = 'esa390'
else:
actprof_input_props['number-shared-general-purpose-processors'] = 1
actprof_input_props['operating-mode'] = 'esa390'
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


@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")

logger = setup_logging(LOGGING, 'test_actprof_crud', LOG_FILE)

for cpc in classic_mode_cpcs:
assert not cpc.dpm_enabled

actprof_mgr = getattr(cpc, profile_type + '_activation_profiles')

msg = "Testing on CPC {c}".format(c=cpc.name)
print(msg)
logger.info(msg)

actprof_name = 'ZHMC{}1'.format(profile_type[0].upper())

# Preparation: Ensure clean starting point for this test
try:
_actprof = actprof_mgr.find(name=actprof_name)
except zhmcclient.NotFound:
pass
else:
msg = ("Preparation: Delete {pt} activation profile {ap!r} on CPC "
"{c} from previous run".
format(pt=profile_type, ap=actprof_name, c=cpc.name))
warnings.warn(msg, UserWarning)
logger.info(msg)
_actprof.delete()

# Test creating the activation profile
actprof_input_props = standard_activation_profile_props(
cpc, actprof_name, profile_type)

logger.info("Test: Create %s activation profile %r on CPC %s",
profile_type, actprof_name, cpc.name)

# The code to be tested
actprof = actprof_mgr.create(actprof_input_props)

try:
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():
if pn == 'profile-name':
pn = 'name'
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."

logger.info("Test: Update a property of %s activation profile "
"%r on CPC %s", profile_type, actprof_name, cpc.name)

# 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

finally:
# Test deleting the activation profile (also cleanup)

logger.info("Test: Delete %s activation profile %r on CPC %s",
profile_type, actprof_name, cpc.name)

# The code to be tested
actprof.delete()


@pytest.mark.parametrize(
"profile_type", ['reset', 'image', 'load']
)
Expand Down Expand Up @@ -73,8 +191,8 @@ def test_actprof_find_list(classic_mode_cpcs, profile_type): # noqa: F811
actprof_list = pick_test_resources(actprof_list)

for actprof in actprof_list:
print("Testing on CPC {c} with {t} activation profile {p!r}".
format(c=cpc.name, t=profile_type, p=actprof.name))
print("Testing on CPC {c} with {pt} activation profile {ap!r}".
format(c=cpc.name, pt=profile_type, ap=actprof.name))
if profile_type == 'image':
actprof_additional_props = ACTPROF_ADDITIONAL_PROPS
else:
Expand Down Expand Up @@ -113,8 +231,8 @@ def test_actprof_property(classic_mode_cpcs, profile_type): # noqa: F811
actprof_list = pick_test_resources(actprof_list)

for actprof in actprof_list:
print("Testing on CPC {c} with {t} activation profile {p!r}".
format(c=cpc.name, t=profile_type, p=actprof.name))
print("Testing on CPC {c} with {pt} activation profile {ap!r}".
format(c=cpc.name, pt=profile_type, ap=actprof.name))

# Select a property that is not returned by list()
non_list_prop = 'description'
Expand Down
85 changes: 85 additions & 0 deletions zhmcclient/_activation_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
from __future__ import absolute_import

import copy
import warnings

from ._manager import BaseManager
from ._resource import BaseResource
Expand Down Expand Up @@ -221,6 +222,67 @@ 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.
Note that the input profile name for creation must be provided in
property 'profile-name', even though it shows up on the created
resource in property 'name'. This applies to all three types of
activation profiles.
Returns:
ActivationProfile:
The resource object for the new Activation Profile.
The object will have its 'element-uri' property set, 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)

# The "Create ... Activation Profile" operations do not return the
# resource URI, so we construct it ourselves. Also, these operations
# specify the profile name in input property 'profile-name'.
if result is not None:
warnings.warn(
"The Create {pt} Activation Profile operation now has "
"response data with properties: {pl!r}".
format(pt=self._profile_type, pl=result.keys()), UserWarning)
name = properties['profile-name']
uri = '{}/{}'.format(uri, name)

props = copy.deepcopy(properties)
props[self._uri_prop] = uri
profile = ActivationProfile(self, uri, name, props)
self._name_uri_cache.update(name, uri)
return profile


class ActivationProfile(BaseResource):
"""
Expand Down Expand Up @@ -250,6 +312,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):
"""
Expand Down

0 comments on commit 9b84948

Please sign in to comment.