Skip to content

Commit

Permalink
Merge pull request #1100 from mulkieran/snapshot-support
Browse files Browse the repository at this point in the history
Snapshot support
  • Loading branch information
mulkieran authored Oct 4, 2024
2 parents b8559fe + fae582b commit 9370aff
Show file tree
Hide file tree
Showing 10 changed files with 418 additions and 3 deletions.
84 changes: 84 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,87 @@
stratis-cli 3.7.0 (UNRELEASED)
=================
Required stratisd version 3.7.0

Recommended development environment: Fedora 40
Lowest supported Python interpreter: 3.9.16

* indicates new since stratis-cli 3.6.2 patch release

* Update for r7 D-Bus revision:
https://github.com/stratis-storage/stratis-cli/pull/1035

* Display snapshot origin in filesystem detail view:
https://github.com/stratis-storage/stratis-cli/pull/1045

* Add filesystem detail view:
https://github.com/stratis-storage/stratis-cli/pull/1051

* Add commands to print filesystem metadata:
https://github.com/stratis-storage/stratis-cli/pull/1089

* Add commands to print pool-level metadata:
https://github.com/stratis-storage/stratis-cli/pull/1075

* Improve parsing of Clevis create options:
https://github.com/stratis-storage/stratis-cli/pull/1076
https://github.com/stratis-storage/stratis-cli/pull/1073

- Implement Clevis-related parser errors as parser errors:
https://github.com/stratis-storage/stratis-cli/pull/1060
https://github.com/stratis-storage/stratis-cli/pull/1057
https://github.com/stratis-storage/stratis-cli/pull/1056
https://github.com/stratis-storage/stratis-cli/pull/1053

* Sort JSON output from report by default:
https://github.com/stratis-storage/stratis-cli/pull/1048

* man: Add description of field in filesystem detail view:
https://github.com/stratis-storage/stratis-cli/pull/1097

* man: Add description of fields in pool detail view:
https://github.com/stratis-storage/stratis-cli/pull/1080

* Improve help text for the unbind command:
https://github.com/stratis-storage/stratis-cli/pull/1083

* Refactor filesystem listing code:
https://github.com/stratis-storage/stratis-cli/pull/1050

- Replace use of getpass with custom implementation:
https://github.com/stratis-storage/stratis-cli/pull/1068

- Tidies and Maintenance:
https://github.com/stratis-storage/stratis-cli/pull/1096
https://github.com/stratis-storage/stratis-cli/pull/1095
https://github.com/stratis-storage/stratis-cli/pull/1094
https://github.com/stratis-storage/stratis-cli/pull/1093
https://github.com/stratis-storage/stratis-cli/pull/1092
https://github.com/stratis-storage/stratis-cli/pull/1090
https://github.com/stratis-storage/stratis-cli/pull/1088
https://github.com/stratis-storage/stratis-cli/pull/1086
https://github.com/stratis-storage/stratis-cli/pull/1084
https://github.com/stratis-storage/stratis-cli/pull/1079
https://github.com/stratis-storage/stratis-cli/pull/1077
https://github.com/stratis-storage/stratis-cli/pull/1074
https://github.com/stratis-storage/stratis-cli/pull/1072
https://github.com/stratis-storage/stratis-cli/pull/1070
https://github.com/stratis-storage/stratis-cli/pull/1067
https://github.com/stratis-storage/stratis-cli/pull/1065
https://github.com/stratis-storage/stratis-cli/pull/1064
https://github.com/stratis-storage/stratis-cli/pull/1063
https://github.com/stratis-storage/stratis-cli/pull/1061
https://github.com/stratis-storage/stratis-cli/pull/1059
https://github.com/stratis-storage/stratis-cli/pull/1058
https://github.com/stratis-storage/stratis-cli/pull/1054
https://github.com/stratis-storage/stratis-cli/pull/1052
https://github.com/stratis-storage/stratis-cli/pull/1049
https://github.com/stratis-storage/stratis-cli/pull/1046
https://github.com/stratis-storage/stratis-cli/pull/1043
https://github.com/stratis-storage/stratis-cli/pull/1040
https://github.com/stratis-storage/stratis-cli/pull/1038
https://github.com/stratis-storage/stratis-cli/pull/1036


