diff --git a/CHANGELOG.md b/CHANGELOG.md index 4105b927..c46cde36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +## [2.31.0] - 2024-11-01 +### Removed +- Moved BOS reporter to https://github.com/Cray-HPE/bos-reporter + ## [2.30.5] - 2024-10-15 ### Fixed - Fix per-bootset CFS setting diff --git a/Jenkinsfile.github b/Jenkinsfile.github index b5c4aa24..7cf930f2 100644 --- a/Jenkinsfile.github +++ b/Jenkinsfile.github @@ -40,12 +40,9 @@ pipeline { environment { NAME = "cray-bos" - REPORTER_NAME = "bos-reporter" DESCRIPTION = "Cray Management System Boot Orchestration Service (BOS)" - RPTR_SPEC_FILE = "bos-reporter.spec" IS_STABLE = getBuildIsStable() DOCKER_BUILDKIT = "1" - BUILD_METADATA = getRpmRevision(isStable: env.IS_STABLE) } stages { @@ -73,17 +70,6 @@ pipeline { sh "make lint" } } - stage('Add RPM Metadata to bos-reporter') { - steps { - echo "RPM build metadata is ${env.BUILD_METADATA}" - runLibraryScript("addRpmMetaData.sh", env.RPTR_SPEC_FILE) - } - } - stage("RPM Build Prepare") { - steps { - sh "make rpm_prepare" - } - } stage("Build Image and Chart") { parallel { stage('Image') { @@ -110,43 +96,15 @@ pipeline { sh "make chart" } } - stage("RPM Build") { - agent { - docker { - image "arti.hpc.amslabs.hpecorp.net/dstbuildenv-docker-master-local/cray-sle15sp5_build_environment:latest" - reuseNode true - // Support docker in docker for clamav scan - args "-v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker --group-add 999" - } - } - steps { - sh "make rptr_rpm_prepare" - sh "make rptr_rpm" - } - } } } - stage('Publish ') { - parallel { - stage('Image and Chart') { - environment { - DOCKER_VERSION = sh(returnStdout: true, script: "head -1 .docker_version").trim() - } - steps { - publishCsmDockerImage(image: env.NAME, tag: env.DOCKER_VERSION, isStable: env.IS_STABLE) - publishCsmHelmCharts(component: env.NAME, chartsPath: "${WORKSPACE}/kubernetes/.packaged", isStable: env.IS_STABLE) - } - } - stage("RPM Publish") { - steps { - script { - publishCsmRpms(component: env.REPORTER_NAME, pattern: "dist/rpmbuild/RPMS/noarch/*.rpm", os: "noos", arch: "noarch", isStable: env.IS_STABLE) - publishCsmRpms(component: env.REPORTER_NAME, pattern: "dist/rpmbuild/SRPMS/*.rpm", os: "noos", arch: "src", isStable: env.IS_STABLE) - } - sh "make rpm_build_clean" - sh "make rpm_build_source_clean" - } - } + stage('Publish Image and Chart') { + environment { + DOCKER_VERSION = sh(returnStdout: true, script: "head -1 .docker_version").trim() + } + steps { + publishCsmDockerImage(image: env.NAME, tag: env.DOCKER_VERSION, isStable: env.IS_STABLE) + publishCsmHelmCharts(component: env.NAME, chartsPath: "${WORKSPACE}/kubernetes/.packaged", isStable: env.IS_STABLE) } } } diff --git a/Makefile b/Makefile index 35d6b8d3..b614a444 100644 --- a/Makefile +++ b/Makefile @@ -27,8 +27,6 @@ NAME ?= cray-bos CHART_PATH ?= kubernetes DOCKER_VERSION ?= $(shell head -1 .docker_version) -RPM_VERSION ?= $(shell head -1 .version) -RPM_RELEASE ?= $(shell head -1 .rpm_release) API_VERSION ?= $(shell head -1 .api_version) CHART_VERSION ?= $(shell head -1 .chart_version) @@ -38,30 +36,14 @@ ifneq ($(wildcard ${HOME}/.netrc),) DOCKER_ARGS ?= --secret id=netrc,src=${HOME}/.netrc endif -# Common RPM variables -BUILD_METADATA ?= "1~development~$(shell git rev-parse --short HEAD)" - -# We copy the built RPMs to these directories to simplify publishing them -RPM_IMAGE_DIR ?= dist/rpmbuild/RPMS/noarch -SRC_RPM_IMAGE_DIR ?= dist/rpmbuild/SRPMS - -# bos-reporter RPM variables -RPTR_BUILD_DIR ?= $(PWD)/dist/bos-rptr-rpmbuild -RPTR_SPEC_NAME ?= bos-reporter -RPTR_SPEC_FILE ?= ${RPTR_SPEC_NAME}.spec -RPTR_SOURCE_NAME ?= ${RPTR_SPEC_NAME}-${RPM_VERSION}-${RPM_RELEASE} -RPTR_SOURCE_PATH := ${RPTR_BUILD_DIR}/SOURCES/${RPTR_SOURCE_NAME}.tar.bz2 - -all : runbuildprep lint image chart rptr_rpm +all : runbuildprep lint image chart local: cms_meta_tools runbuildprep image chart_setup chart_package chart: chart_setup chart_package chart_test image: image_setup image_build image_build_pylint_errors image_run_pylint_errors image_build_pylint_full image_run_pylint_full -rptr_rpm: rptr_rpm_package_source rptr_rpm_build_source rptr_rpm_build clone_input_files: cp ${CHART_PATH}/${NAME}/Chart.yaml.in ${CHART_PATH}/${NAME}/Chart.yaml cp ${CHART_PATH}/${NAME}/values.yaml.in ${CHART_PATH}/${NAME}/values.yaml - cp bos-reporter.spec.in bos-reporter.spec cp constraints.txt.in constraints.txt cp src/setup.py.in src/setup.py cp api/openapi.yaml.in api/openapi.yaml @@ -81,16 +63,6 @@ chart_setup: lint: ./cms_meta_tools/scripts/runLint.sh -rpm_prepare: - mkdir -p $(RPM_IMAGE_DIR) \ - $(SRC_RPM_IMAGE_DIR) -rptr_rpm_prepare: - rm -rf $(RPTR_BUILD_DIR) - mkdir -p $(RPTR_BUILD_DIR)/SPECS \ - $(RPTR_BUILD_DIR)/SOURCES - cp $(RPTR_SPEC_FILE) $(RPTR_BUILD_DIR)/SPECS/ - cat $(RPTR_SPEC_FILE) $(RPTR_BUILD_DIR)/SPECS/bos-reporter.spec - image_setup: # Create list of BOS Python source files, to be checked later by pylint find src/bos -type f -name \*.py -print | sed 's#^src/#/app/lib/#' | tr '\n' ' ' | tee srclist.txt @@ -117,23 +89,3 @@ chart_package: chart_test: helm lint "${CHART_PATH}/${NAME}" docker run --rm -v ${PWD}/${CHART_PATH}:/apps ${HELM_UNITTEST_IMAGE} -3 ${NAME} - -rptr_rpm_package_source: - tar --transform 'flags=r;s,^,/$(RPTR_SOURCE_NAME)/,' -cvjf $(RPTR_SOURCE_PATH) \ - ./${RPTR_SPEC_FILE} \ - ./src \ - ./LICENSE - -rptr_rpm_build_source: - BUILD_METADATA=$(BUILD_METADATA) rpmbuild -ts $(RPTR_SOURCE_PATH) --define "_topdir $(RPTR_BUILD_DIR)" - cp $(RPTR_BUILD_DIR)/SRPMS/*.rpm $(SRC_RPM_IMAGE_DIR) - -rptr_rpm_build: - BUILD_METADATA=$(BUILD_METADATA) rpmbuild -ba $(RPTR_SPEC_FILE) --define "_topdir $(RPTR_BUILD_DIR)" - cp $(RPTR_BUILD_DIR)/RPMS/noarch/*.rpm $(RPM_IMAGE_DIR) - -rpm_build_clean: - rm -rf $(RPM_IMAGE_DIR)/* - -rpm_build_source_clean: - rm -rf $(SRC_RPM_IMAGE_DIR)/* diff --git a/bos-reporter.spec.in b/bos-reporter.spec.in deleted file mode 100644 index 730e8ff8..00000000 --- a/bos-reporter.spec.in +++ /dev/null @@ -1,117 +0,0 @@ -# -# 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. -# -Name: bos-reporter -License: MIT -Summary: A system service which reports information about a booted node state -Group: System/Management -Version: @RPM_VERSION@ -Release: @RPM_RELEASE@ -Source: %{name}-@RPM_VERSION@-@RPM_RELEASE@.tar.bz2 -BuildArch: noarch -Vendor: HPE -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release} -BuildRequires: python-rpm-macros -BuildRequires: systemd-rpm-macros -BuildRequires: python3-base -Requires: python3-base -Requires: python3-liveness -Requires: python3-requests -Requires: python3-requests-retry-session -Requires: systemd -Requires: cray-auth-utils -Requires: spire-agent - -# Death to Fascist build policies -%define _unpackaged_files_terminate_build 0 -%define _systemdsvcdir /usr/lib/systemd/system -%define craydir /opt/cray - -%description -Provides a systemd service and associated library that reports -BOS' Boot Artifact ID for a node throughout its booted life. - -%prep -%setup -qn %{name}-@RPM_VERSION@-@RPM_RELEASE@ - -%build -pushd ./src -pip3 install setuptools -/usr/bin/python3 setup.py build -popd - -%install -rm -rf %{buildroot} - -pushd ./src -/usr/bin/python3 setup.py install -O1 --skip-build --root %{buildroot} -mkdir -p ${RPM_BUILD_ROOT}%{_systemdsvcdir} -cp bos/reporter/etc/bos-reporter.service %{buildroot}/%{_systemdsvcdir}/bos-reporter.service -chmod +x %{buildroot}/%{python3_sitelib}/bos/reporter/status_reporter/__main__.py -popd -# Remove __pycache__ directories that we don't want in the RPM -find %{buildroot}/%{python3_sitelib}/bos -type d -name __pycache__ -exec rm -rvf {} \; -prune - -%clean -rm -rf %{buildroot} - -%files -%defattr(-,root,root) - -%dir %{python3_sitelib}/bos -%{python3_sitelib}/bos/__init__.py -%{python3_sitelib}/bos/common -%{python3_sitelib}/bos/reporter -%{_systemdsvcdir}/bos-reporter.service - -%pre -%if 0%{?suse_version} -%service_add_pre bos-reporter.service -%endif - -%post -ln -f /opt/cray/cray-spire/spire-agent /usr/bin/bos-reporter-spire-agent -%if 0%{?suse_version} -%service_add_post bos-reporter.service -%else -%systemd_post bos-reporter.service -%endif - -%preun -%if 0%{?suse_version} -%service_del_preun bos-reporter.service -%else -%systemd_preun bos-reporter.service -%endif - -%postun -if [ $1 -eq 0 ];then - rm -f /usr/bin/bos-reporter-spire-agent -fi -%if 0%{?suse_version} -%service_del_postun bos-reporter.service -%else -%systemd_postun_with_restart bos-reporter.service -%endif - -%changelog diff --git a/git_info.conf b/git_info.conf index 1e9bc777..d98211c9 100644 --- a/git_info.conf +++ b/git_info.conf @@ -20,7 +20,7 @@ chart: kubernetes/cray-bos/Chart.yaml # - commit-date: ${GIT_COMMIT_DATE} # - commit-id: "${GIT_COMMIT_ID} -specfile: bos-reporter.spec +#specfile: # For specified Dockerfile lines, the first field specifies the filename of the # Dockerfile. All subsequent lines are the name of the containers where you diff --git a/src/bos/reporter/.reporter_version b/src/bos/reporter/.reporter_version deleted file mode 100644 index 3eefcb9d..00000000 --- a/src/bos/reporter/.reporter_version +++ /dev/null @@ -1 +0,0 @@ -1.0.0 diff --git a/src/bos/reporter/README.md b/src/bos/reporter/README.md deleted file mode 100644 index 3cd1f47e..00000000 --- a/src/bos/reporter/README.md +++ /dev/null @@ -1 +0,0 @@ -The BOS client reports the state of the boot artifacts on the node. Specifically, it reports a Boot Artifact ID that it parses out of the kernel boot parameters found at /proc/cmdline. \ No newline at end of file diff --git a/src/bos/reporter/__init__.py b/src/bos/reporter/__init__.py deleted file mode 100644 index ad2f28a1..00000000 --- a/src/bos/reporter/__init__.py +++ /dev/null @@ -1,42 +0,0 @@ -# -# MIT License -# -# (C) Copyright 2020-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 os -import logging - -PROTOCOL = 'https' -API_GATEWAY_DNS_NAME = os.environ.get('API_GATEWAY_HOST', 'api-gw-service-nmn.local') -SERVICE = 'bos' -API_VERSION = 'v2' -ENDPOINT = f'{PROTOCOL}://{API_GATEWAY_DNS_NAME}/apis/{SERVICE}/{API_VERSION}' - - -class BOSException(Exception): - """ - A Base class that all custom Exceptions from this - project inherits from. - """ - - -# Setup project level loggging options -LOGGER = logging.getLogger(__name__) diff --git a/src/bos/reporter/client.py b/src/bos/reporter/client.py deleted file mode 100644 index 935a80ff..00000000 --- a/src/bos/reporter/client.py +++ /dev/null @@ -1,91 +0,0 @@ -# -# 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. -# -""" -This module is responsible for interacting with BOS in a reliable, authorized -fashion. -""" - -# Standard imports -import os -import logging -import subprocess -import time - -# 3rd party imports -import requests - -# Imports from BOS module -from bos.common.utils import requests_retry_session as common_requests_retry_session - -# Local imports -from . import PROTOCOL - -LOGGER = logging.getLogger('bos.reporter.client') - -TOKEN_DIR = "/etc/opt/cray/tokens/" -ACCESS_TOKEN_PATH = os.path.join(TOKEN_DIR, 'access') -REFRESH_TOKEN_PATH = os.path.join(TOKEN_DIR, 'refresh') - -# Note: There is not a current process in place for what -# would otherwise update the access token, as stored in the -# ACCESS_TOKEN_PATH. Our assumption is that the token lifetime -# is sufficient for us to use it as part of multi-user.target -# right after a node reboots. The code is written to handle -# both kinds of files, should we ever need to extend this -# code to handle token refresh operations. - - -def get_auth_token(path='/opt/cray/auth-utils/bin/get-auth-token'): - """ - Obtain the authorization token. Continually retry until acquired. - """ - # This environment variable needs to be set because the get-auth-token script utilizes it. - if not os.getenv('SPIRE_AGENT_PATH'): - os.environ['SPIRE_AGENT_PATH'] = '/usr/bin/bos-reporter-spire-agent' - while True: - try: - out = subprocess.check_output([path], universal_newlines=True) - out = out.rstrip('\n') - return out - except subprocess.CalledProcessError as e: - LOGGER.error( - 'get_auth_token failed to retrieve authorization token: code=%d: error=%s', - e.returncode, e.output) - except Exception as exc: - LOGGER.exception("Unexpected exception: %s", exc) - LOGGER.info("Spire Token not yet available; retrying in a few seconds.") - time.sleep(2) - -def authorized_requests_retry_session(*pargs, **kwargs) -> requests.session: - """ - Returns a session with the authorization token included in the headers of the session's - requests. - """ - if 'protocol' not in kwargs: - kwargs['protocol'] = PROTOCOL - session = common_requests_retry_session(*pargs, **kwargs) - auth_token = get_auth_token() - headers = {'Authorization': f'Bearer {auth_token}'} - session.headers.update(headers) - return session diff --git a/src/bos/reporter/components/__init__.py b/src/bos/reporter/components/__init__.py deleted file mode 100644 index 50829a8d..00000000 --- a/src/bos/reporter/components/__init__.py +++ /dev/null @@ -1,35 +0,0 @@ -# -# 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. -# -from bos.reporter import BOSException -from bos.reporter import ENDPOINT as BOS_ENDPOINT - -__name = __name__.rsplit('.', maxsplit=1)[-1] -ENDPOINT = f"{BOS_ENDPOINT}/{__name}" - - -class BOSComponentException(BOSException): - """ - A custom base class for all exceptions specific to - interacting with BOS Component endpoints. - """ diff --git a/src/bos/reporter/components/state.py b/src/bos/reporter/components/state.py deleted file mode 100644 index ff5e600d..00000000 --- a/src/bos/reporter/components/state.py +++ /dev/null @@ -1,87 +0,0 @@ -# -# 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. -# -""" -This is a client module to the BOS component state API. - -The primary use for this is to allow nodes to indicate the -state of their boot artifacts as indicate by the BOS Session ID. -""" -import logging -import json -from requests.exceptions import HTTPError, ConnectionError -from urllib3.exceptions import MaxRetryError - -from bos.common.utils import exc_type_msg -from bos.reporter.components import BOSComponentException -from bos.reporter.components import ENDPOINT as COMPONENT_ENDPOINT -from bos.reporter.client import authorized_requests_retry_session - -LOGGER = logging.getLogger(__name__) - - -class UnknownComponent(BOSComponentException): - """ - When we attempt to patch information on a component that doesn't exist. - """ - - -class UnrecognizedResponse(BOSComponentException): - """ - BOS responded in an inconsistent fashion. - """ - - -def patch_component(component, properties, session=None): - """ - For a given , patch the component's using - the BOS API endpoint. - """ - session = session or authorized_requests_retry_session() - component_endpoint = f'{COMPONENT_ENDPOINT}/{component}' - try: - response = session.patch(component_endpoint, json=properties) - except (ConnectionError, MaxRetryError) as ce: - LOGGER.warning("Could not connect to BOS API service: %s", exc_type_msg(ce)) - raise BOSComponentException(ce) from ce - try: - response.raise_for_status() - except HTTPError as hpe: - if response.status_code == 404: - try: - json_response = json.loads(response.text) - raise UnknownComponent(json_response['detail']) from hpe - except json.JSONDecodeError as jde: - raise UnrecognizedResponse( - f"BOS returned a non-json response: {response.text}\n{jde}") from jde - LOGGER.warning("Unexpected response from '%s':\n%s: %s", component_endpoint, - response.status_code, response.text) - raise BOSComponentException(hpe) from hpe - - -def report_state(component, state, session=None): - """ - Report the 's state. - """ - data = {'id': component, 'actual_state': state} - patch_component(component, data, session=session) diff --git a/src/bos/reporter/etc/bos-reporter.service b/src/bos/reporter/etc/bos-reporter.service deleted file mode 100644 index 342dc945..00000000 --- a/src/bos/reporter/etc/bos-reporter.service +++ /dev/null @@ -1,14 +0,0 @@ - -[Unit] -Description=bos-status-reporter reports boot session information periodically to the BOS API -DefaultDependencies=no -After=multi-user.target - -[Service] -Environment="MODULEFLAG=-m" -Environment="MODULENAME=bos.reporter.status_reporter" -Type=simple -ExecStart=/usr/bin/python3 ${MODULEFLAG} ${MODULENAME} - -[Install] -WantedBy=multi-user.target diff --git a/src/bos/reporter/node_identity.py b/src/bos/reporter/node_identity.py deleted file mode 100644 index 88a8dd85..00000000 --- a/src/bos/reporter/node_identity.py +++ /dev/null @@ -1,81 +0,0 @@ -# -# 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. -# -""" -This module contains a set of operations that allow a node to -query its hardware identity. A node's given identity is bestowed -upon it via HSM, however it is not always recorded in the same -way for any given node. -""" - -import os -from bos.reporter import BOSException -from bos.reporter.proc_cmdline import get_value_from_proc_cmdline - - -class UnknownIdentity(BOSException): - """ - For any situation that could arise where the identity of a running - system cannot be ascertained. - """ - - -def xname_from_proc_cmdline(): - """ - Attempts to read the xname from /proc/cmdline and return it. - - If the xname is not found, raise an UnknownIdentity exception. - """ - try: - return get_value_from_proc_cmdline("xname") - except (KeyError, OSError) as exc: - raise UnknownIdentity("'xname' was not discovered on '/proc/cmdline'") from exc - - -def identity_from_environment(): - """ - As an override or replacement for an entry in /proc/cmdline, - check to see if the user has provided an override in the environment. - """ - ident_string = 'NODE_IDENTITY' - try: - return os.environ[ident_string] - except KeyError as exc: - raise UnknownIdentity( - f"Node identity not passed in via environment '{ident_string}'") from exc - - -def read_identity(): - """ - Obtain identity information from defined sources in the desired order. - Return the first viable identity. - If no identity is discovered, raise an UnknownIdentity exception. - """ - for method in (identity_from_environment, - xname_from_proc_cmdline): - try: - return method() - except UnknownIdentity: - continue - raise UnknownIdentity("All available methods used to determine node hardware " - "identity have failed.") diff --git a/src/bos/reporter/proc_cmdline.py b/src/bos/reporter/proc_cmdline.py deleted file mode 100644 index 73b017a9..00000000 --- a/src/bos/reporter/proc_cmdline.py +++ /dev/null @@ -1,63 +0,0 @@ -# -# 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. -# -""" -This module provides a function for parsing the /proc/cmdline special file. -""" - - -def proc_cmdline(): - """ - This generator yields key value pairs from a node's /proc/cmdline file in - the order they appear. - - Emits both tuples and strings. - - Raises: - OSError if it cannot open /proc/cmdline - """ - with open('/proc/cmdline', 'r') as procfile: - boot_options = procfile.read().strip().split(' ') - for entry in boot_options: - try: - yield entry.split('=') - except IndexError: - yield entry - - -def get_value_from_proc_cmdline(key): - """ - Attempts to read the value of a key from /proc/cmdline and return it. - The key is assumed to have a value associated with it. - - If the key is not found, raise a KeyError exception. - """ - for entry in proc_cmdline(): - try: - ekey, value = entry - if ekey == key: - return value - except ValueError: - # Single string values are not interesting to us - continue - raise KeyError(f"Key '{key}' was not discovered on '/proc/cmdline'") diff --git a/src/bos/reporter/status_reporter/__init__.py b/src/bos/reporter/status_reporter/__init__.py deleted file mode 100644 index f4345184..00000000 --- a/src/bos/reporter/status_reporter/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# -# MIT License -# -# (C) Copyright 2021-2022 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. -# diff --git a/src/bos/reporter/status_reporter/__main__.py b/src/bos/reporter/status_reporter/__main__.py deleted file mode 100644 index 59cac910..00000000 --- a/src/bos/reporter/status_reporter/__main__.py +++ /dev/null @@ -1,130 +0,0 @@ -# -# MIT License -# -# (C) Copyright 2020-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 -import sys -import random -import re -from time import sleep - -from bos.common.utils import duration_to_timedelta, exc_type_msg -from bos.reporter.client import authorized_requests_retry_session -from bos.reporter.node_identity import read_identity -from bos.reporter.components.state import report_state, BOSComponentException, UnknownComponent -from bos.reporter.proc_cmdline import get_value_from_proc_cmdline - -# Configure Project Level Logging options when invoked through __main__; -# This allows the whole project to log from their source when invoked through -# __main__, but does not populate standard out streaming when the code -# is imported by other tooling. -try: - LOG_LEVEL = get_value_from_proc_cmdline('bos_log_level') - LOG_LEVEL = getattr(logging, LOG_LEVEL.upper(), logging.WARN) -except KeyError: - LOG_LEVEL = logging.WARN -PROJECT_LOGGER = logging.getLogger('bos') -LOGGER = logging.getLogger('bos.reporter.status_reporter') -LOGGER.setLevel(LOG_LEVEL) -_stream_handler = logging.StreamHandler(sys.stdout) -_stream_handler.setLevel(LOG_LEVEL) -PROJECT_LOGGER.addHandler(_stream_handler) -PROJECT_LOGGER.setLevel(LOG_LEVEL) -TIME_DURATION_PATTERN = re.compile(r"^(\d+?)(\D+?)$", re.M | re.S) - -# The percentage of the total Time To Live (TTL) to wait before reporting status, e.g. -# a state TTL of 4 hours with a ratio of .75 means nodes report every 3 hours. -REPORTING_RATIO = .75 -STATE_UPDATE_FREQUENCY = 14400 # Number of seconds between state updates (4h default) - - -def report_state_until_success(component): - """ - Loop until BOS component information has been registered; - tells BOS the component's (_this_ node) state. - """ - backoff_ceiling = 30 - backoff_scalar = 2 - attempt = 0 - while True: - # Each iteration, wait a bit longer before patching BOS component - # state until the ceiling is reached. - time_to_wait = backoff_scalar * attempt - time_to_wait = min([backoff_ceiling, time_to_wait]) - sleep(time_to_wait) - attempt += 1 - LOGGER.info("Attempt %s of contacting BOS...", attempt) - session = authorized_requests_retry_session() - try: - bss_referral_token = get_value_from_proc_cmdline('bss_referral_token') - state = {'bss_token': bss_referral_token} - report_state(component, state, session) - except UnknownComponent: - LOGGER.warning("BOS has no record of component '%s'; nothing to report.", component) - LOGGER.warning("Will re-attempt patch operation as necessary.") - continue - except BOSComponentException as cce: - LOGGER.warning("Unable to contact BOS to report component status: %s", cce) - continue - except OSError as exc: - LOGGER.error("BOS client encountered an error: %s", exc_type_msg(exc)) - continue - LOGGER.info("Updated the actual_state record for BOS component '%s'.", component) - return - - -def main(): - """ - Read the Boot Artifact ID from the /proc/cmdline and report it to the BOS - API. This reports the booted 'state' of the node to BOS. - """ - component = read_identity() - try: - sleep_time = duration_to_timedelta(get_value_from_proc_cmdline('bos_update_frequency')) - sleep_time = REPORTING_RATIO * sleep_time.total_seconds() - except KeyError: - sleep_time = STATE_UPDATE_FREQUENCY * REPORTING_RATIO - - # In order to reduce overall thundering herd conditions after a full system - # boot, the amount of time between reporting is less than the whole amount - # of time in sleep_time for the first reporting interval. It is thought that - # this optimization decreases overall load on the BOS API for very large systems - # and reduces the likelihood that our horizontal autoscaler unnecessarily increases - # the number of instances serving requests over the lifetime of a session boot. - has_slept_before = False - - while True: - LOGGER.info("Attempting to report status for '%s'", component) - try: - report_state_until_success(component) - except Exception as exp: - LOGGER.error("An error occurred: %s", exc_type_msg(exp)) - if has_slept_before: - sleep(sleep_time) - else: - sleep(sleep_time * random.random()) - has_slept_before = True - LOGGER.info("Now periodically reporting every ~%s seconds.", sleep_time) - - -if __name__ == '__main__': - main() diff --git a/update_versions.conf b/update_versions.conf index d69207fd..fc1adc62 100644 --- a/update_versions.conf +++ b/update_versions.conf @@ -24,18 +24,10 @@ # Many of these sourcefiles do not exist in the repo as static files # They are generated at build time -sourcefile: .version -tag: @RPM_VERSION@ -targetfile: bos-reporter.spec - sourcefile: .version tag: @VERSION@ targetfile: src/setup.py -sourcefile-novalidate: .rpm_release -tag: @RPM_RELEASE@ -targetfile: bos-reporter.spec - sourcefile: .chart_version tag: 0.0.0-chart targetfile: kubernetes/cray-bos/Chart.yaml