Skip to content

Commit

Permalink
CASMCMS-9145: Create BOS option arch_check_requires_ims
Browse files Browse the repository at this point in the history
  • Loading branch information
mharding-hpe committed Oct 2, 2024
1 parent 8ee961b commit e5bd7fc
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 21 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ 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]
### Added
- Added `arch_check_requires_ims` BOS option. This determines whether or not a failure to
get IMS data is considered fatal when validating image architecture in a boot set. By default
this is false. Note that this has no effect for boot sets whose images are not in IMS, nor
for boot sets whose architecture is `Other`.

### Changed
- Refactored some BOS Options code to use abstract base classes, to avoid code duplication.

Expand Down
9 changes: 9 additions & 0 deletions api/openapi.yaml.in
Original file line number Diff line number Diff line change
Expand Up @@ -1063,6 +1063,15 @@ components:
session_limit_required:
type: boolean
description: If true, Sessions cannot be created without specifying the limit parameter.
arch_check_requires_ims:
type: boolean
description: |
This option modifies how BOS behaves when validating the architecture of a boot image in a boot set.
Specifically, this option comes into play when BOS needs data from IMS in order to do this validation, but
IMS is unreachable.
In the above situation, if this option is true, then the validation will fail.
Otherwise, if the option is false, then a warning will be logged, but the validation will not
be failed because of this.
additionalProperties: true
minProperties: 1
maxProperties: 1024
Expand Down
5 changes: 5 additions & 0 deletions src/bos/common/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from typing import Any

DEFAULTS = {
'arch_check_requires_ims': False,
'cleanup_completed_session_ttl': "7d",
'clear_stage': False,
'component_actual_state_ttl': "4h",
Expand Down Expand Up @@ -56,6 +57,10 @@ def get_option(self, key: str) -> Any:
# All these do is convert the response to the appropriate type for the option,
# and return it.

@property
def arch_check_requires_ims(self) -> bool:
return bool(self.get_option('arch_check_requires_ims'))

@property
def cleanup_completed_session_ttl(self) -> str:
return str(self.get_option('cleanup_completed_session_ttl'))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,17 +223,7 @@ def arch(self):
"Boot artifact S3 URL '%s' does not follow the expected IMS image convention",
s3_url)
return None
try:
ims_image_data = get_image(ims_id)
except ImageNotFound:
LOGGER.warning(
"Can't determine architecture of '%s' because image '%s' does not exist in IMS",
s3_url.url, ims_id)
return None
except Exception as err:
LOGGER.error("Error getting IMS image data for '%s' (S3 path '%s'): %s", ims_id,
s3_url.url, exc_type_msg(err))
return None
ims_image_data = get_image(ims_id)
try:
return ims_image_data["arch"]
except KeyError:
Expand Down
25 changes: 19 additions & 6 deletions src/bos/operators/utils/clients/ims.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,18 @@
# backward-compatibility
DEFAULT_IMS_IMAGE_ARCH = 'x86_64'


class ImsError(Exception):
"""
Raised when there are errors in calls to IMS
"""


class TagFailure(Exception):
pass


class ImageNotFound(Exception):
class ImageNotFound(ImsError):
"""
Raised if querying IMS for an image and it is not found
"""
Expand All @@ -69,7 +76,12 @@ def get_image(image_id: str, session: RequestsSession|None=None) -> dict:
session = requests_retry_session()
url=f"{IMAGES_ENDPOINT}/{image_id}"
LOGGER.debug("GET %s", url)
response = session.get(url)
try:
response = session.get(url)
except Exception as err:
msg = f"Exception during GET request to {url}: {exc_type_msg(err)}"
LOGGER.error(msg)
raise ImsError(msg) from err
LOGGER.debug("Response status code=%d, reason=%s, body=%s", response.status_code,
response.reason, compact_response_text(response.text))
try:
Expand All @@ -82,13 +94,14 @@ def get_image(image_id: str, session: RequestsSession|None=None) -> dict:
LOGGER.warning(msg)
raise ImageNotFound(image_id) from err
LOGGER.error(msg)
raise
raise ImsError(msg) from err
try:
return response.json()
except Exception as err:
LOGGER.error("Failed decoding JSON response from getting IMS image %s: %s", image_id,
exc_type_msg(err))
raise
msg = "Failed decoding JSON response from getting IMS image " \
f"{image_id}: {exc_type_msg(err)}"
LOGGER.error(msg)
raise ImsError(msg) from err


def patch_image(image_id: str, data: dict, session: RequestsSession|None=None) -> None:
Expand Down
17 changes: 13 additions & 4 deletions src/bos/server/controllers/v2/boot_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from bos.common.utils import exc_type_msg
from bos.operators.utils.boot_image_metadata import BootImageMetaData
from bos.operators.utils.boot_image_metadata.factory import BootImageMetaDataFactory
from bos.operators.utils.clients.ims import ImageNotFound, ImsError
from bos.operators.utils.clients.s3 import S3Object, ArtifactNotFound
from bos.server.controllers.v2.options import OptionsData
from bos.server.utils import canonize_xname, ParsingException
Expand Down Expand Up @@ -163,7 +164,7 @@ def _validate_boot_set(bs: dict, operation: str, options_data: OptionsData) -> l
raise BootSetError(f"Can't find boot artifacts. Error: {exc_type_msg(err)}") from err

try:
validate_boot_set_arch(bs, image_metadata)
validate_boot_set_arch(bs, options_data=options_data, image_metadata=image_metadata)
except CannotValidateBootSetArch as err:
warning_msgs.append(str(err))
except BootSetError as err:
Expand Down Expand Up @@ -204,7 +205,8 @@ def _validate_boot_set(bs: dict, operation: str, options_data: OptionsData) -> l
return warning_msgs


def validate_boot_set_arch(bs: dict, image_metadata: BootImageMetaData|None=None) -> None:
def validate_boot_set_arch(bs: dict, options_data: OptionsData,
image_metadata: BootImageMetaData|None=None) -> None:
"""
If the boot set architecture is not set to Other, check that the IMS image
architecture matches the boot set architecture (treating a boot set architecture
Expand All @@ -221,7 +223,14 @@ def validate_boot_set_arch(bs: dict, image_metadata: BootImageMetaData|None=None
raise CannotValidateBootSetArch(
f"Can't find boot artifacts: {exc_type_msg(err)}") from err

ims_image_arch = image_metadata.arch
try:
ims_image_arch = image_metadata.arch
except ImageNotFound as err:
raise CannotValidateBootSetArch(str(err)) from err
except ImsError as err:
if options_data.arch_check_requires_ims:
raise err
raise CannotValidateBootSetArch(str(err)) from err

if ims_image_arch is None:
raise CannotValidateBootSetArch("Can't determine architecture of boot artifacts")
Expand Down Expand Up @@ -275,7 +284,7 @@ def validate_sanitize_boot_set(bs_name: str, bs_data: dict, options_data: Option

# Validate the boot set architecture
try:
validate_boot_set_arch(bs_data)
validate_boot_set_arch(bs_data, options_data=options_data)
except CannotValidateBootSetArch as err:
LOGGER.warning('%s', bs_data)
LOGGER.warning("Bboot set '%s': %s", bs_name, err)
Expand Down

0 comments on commit e5bd7fc

Please sign in to comment.