diff --git a/CHANGELOG.md b/CHANGELOG.md index a1e70cf3..863ec1aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,12 +25,19 @@ 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). -## [3.33.3] - 2024-11-26 +## [3.33.4] - 2024-12-11 + +### Added +- Added support for using either the CFS v2 or v3 API in `sat bootsys`, + depending on the value of the `--cfs-version` command-line option or the + `cfs.api_version` config-file option. + +## [3.33.3] - 2024-12-10 ### Added - Added the ability to sort reports by multiple fields -## [3.33.2] - 2024-11-26 +## [3.33.2] - 2024-12-10 ### Fixed - Added error message and system exit when token file is not found. diff --git a/docs/man/sat-bootsys.8.rst b/docs/man/sat-bootsys.8.rst index f4692e17..adaee678 100644 --- a/docs/man/sat-bootsys.8.rst +++ b/docs/man/sat-bootsys.8.rst @@ -159,6 +159,9 @@ These options apply to both the ``shutdown`` and ``boot`` actions. **--bos-version BOS_VERSION** The version of the BOS API to use when launching BOS sessions. +**--cfs-version CFS_VERSION** + The version of the CFS API to use when querying CFS sessions. + **--cle-bos-template** *CLE_BOS_TEMPLATE* The name of the BOS session template for shutdown or boot of COS (formerly known as CLE) compute nodes. If not specified, no diff --git a/sat/cli/bootsys/parser.py b/sat/cli/bootsys/parser.py index fc388da3..1cdb7e54 100644 --- a/sat/cli/bootsys/parser.py +++ b/sat/cli/bootsys/parser.py @@ -285,6 +285,12 @@ def add_bootsys_subparser(subparsers): help='The version of the BOS API to use for BOS operations', ) + bootsys_parser.add_argument( + '--cfs-version', + choices=['v2', 'v3'], + help='The version of the CFS API to use for CFS operations', + ) + actions_subparsers = bootsys_parser.add_subparsers( metavar='action', dest='action', help='The action to perform.' ) diff --git a/sat/cli/bootsys/service_activity.py b/sat/cli/bootsys/service_activity.py index fa28fef0..7e4da1e3 100644 --- a/sat/cli/bootsys/service_activity.py +++ b/sat/cli/bootsys/service_activity.py @@ -383,9 +383,9 @@ def get_active_sessions(self): Raises: ServiceCheckError: if unable to get the active CFS sessions. """ - cfs_client = CFSClientBase.get_cfs_client(SATSession(), 'v2') + cfs_client = CFSClientBase.get_cfs_client(SATSession(), get_config_value('cfs.api_version')) try: - sessions = cfs_client.get('sessions').json() + sessions = cfs_client.get_sessions() except (APIError, ValueError) as err: raise self.get_err(str(err)) diff --git a/tests/cli/bootsys/test_service_activity.py b/tests/cli/bootsys/test_service_activity.py index 3c332a6b..ebca39e8 100644 --- a/tests/cli/bootsys/test_service_activity.py +++ b/tests/cli/bootsys/test_service_activity.py @@ -495,26 +495,15 @@ def setUp(self): # If not None, causes CFSClient().get() to raise this self.cfs_err = None - # If not None, causes CFSClient().get().json() to raise this - self.json_err = None - - def mock_cfs_get(*args): - if self.cfs_err: - raise self.cfs_err - def json(): - if len(args) != 1 or args[0] != 'sessions': - self.fail('Unexpected get to CFSClient with args: {}'.format(args)) - elif self.json_err: - raise self.json_err - else: - return self.cfs_sessions - return Mock(json=json) + def mock_get_sessions(*args, **kwargs): + for session in self.cfs_sessions: + yield session patch('sat.cli.bootsys.service_activity.SATSession').start() self.mock_cfs_client = patch( 'sat.cli.bootsys.service_activity.CFSClientBase.get_cfs_client').start() - self.mock_cfs_client.return_value.get = mock_cfs_get + self.mock_cfs_client.return_value.get_sessions = mock_get_sessions def tearDown(self): """Stop mocks at the end of each unit test.""" @@ -553,20 +542,15 @@ def test_get_active_sessions_two_active(self): def test_get_active_sessions_api_err(self): """Test get_active_sessions with an API error.""" + self.mock_cfs_client.return_value.get_sessions = Mock( + side_effect=APIError('service unavailable') + ) api_err_msg = 'service unavailable' self.cfs_err = APIError(api_err_msg) err_regex = '^Unable to get active CFS sessions: {}'.format(api_err_msg) with self.assertRaisesRegex(ServiceCheckError, err_regex): self.cfs_checker.get_active_sessions() - def test_get_active_sessions_value_err(self): - """Test get_active_sessions""" - val_err_msg = 'invalid json' - self.json_err = ValueError(val_err_msg) - err_regex = '^Unable to get active CFS sessions: {}'.format(val_err_msg) - with self.assertRaisesRegex(ServiceCheckError, err_regex): - self.cfs_checker.get_active_sessions() - class TestFirmwareActivityChecker(ExtendedTestCase): """Test the FirmwareActivityChecker class.""" diff --git a/tests/test_report.py b/tests/test_report.py index 226720e3..ab54b84b 100644 --- a/tests/test_report.py +++ b/tests/test_report.py @@ -313,7 +313,7 @@ def test_get_formatted_report_json(self): data = json.loads(json_s) for expected, actual in zip(self.entries, data): - self.assertEquals(expected, list(actual.values())) + self.assertEqual(expected, list(actual.values())) def test_get_formatted_report_json_with_xnames(self): """Json dumps should encode XName datatypes as strings. @@ -326,7 +326,7 @@ def test_get_formatted_report_json_with_xnames(self): json_s = report.get_formatted_report('json') data = json.loads(json_s) - self.assertEquals(xname_s, data[0][header_s]) + self.assertEqual(xname_s, data[0][header_s]) def test_print_report(self): """str(report) should depend on the format instance variable.