Lin Yang 7754b87ba3 Allow update node properties in RSD 2.4
Change-Id: I4a34f2bf422e917a801c26d28da6860858af507b
2019-03-11 19:42:44 -07:00

217 lines
8.5 KiB
Python

# Copyright 2019 Intel, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from jsonschema import validate
import logging
from sushy import exceptions
from sushy.resources import base
from rsd_lib.resources.v2_3.node import node
from rsd_lib.resources.v2_4.node import schemas as node_schemas
LOG = logging.getLogger(__name__)
PM_OPENATION_ON_DELETE_VALUES = [
'PreserveConfiguration', 'SecureErase', 'OverwritePCD']
class AttachEndpointActionField(base.CompositeField):
target_uri = base.Field('target', required=True)
action_info_path = base.Field('@Redfish.ActionInfo')
action_info = None
class DetachEndpointActionField(base.CompositeField):
target_uri = base.Field('target', required=True)
action_info_path = base.Field('@Redfish.ActionInfo')
action_info = None
class NodeActionsField(node.NodeActionsField):
attach_endpoint = AttachEndpointActionField('#ComposedNode.AttachResource')
detach_endpoint = DetachEndpointActionField('#ComposedNode.DetachResource')
class Node(node.Node):
persistent_memory_operation_on_delete = base.Field(
'PersistentMemoryOperationOnDelete')
"""This property is used to specify what operation should be performed on
Intel OptaneTM DC Persistent Memory on ComposedNode DELETE Request:
- PreserveConfiguration
- SecureErase
- OverwritePCD
"""
_actions = NodeActionsField('Actions', required=True)
def update(self, clear_tpm_on_delete=None, pm_on_delete=None):
"""Update properties of this composed node
:param clear_tpm_on_delete: This is used to specify if TPM module
should be cleared on composed node DELETE request.
:param pm_on_delete: This is used to specify what operation should be
performed on Intel OptaneTM DC Persistent Memory on ComposedNode
DELETE Request:
- PreserveConfiguration
- SecureErase
- OverwritePCD
:raises: InvalidParameterValueError, if any information passed is
invalid.
"""
if clear_tpm_on_delete is None and pm_on_delete is None:
raise ValueError('At least "clear_tpm_on_delete" or "pm_on_delete"'
' parameter has to be specified')
data = {}
if clear_tpm_on_delete is not None:
if not isinstance(clear_tpm_on_delete, bool):
raise exceptions.InvalidParameterValueError(
parameter='clear_tpm_on_delete', value=clear_tpm_on_delete,
valid_values=[True, False])
data['ClearTPMOnDelete'] = clear_tpm_on_delete
if pm_on_delete is not None:
if pm_on_delete not in PM_OPENATION_ON_DELETE_VALUES:
raise exceptions.InvalidParameterValueError(
parameter='pm_on_delete', value=pm_on_delete,
valid_values=PM_OPENATION_ON_DELETE_VALUES)
data['PersistentMemoryOperationOnDelete'] = pm_on_delete
self._conn.patch(self.path, data=data)
class NodeCollection(node.NodeCollection):
@property
def _resource_type(self):
return Node
def __init__(self, connector, path, redfish_version=None):
"""A class representing a NodeCollection
:param connector: A Connector instance
:param path: The canonical path to the Node collection
resource
:param redfish_version: The version of RedFish. Used to construct
the object according to schema of the given version.
"""
super(NodeCollection, self).__init__(connector, path, redfish_version)
def _create_compose_request(self, name=None, description=None,
processor_req=None, memory_req=None,
remote_drive_req=None, local_drive_req=None,
ethernet_interface_req=None,
security_req=None, total_system_core_req=None,
total_system_memory_req=None):
request = {}
if name is not None:
request['Name'] = name
if description is not None:
request['Description'] = description
if processor_req is not None:
validate(processor_req,
node_schemas.processor_req_schema)
request['Processors'] = processor_req
if memory_req is not None:
validate(memory_req,
node_schemas.memory_req_schema)
request['Memory'] = memory_req
if remote_drive_req is not None:
validate(remote_drive_req,
node_schemas.remote_drive_req_schema)
request['RemoteDrives'] = remote_drive_req
if local_drive_req is not None:
validate(local_drive_req,
node_schemas.local_drive_req_schema)
request['LocalDrives'] = local_drive_req
if ethernet_interface_req is not None:
validate(ethernet_interface_req,
node_schemas.ethernet_interface_req_schema)
request['EthernetInterfaces'] = ethernet_interface_req
if security_req is not None:
validate(security_req,
node_schemas.security_req_schema)
request['Security'] = security_req
if total_system_core_req is not None:
validate(total_system_core_req,
node_schemas.total_system_core_req_schema)
request['TotalSystemCoreCount'] = total_system_core_req
if total_system_memory_req is not None:
validate(total_system_memory_req,
node_schemas.total_system_memory_req_schema)
request['TotalSystemMemoryMiB'] = total_system_memory_req
return request
def compose_node(self, name=None, description=None,
processor_req=None, memory_req=None,
remote_drive_req=None, local_drive_req=None,
ethernet_interface_req=None, security_req=None,
total_system_core_req=None, total_system_memory_req=None):
"""Compose a node from RackScale hardware
:param name: Name of node
:param description: Description of node
:param processor_req: JSON for node processors
:param memory_req: JSON for node memory modules
:param remote_drive_req: JSON for node remote drives
:param local_drive_req: JSON for node local drives
:param ethernet_interface_req: JSON for node ethernet ports
:param security_req: JSON for node security requirements
:param total_system_core_req: Total processor cores available in
composed node
:param total_system_memory_req: Total memory available in composed node
:returns: The location of the composed node
When the 'processor_req' is not none: it need a computer system
contains processors whose each processor meet all conditions in the
value.
When the 'total_system_core_req' is not none: it need a computer
system contains processors whose cores sum up to number equal or
greater than 'total_system_core_req'.
When both values are not none: it need meet all conditions.
'memory_req' and 'total_system_memory_req' is the same.
"""
target_uri = self._get_compose_action_element().target_uri
properties = self._create_compose_request(
name=name, description=description,
processor_req=processor_req,
memory_req=memory_req,
remote_drive_req=remote_drive_req,
local_drive_req=local_drive_req,
ethernet_interface_req=ethernet_interface_req,
security_req=security_req,
total_system_core_req=total_system_core_req,
total_system_memory_req=total_system_memory_req)
resp = self._conn.post(target_uri, data=properties)
LOG.info("Node created at %s", resp.headers['Location'])
node_url = resp.headers['Location']
return node_url[node_url.find(self._path):]