diff --git a/src/bos/common/clients/bss/__init__.py b/src/bos/common/clients/bss/__init__.py new file mode 100644 index 00000000..7bf62fa7 --- /dev/null +++ b/src/bos/common/clients/bss/__init__.py @@ -0,0 +1,24 @@ +# +# MIT License +# +# (C) Copyright 2024 Hewlett Packard Enterprise Development LP +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +from .client import BSSClient diff --git a/src/bos/common/clients/bss/base.py b/src/bos/common/clients/bss/base.py new file mode 100644 index 00000000..c83cbb92 --- /dev/null +++ b/src/bos/common/clients/bss/base.py @@ -0,0 +1,40 @@ +# +# MIT License +# +# (C) Copyright 2021-2024 Hewlett Packard Enterprise Development LP +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +from abc import ABC +import logging + +from bos.common.clients.endpoints import BaseRawEndpoint +from bos.common.utils import PROTOCOL + +LOGGER = logging.getLogger(__name__) + +SERVICE_NAME = 'cray-bss' +ENDPOINT = f"{PROTOCOL}://{SERVICE_NAME}/boot/v1" + + +class BaseBssEndpoint(BaseRawEndpoint, ABC): + """ + This base class provides generic access to the BSS API. + """ + BASE_ENDPOINT = ENDPOINT diff --git a/src/bos/common/clients/bss/boot_parameters.py b/src/bos/common/clients/bss/boot_parameters.py new file mode 100644 index 00000000..280f47c9 --- /dev/null +++ b/src/bos/common/clients/bss/boot_parameters.py @@ -0,0 +1,76 @@ +# +# MIT License +# +# (C) Copyright 2021-2022, 2024 Hewlett Packard Enterprise Development LP +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +import logging + +from .base import BaseBssEndpoint + +LOGGER = logging.getLogger(__name__) + + +class BootParametersEndpoint(BaseBssEndpoint): + ENDPOINT = 'bootparameters' + + def set_bss(self, node_set, kernel_params, kernel, initrd) -> str: + ''' + Tell the Boot Script Service (BSS) which boot artifacts are associated + with each node. + + Currently, this is biased towards 'hosts' (i.e. xnames) rather than + NIDS. + + Args: + node_set (set): A list of nodes to assign the boot artifacts to + kernel_params (string): Kernel parameters to assign to the node + kernel (string): The kernel to assign to the node + initrd (string): The initrd to assign to the node + session (requests Session instance): An existing session to use + + Returns: + The 'bss-referral-token' value from the header of the response from BSS. + + Raises: + KeyError -- 'bss-referral-token' not found in header + requests.exceptions.HTTPError -- An HTTP error encountered while + communicating with the + Hardware State Manager + Exception -- called with empty node_set + ''' + if not node_set: + # Cannot simply return if no nodes are specified, as this function + # is intended to return the response object from BSS. + # Accordingly, an Exception is raised. + raise Exception("set_bss called with empty node_set") + + LOGGER.info("Params: %s", kernel_params) + + # Assignment payload + payload = { + "hosts": list(node_set), + "params": kernel_params, + "kernel": kernel, + "initrd": initrd + } + + return self.put(json=payload, + verify=False).headers['bss-referral-token'] diff --git a/src/bos/common/clients/bss/client.py b/src/bos/common/clients/bss/client.py new file mode 100644 index 00000000..85d58cbe --- /dev/null +++ b/src/bos/common/clients/bss/client.py @@ -0,0 +1,33 @@ +# +# MIT License +# +# (C) Copyright 2024 Hewlett Packard Enterprise Development LP +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +from bos.common.clients.api_client import APIClient + +from .boot_parameters import BootParametersEndpoint + + +class BSSClient(APIClient): + + @property + def boot_parameters(self) -> BootParametersEndpoint: + return self.get_endpoint(BootParametersEndpoint) diff --git a/src/bos/operators/base.py b/src/bos/operators/base.py index 314a0c9f..90129084 100644 --- a/src/bos/operators/base.py +++ b/src/bos/operators/base.py @@ -35,6 +35,7 @@ import time from typing import Generator, List, NoReturn, Type +from bos.common.clients.bss import BSSClient from bos.common.clients.pcs import PCSClient from bos.common.utils import exc_type_msg from bos.common.values import Status @@ -65,7 +66,7 @@ class ApiClients: def __init__(self): #self.bos = BOSClient() - #self.bss = BSSClient() + self.bss = BSSClient() #self.cfs = CFSClient() #self.hsm = HSMClient() #self.ims = IMSClient() @@ -77,7 +78,7 @@ def __enter__(self): Enter context for all API clients """ #self._stack.enter_context(self.bos) - #self._stack.enter_context(self.bss) + self._stack.enter_context(self.bss) #self._stack.enter_context(self.cfs) #self._stack.enter_context(self.hsm) #self._stack.enter_context(self.ims) diff --git a/src/bos/operators/power_on.py b/src/bos/operators/power_on.py index f5684b7a..9dc50af8 100644 --- a/src/bos/operators/power_on.py +++ b/src/bos/operators/power_on.py @@ -35,7 +35,6 @@ from bos.common.utils import exc_type_msg, get_image_id_from_kernel, \ using_sbps_check_kernel_parameters, components_by_id from bos.common.values import Action, Status -from bos.operators.utils.clients import bss from bos.operators.utils.clients.ims import tag_image from bos.operators.utils.clients.cfs import set_cfs from bos.operators.base import BaseOperator, main @@ -152,7 +151,7 @@ def _set_bss(self, boot_artifacts, bos_sessions, retries=5): for key, nodes in boot_artifacts.items(): kernel, kernel_parameters, initrd = key try: - resp = bss.set_bss(node_set=nodes, + resp = self.client.bss.boot_parameters.set_bss(node_set=nodes, kernel_params=kernel_parameters, kernel=kernel, initrd=initrd) diff --git a/src/bos/operators/utils/clients/bss.py b/src/bos/operators/utils/clients/bss.py deleted file mode 100644 index e174aa42..00000000 --- a/src/bos/operators/utils/clients/bss.py +++ /dev/null @@ -1,90 +0,0 @@ -# -# MIT License -# -# (C) Copyright 2019-2024 Hewlett Packard Enterprise Development LP -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR -# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -# OTHER DEALINGS IN THE SOFTWARE. -# -import logging -import json - -from requests.exceptions import HTTPError - -from bos.common.utils import compact_response_text, exc_type_msg, requests_retry_session, PROTOCOL - -LOGGER = logging.getLogger(__name__) -SERVICE_NAME = 'cray-bss' -ENDPOINT = f"{PROTOCOL}://{SERVICE_NAME}/boot/v1" - - -def set_bss(node_set, kernel_params, kernel, initrd, session=None): - ''' - Tell the Boot Script Service (BSS) which boot artifacts are associated - with each node. - - Currently, this is biased towards 'hosts' (i.e. xnames) rather than - NIDS. - - Args: - node_set (set): A list of nodes to assign the boot artifacts to - kernel_params (string): Kernel parameters to assign to the node - kernel (string): The kernel to assign to the node - initrd (string): The initrd to assign to the node - session (requests Session instance): An existing session to use - - Returns: - The response from BSS. - - Raises: - KeyError -- If the boot_artifacts does not find either the initrd - or kernel keys, this error is raised. - ValueError -- if the kernel_parameters contains an 'initrd' - requests.exceptions.HTTPError -- An HTTP error encountered while - communicating with the - Hardware State Manager - ''' - if not node_set: - # Cannot simply return if no nodes are specified, as this function - # is intended to return the response object from BSS. - # Accordingly, an Exception is raised. - raise Exception("set_bss called with empty node_set") - - session = session or requests_retry_session() - LOGGER.info("Params: %s", kernel_params) - url = f"{ENDPOINT}/bootparameters" - - # Assignment payload - payload = { - "hosts": list(node_set), - "params": kernel_params, - "kernel": kernel, - "initrd": initrd - } - - LOGGER.debug("PUT %s for hosts %s", url, node_set) - try: - resp = session.put(url, data=json.dumps(payload), verify=False) - LOGGER.debug("Response status code=%d, reason=%s, body=%s", - resp.status_code, resp.reason, - compact_response_text(resp.text)) - resp.raise_for_status() - return resp - except HTTPError as err: - LOGGER.error(exc_type_msg(err)) - raise