diff --git a/.packit.yaml b/.packit.yaml index b69835903..726d4abee 100644 --- a/.packit.yaml +++ b/.packit.yaml @@ -26,7 +26,6 @@ jobs: - job: copr_build trigger: pull_request identifier: copr_pull - manual_trigger: true targets: - fedora-all diff --git a/docs/stratis.txt b/docs/stratis.txt index 920630ab2..9a4b27af5 100644 --- a/docs/stratis.txt +++ b/docs/stratis.txt @@ -76,6 +76,8 @@ pool init-cache [..]:: drives, such as SSDs, are used for this purpose. pool add-cache [..]:: Add one or more blockdevs to an existing pool with an initialized cache. +pool remove-cache <(--uuid |--name )>:: + Remove a pool's cache. pool extend-data [--device-uuid ]:: Increase the pool's data capacity with additional storage space offered by its component data devices through, e.g., expansion of a component RAID diff --git a/src/stratis_cli/_actions/_introspect.py b/src/stratis_cli/_actions/_introspect.py index ac03f6fd9..6c8e580ab 100644 --- a/src/stratis_cli/_actions/_introspect.py +++ b/src/stratis_cli/_actions/_introspect.py @@ -246,6 +246,11 @@ + + + + + diff --git a/src/stratis_cli/_actions/_pool.py b/src/stratis_cli/_actions/_pool.py index 4306077bf..e8eedbc62 100644 --- a/src/stratis_cli/_actions/_pool.py +++ b/src/stratis_cli/_actions/_pool.py @@ -619,6 +619,47 @@ def add_cache_devices(namespace: Namespace): ) ) + @staticmethod + def remove_cache(namespace: Namespace): + """ + Remove the cache from this pool. + + :raises StratisCliEngineError: + :raises StratisCliIncoherenceError: + :raises StratisCliNoChangeError: + """ + from ._data import MOPool, ObjectManager, Pool, pools # noqa: PLC0415 + + pool_id = PoolId.from_parser_namespace(namespace) + assert pool_id is not None + + proxy = get_object(TOP_OBJECT) + managed_objects = ObjectManager.Methods.GetManagedObjects(proxy, {}) + + (pool_object_path, pool_info) = next( + pools(props=pool_id.managed_objects_key()) + .require_unique_match(True) + .search(managed_objects) + ) + + if not bool(MOPool(pool_info).HasCache()): + raise StratisCliNoChangeError("remove-cache", "cache") + + ((removed, devs_removed), return_code, message) = Pool.Methods.RemoveCache( + get_object(pool_object_path), {} + ) + + if return_code != StratisdErrors.OK: # pragma: no cover + raise StratisCliEngineError(return_code, message) + + if not removed: # pragma: no cover + raise StratisCliIncoherenceError( + ( + f"Expected to remove the cache from {pool_id} but " + "stratisd reports that it did not remove the cache." + ) + ) + @staticmethod def extend_data(namespace: Namespace): """ diff --git a/src/stratis_cli/_parser/_pool.py b/src/stratis_cli/_parser/_pool.py index 1e8d959de..d7a8b101a 100644 --- a/src/stratis_cli/_parser/_pool.py +++ b/src/stratis_cli/_parser/_pool.py @@ -426,6 +426,22 @@ def verify(self, namespace: Namespace, parser: ArgumentParser): "func": PoolActions.add_cache_devices, }, ), + ( + "remove-cache", + { + "help": "Remove an active pool's cache", + "func": PoolActions.remove_cache, + "groups": [ + ( + "Pool Identifier", + { + "description": ("Choose one option to specify the pool"), + "mut_ex_args": [(True, UUID_OR_NAME)], + }, + ) + ], + }, + ), ( "extend-data", { diff --git a/tests/integration/pool/test_remove_cache.py b/tests/integration/pool/test_remove_cache.py new file mode 100644 index 000000000..954f336e0 --- /dev/null +++ b/tests/integration/pool/test_remove_cache.py @@ -0,0 +1,81 @@ +# Copyright 2026 Red Hat, Inc. +# +# 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. +""" +Test 'remove-cache'. +""" + +from uuid import uuid4 + +from dbus_client_gen import DbusClientUniqueResultError +from stratis_cli import StratisCliErrorCodes +from stratis_cli._errors import StratisCliNoChangeError + +from .._misc import RUNNER, TEST_RUNNER, SimTestCase, device_name_list + +_DEVICE_STRATEGY = device_name_list(1, 1) +_DEVICE_STRATEGY_2 = device_name_list(2, 2) +_ERROR = StratisCliErrorCodes.ERROR + + +class RemoveCacheTestCase1(SimTestCase): + """ + Test removing a cache where the cache is non-existent. + """ + + _MENU = ["--propagate", "pool", "remove-cache"] + _POOLNAME = "deadpool" + + def setUp(self): + super().setUp() + command_line = ["pool", "create", self._POOLNAME] + _DEVICE_STRATEGY() + RUNNER(command_line) + + def test_remove(self): + """ + Verify that trying to remove a non-existent cache returns + StratisCliNoChangeError. + """ + command_line = self._MENU + [f"--name={self._POOLNAME}"] + self.check_error(StratisCliNoChangeError, command_line, _ERROR) + + def test_non_existent_pool(self): + """ + Verify that trying to remove a cache from a non-existent pool raises + DbusClientUniqueResultError. + """ + command_line = self._MENU + [f"--uuid={uuid4()}"] + self.check_error(DbusClientUniqueResultError, command_line, _ERROR) + + +class RemoveCacheTestCase2(SimTestCase): + """ + Test removing a cache. + """ + + _MENU = ["--propagate", "pool", "remove-cache"] + _POOLNAME = "deadpool" + + def setUp(self): + super().setUp() + command_line = ["pool", "create", self._POOLNAME] + _DEVICE_STRATEGY() + RUNNER(command_line) + command_line = ["pool", "init-cache", self._POOLNAME] + _DEVICE_STRATEGY_2() + RUNNER(command_line) + + def test_remove(self): + """ + Verify that remove an existing cache succeeds. + """ + command_line = self._MENU + [f"--name={self._POOLNAME}"] + TEST_RUNNER(command_line)