stratis-cli 3.6.0
=================
Required stratisd version: 3.6.0
Expand Down
9 changes: 8 additions & 1 deletion docs/stratis.txt
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ filesystem set-size-limit <pool_name> <fs_name> <size_limit>::
as the filesystem's current size, use the keyword "current".
filesystem unset-size-limit <pool_name> <fs_name>::
Remove a filesystem size limit previously set.
filesystem schedule-revert <pool_name> <snapshot_name>::
Set a flag so that when the pool is next started, the specified snapshot
will overwrite its origin filesystem.
filesystem cancel-revert <pool_name> <snapshot_name>::
Cancel a scheduled revert.
filesystem debug get-object-path <(--uuid <uuid> |--name <name>)> ::
Look up the D-Bus object path for a filesystem given the UUID or name.
filesystem debug get-metadata <pool_name> [--pretty] [--written] [--fs-name <fs-name>] ::
Expand Down Expand Up @@ -343,7 +348,9 @@ Created::
The time the filesystem was created.

Snapshot origin::
If this filesystem is a snapshot, its origin.
If this filesystem is a snapshot, its origin. If the filesystem is
a snapshot, whether or not it is scheduled to replace its origin
next time the pool is started.

Sizes::
The logical size of the Stratis filesystem, the total space actually
Expand Down
1 change: 1 addition & 0 deletions src/stratis_cli/_actions/_introspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@
<property name="Devnode" type="s" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates" />
</property>
<property name="MergeScheduled" type="b" access="readwrite" />
<property name="Name" type="s" access="read" />
<property name="Origin" type="(bs)" access="read" />
<property name="Pool" type="o" access="read">
Expand Down
7 changes: 5 additions & 2 deletions src/stratis_cli/_actions/_list_filesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ def display(self):
date_parser.parse(fs.Created()).astimezone().strftime("%b %d %Y %H:%M")
)

origin = get_property(fs.Origin(), self.uuid_formatter, "None")
origin = get_property(fs.Origin(), self.uuid_formatter, None)

print(f"UUID: {self.uuid_formatter(fs.Uuid())}")
print(f"Name: {fs.Name()}")
Expand All @@ -186,7 +186,10 @@ def display(self):
print()
print(f"Created: {created}")
print()
print(f"Snapshot origin: {origin}")
print(f'Snapshot origin: {"None" if origin is None else origin}')
if origin is not None:
scheduled = "Yes" if fs.MergeScheduled() else "No"
print(f" Revert scheduled: {scheduled}")
print()
print("Sizes:")
print(f" Logical size of thin device: {total}")
Expand Down
62 changes: 62 additions & 0 deletions src/stratis_cli/_actions/_logical.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from .._constants import Id, IdType
from .._errors import (
StratisCliEngineError,
StratisCliFsMergeScheduledChangeError,
StratisCliFsSizeLimitChangeError,
StratisCliIncoherenceError,
StratisCliNoChangeError,
Expand Down Expand Up @@ -336,3 +337,64 @@ def unset_size_limit(namespace):
raise StratisCliFsSizeLimitChangeError(None)

Filesystem.Properties.SizeLimit.Set(get_object(fs_object_path), (False, ""))

@staticmethod
def schedule_revert(namespace):
"""
Schedule reverting a snapshot into its origin.
"""
# pylint: disable=import-outside-toplevel
from ._data import Filesystem, MOFilesystem, ObjectManager, filesystems, pools

proxy = get_object(TOP_OBJECT)
managed_objects = ObjectManager.Methods.GetManagedObjects(proxy, {})
(pool_object_path, _) = next(
pools(props={"Name": namespace.pool_name})
.require_unique_match(True)
.search(managed_objects)
)
(fs_object_path, fs_info) = next(
filesystems(
props={"Name": namespace.snapshot_name, "Pool": pool_object_path}
)
.require_unique_match(True)
.search(managed_objects)
)

merge_requested = MOFilesystem(fs_info).MergeScheduled()

if bool(merge_requested):
raise StratisCliFsMergeScheduledChangeError(True)

Filesystem.Properties.MergeScheduled.Set(get_object(fs_object_path), True)

@staticmethod
def cancel_revert(namespace):
"""
Cancel reverting a snapshot into its origin.
"""
# pylint: disable=import-outside-toplevel
from ._data import Filesystem, MOFilesystem, ObjectManager, filesystems, pools

proxy = get_object(TOP_OBJECT)
managed_objects = ObjectManager.Methods.GetManagedObjects(proxy, {})
(pool_object_path, _) = next(
pools(props={"Name": namespace.pool_name})
.require_unique_match(True)
.search(managed_objects)
)
(fs_object_path, fs_info) = next(
filesystems(
props={"Name": namespace.snapshot_name, "Pool": pool_object_path}
)
.require_unique_match(True)
.search(managed_objects)
)

mofs = MOFilesystem(fs_info)
(merge_requested, (origin_set, _)) = (mofs.MergeScheduled(), mofs.Origin())

if origin_set and not bool(merge_requested):
raise StratisCliFsMergeScheduledChangeError(False)

Filesystem.Properties.MergeScheduled.Set(get_object(fs_object_path), False)
12 changes: 12 additions & 0 deletions src/stratis_cli/_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,18 @@ def __str__(self):
return f"Filesystem's size limit is exactly {self.value}"


class StratisCliFsMergeScheduledChangeError(StratisCliNoPropertyChangeError):
"""
Raised when the user requests the same filesystems MergeScheduled value
that the filesystem already has.
"""

def __str__(self):
if self.value:
return "Filesystem is already scheduled for a revert operation."
return "Filesystem is not currently scheduled for a revert operation."


class StratisCliHasCacheChangeError(StratisCliNoPropertyChangeError):
"""
Raised when the user request cache initialization, but a cache is already
Expand Down
45 changes: 45 additions & 0 deletions src/stratis_cli/_parser/_logical.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,51 @@ def verify(self, namespace, parser):
"func": LogicalActions.unset_size_limit,
},
),
(
"schedule-revert",
{
"help": (
"Schedule a revert operation for this snapshot filesystem "
"into its origin filesystem"
),
"args": [
(
"pool_name",
{
"help": (
"Name of the pool the snapshot and its origin belong to"
),
},
),
(
"snapshot_name",
{"help": "Name of the snapshot filesystem"},
),
],
"func": LogicalActions.schedule_revert,
},
),
(
"cancel-revert",
{
"help": "Cancel a previously scheduled revert operation",
"args": [
(
"pool_name",
{
"help": (
"Name of the pool the snapshot and its origin belong to"
),
},
),
(
"snapshot_name",
{"help": "Name of the snapshot filesystem"},
),
],
"func": LogicalActions.cancel_revert,
},
),
(
"debug",
{
Expand Down
94 changes: 94 additions & 0 deletions tests/whitebox/integration/logical/test_cancel_revert.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Copyright 2023 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 'cancel-revert'.
"""

# isort: FIRSTPARTY
from dbus_python_client_gen import DPClientInvocationError

# isort: LOCAL
from stratis_cli import StratisCliErrorCodes
from stratis_cli._errors import StratisCliFsMergeScheduledChangeError

from .._misc import RUNNER, SimTestCase, device_name_list

_DEVICE_STRATEGY = device_name_list(1)
_ERROR = StratisCliErrorCodes.ERROR


class FsCancelRevertTestCase(SimTestCase):
"""
Test canceling a filesystem revert.
"""

_MENU = ["--propagate", "filesystem", "cancel-revert"]
_POOLNAME = "pool"
_FSNAME = "nofs"
_SNAPNAME = "snofs"

def setUp(self):
"""
Start the stratisd daemon with the simulator.
"""
super().setUp()
command_line = ["pool", "create", self._POOLNAME] + _DEVICE_STRATEGY()
RUNNER(command_line)

command_line = [
"filesystem",
"create",
self._POOLNAME,
self._FSNAME,
]
RUNNER(command_line)

command_line = [
"filesystem",
"snapshot",
self._POOLNAME,
self._FSNAME,
self._SNAPNAME,
]
RUNNER(command_line)

def test_cancel_revert_when_unscheduled(self):
"""
Cancelling an unscheduled revert should fail.
"""
command_line = self._MENU + [self._POOLNAME, self._SNAPNAME]
self.check_error(StratisCliFsMergeScheduledChangeError, command_line, _ERROR)

def test_cancel_revert_when_no_origin(self):
"""
Cancelling a revert on a filesystem with no origin should fail.
"""
command_line = self._MENU + [self._POOLNAME, self._FSNAME]
self.check_error(DPClientInvocationError, command_line, _ERROR)

def test_cancel_a_revert_twice(self):
"""
Cancelling a revert twice should fail.
"""
command_line = [
"--propagate",
"filesystem",
"schedule-revert",
self._POOLNAME,
self._SNAPNAME,
]
RUNNER(command_line)
command_line = self._MENU + [self._POOLNAME, self._SNAPNAME]
RUNNER(command_line)
self.check_error(StratisCliFsMergeScheduledChangeError, command_line, _ERROR)
Loading

0 comments on commit 9370aff

Please sign in to comment.