Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for creation and deletion of activation profiles on z16 #1330

Merged
merged 1 commit into from
Nov 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading