Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Transactional flag #789

Merged
merged 13 commits into from Oct 5, 2023
3 changes: 2 additions & 1 deletion doc/dbus/org.opensuse.Agama.Storage1.Proposal.doc.xml
Expand Up @@ -22,7 +22,8 @@
MinSize t (bytes)
MaxSize t (bytes. Optional, max size is considered as unlimited if omitted)
AutoSize b
Snapshots b
Snapshots b ( makes sense only for btrfs )
Transactional b ( makes sense only for btrfs )
Outline a{sv}
Required b
FsTypes as
Expand Down
17 changes: 9 additions & 8 deletions service/lib/agama/dbus/storage/volume_conversion/to_dbus.rb
Expand Up @@ -35,14 +35,15 @@ def initialize(volume)
# @return [Hash]
def convert
{
"MountPath" => volume.mount_path.to_s,
"MountOptions" => volume.mount_options,
"TargetDevice" => volume.device.to_s,
"TargetVG" => volume.separate_vg_name.to_s,
"FsType" => volume.fs_type&.to_human_string || "",
"MinSize" => volume.min_size&.to_i,
"AutoSize" => volume.auto_size?,
"Snapshots" => volume.btrfs.snapshots?
"MountPath" => volume.mount_path.to_s,
"MountOptions" => volume.mount_options,
"TargetDevice" => volume.device.to_s,
"TargetVG" => volume.separate_vg_name.to_s,
"FsType" => volume.fs_type&.to_human_string || "",
"MinSize" => volume.min_size&.to_i,
"AutoSize" => volume.auto_size?,
"Snapshots" => volume.btrfs.snapshots?,
"Transactional" => volume.btrfs.read_only?
}.tap do |target|
max_size_conversion(target)
outline_conversion(target)
Expand Down
6 changes: 6 additions & 0 deletions service/package/rubygem-agama.changes
@@ -1,3 +1,9 @@
-------------------------------------------------------------------
Wed Oct 4 19:51:32 UTC 2023 - Josef Reidinger <jreidinger@suse.com>

- Add indication to btrfs volumes if it is transactional
(gh#openSUSE/agama#789)

-------------------------------------------------------------------
Fri Sep 29 14:37:25 UTC 2023 - Ancor Gonzalez Sosa <ancor@suse.com>

Expand Down
Expand Up @@ -68,15 +68,16 @@
"SpaceActions" => { "/dev/sda" => :force_delete },
"Volumes" => [
{
"MountPath" => "/test",
"MountOptions" => [],
"TargetDevice" => "",
"TargetVG" => "",
"FsType" => "",
"MinSize" => 0,
"AutoSize" => false,
"Snapshots" => false,
"Outline" => {
"MountPath" => "/test",
"MountOptions" => [],
"TargetDevice" => "",
"TargetVG" => "",
"FsType" => "",
"MinSize" => 0,
"AutoSize" => false,
"Snapshots" => false,
"Transactional" => false,
"Outline" => {
"Required" => false,
"FsTypes" => [],
"SupportAutoSize" => false,
Expand Down
41 changes: 22 additions & 19 deletions service/test/agama/dbus/storage/volume_conversion/to_dbus_test.rb
Expand Up @@ -44,6 +44,7 @@
volume.outline = volume_outline
volume.fs_type = Y2Storage::Filesystems::Type::EXT4
volume.btrfs.snapshots = true
volume.btrfs.read_only = true
volume.mount_options = ["rw", "default"]
volume.device = "/dev/sda"
volume.separate_vg_name = "/dev/system"
Expand All @@ -56,15 +57,16 @@
describe "#convert" do
it "converts the volume to a D-Bus hash" do
expect(described_class.new(default_volume).convert).to eq(
"MountPath" => "/test",
"MountOptions" => [],
"TargetDevice" => "",
"TargetVG" => "",
"FsType" => "",
"MinSize" => 0,
"AutoSize" => false,
"Snapshots" => false,
"Outline" => {
"MountPath" => "/test",
"MountOptions" => [],
"TargetDevice" => "",
"TargetVG" => "",
"FsType" => "",
"MinSize" => 0,
"AutoSize" => false,
"Snapshots" => false,
"Transactional" => false,
"Outline" => {
"Required" => false,
"FsTypes" => [],
"SupportAutoSize" => false,
Expand All @@ -75,16 +77,17 @@
)

expect(described_class.new(custom_volume).convert).to eq(
"MountPath" => "/test",
"MountOptions" => ["rw", "default"],
"TargetDevice" => "/dev/sda",
"TargetVG" => "/dev/system",
"FsType" => "Ext4",
"MinSize" => 1024,
"MaxSize" => 2048,
"AutoSize" => true,
"Snapshots" => true,
"Outline" => {
"MountPath" => "/test",
"MountOptions" => ["rw", "default"],
"TargetDevice" => "/dev/sda",
"TargetVG" => "/dev/system",
"FsType" => "Ext4",
"MinSize" => 1024,
"MaxSize" => 2048,
"AutoSize" => true,
"Snapshots" => true,
"Transactional" => true,
"Outline" => {
"Required" => true,
"FsTypes" => ["Ext3", "Ext4"],
"SupportAutoSize" => true,
Expand Down
5 changes: 5 additions & 0 deletions web/package/cockpit-agama.changes
@@ -1,3 +1,8 @@
-------------------------------------------------------------------
Wed Oct 4 19:52:17 UTC 2023 - Josef Reidinger <jreidinger@suse.com>

- Add flag if volume is transactional btrfs (gh#openSUSE/agama#789)

-------------------------------------------------------------------
Mon Oct 2 08:02:23 UTC 2023 - David Diaz <dgonzalez@suse.com>

Expand Down
6 changes: 5 additions & 1 deletion web/src/client/storage.js
Expand Up @@ -238,6 +238,7 @@ class ProposalManager {
* @property {number} [maxSize]
* @property {boolean} autoSize
* @property {boolean} snapshots
* @property {boolean} transactional
* @property {VolumeOutline} outline
*
* @typedef {object} VolumeOutline
Expand Down Expand Up @@ -348,7 +349,8 @@ class ProposalManager {
MinSize: { t: "t", v: volume.minSize },
MaxSize: { t: "t", v: volume.maxSize },
AutoSize: { t: "b", v: volume.autoSize },
Snapshots: { t: "b", v: volume.snapshots }
Snapshots: { t: "b", v: volume.snapshots },
Transactional: { t: "b", v: volume.transactional },
});
};

Expand Down Expand Up @@ -377,6 +379,7 @@ class ProposalManager {
* @property {CockpitNumber} [MaxSize]
* @property {CockpitBoolean} AutoSize
* @property {CockpitBoolean} Snapshots
* @property {CockpitBoolean} Transactional
* @property {CockpitVolumeOutline} Outline
*
* @typedef {Object} DBusVolumeOutline
Expand Down Expand Up @@ -430,6 +433,7 @@ class ProposalManager {
maxSize: dbusVolume.MaxSize?.v,
autoSize: dbusVolume.AutoSize.v,
snapshots: dbusVolume.Snapshots.v,
transactional: dbusVolume.Transactional.v,
outline: buildOutline(dbusVolume.Outline.v)
};
}
Expand Down
8 changes: 8 additions & 0 deletions web/src/client/storage.test.js
Expand Up @@ -163,6 +163,7 @@ const contexts = {
MaxSize: { t: "x", v: 2048 },
AutoSize: { t: "b", v: true },
Snapshots: { t: "b", v: true },
Transactional: { t: "b", v: true },
Outline: {
t: "a{sv}",
v: {
Expand All @@ -182,6 +183,7 @@ const contexts = {
MaxSize: { t: "x", v: 4096 },
AutoSize: { t: "b", v: false },
Snapshots: { t: "b", v: false },
Transactional: { t: "b", v: false },
Outline: {
t: "a{sv}",
v: {
Expand Down Expand Up @@ -712,6 +714,7 @@ describe("#proposal", () => {
MaxSize: { t: "x", v: 4096 },
AutoSize: { t: "b", v: false },
Snapshots: { t: "b", v: false },
Transactional: { t: "b", v: false },
Outline: {
t: "a{sv}",
v: {
Expand All @@ -731,6 +734,7 @@ describe("#proposal", () => {
MaxSize: { t: "x", v: 2048 },
AutoSize: { t: "b", v: false },
Snapshots: { t: "b", v: false },
Transactional: { t: "b", v: false },
Outline: {
t: "a{sv}",
v: {
Expand Down Expand Up @@ -759,6 +763,7 @@ describe("#proposal", () => {
maxSize: 4096,
autoSize: false,
snapshots: false,
transactional: false,
outline: {
required: false,
fsTypes: ["Ext4", "XFS"],
Expand All @@ -778,6 +783,7 @@ describe("#proposal", () => {
maxSize: 2048,
autoSize: false,
snapshots: false,
transactional: false,
outline: {
required: false,
fsTypes: ["Ext4", "XFS"],
Expand Down Expand Up @@ -825,6 +831,7 @@ describe("#proposal", () => {
maxSize: 2048,
autoSize: true,
snapshots: true,
transactional: true,
outline: {
required: true,
fsTypes: ["Btrfs", "Ext3"],
Expand All @@ -841,6 +848,7 @@ describe("#proposal", () => {
maxSize: 4096,
autoSize: false,
snapshots: false,
transactional: false,
outline: {
required: false,
fsTypes: ["Ext4", "XFS"],
Expand Down
3 changes: 3 additions & 0 deletions web/src/components/storage/ProposalVolumes.jsx
Expand Up @@ -201,6 +201,7 @@ const VolumeRow = ({ columns, volume, options, isLoading, onEdit, onDelete }) =>

const Details = ({ volume, options }) => {
const hasSnapshots = volume.fsType === "Btrfs" && volume.snapshots;
const transactional = volume.fsType === "Btrfs" && volume.transactional;

// TRANSLATORS: the filesystem uses a logical volume (LVM)
const text = `${volume.fsType} ${options.lvm ? _("logical volume") : _("partition")}`;
Expand All @@ -214,6 +215,8 @@ const VolumeRow = ({ columns, volume, options, isLoading, onEdit, onDelete }) =>
<If condition={options.encryption} then={<Em icon={lockIcon}>{_("encrypted")}</Em>} />
{/* TRANSLATORS: filesystem flag, it allows creating snapshots */}
<If condition={hasSnapshots} then={<Em icon={snapshotsIcon}>{_("with snapshots")}</Em>} />
{/* TRANSLATORS: filesystem flag, filesystem is read only */}
jreidinger marked this conversation as resolved.
Show resolved Hide resolved
<If condition={transactional} then={<Em>{_("transactional")}</Em>} />
</div>
);
};
Expand Down
47 changes: 45 additions & 2 deletions web/src/components/storage/ProposalVolumes.test.jsx
Expand Up @@ -40,7 +40,8 @@ const volumes = {
minSize: 1024,
maxSize: 2048,
autoSize: false,
snapshots: true,
snapshots: false,
transactional: false,
outline: {
required: true,
fsTypes: ["Btrfs", "Ext4"],
Expand Down Expand Up @@ -179,7 +180,7 @@ describe("if there are volumes", () => {
const [, body] = await screen.findAllByRole("rowgroup");

expect(within(body).queryAllByRole("row").length).toEqual(3);
within(body).getByRole("row", { name: "/ Btrfs partition with snapshots 1 KiB - 2 KiB" });
within(body).getByRole("row", { name: "/ Btrfs partition 1 KiB - 2 KiB" });
within(body).getByRole("row", { name: "/home XFS partition At least 1 KiB" });
within(body).getByRole("row", { name: "swap Swap partition 1 KiB" });
});
Expand Down Expand Up @@ -216,6 +217,48 @@ describe("if there are volumes", () => {
const mountPointSelector = within(popup).getByRole("combobox", { name: "Mount point" });
expect(mountPointSelector).toHaveAttribute("disabled");
});

describe("and there is transactional Btrfs volume", () => {
beforeEach(() => {
props.volumes = [{ ...volumes.root, transactional: true }];
});

it("renders 'transactional' legend as part of its information", async () => {
plainRender(<ProposalVolumes {...props} />);

const [, volumes] = await screen.findAllByRole("rowgroup");

within(volumes).getByRole("row", { name: "/ Btrfs partition transactional 1 KiB - 2 KiB" });
});
});

describe("and there is Btrfs volume using snapshots", () => {
beforeEach(() => {
props.volumes = [{ ...volumes.root, snapshots: true }];
});

it("renders 'with snapshots' legend as part of its information", async () => {
plainRender(<ProposalVolumes {...props} />);

const [, volumes] = await screen.findAllByRole("rowgroup");

within(volumes).getByRole("row", { name: "/ Btrfs partition with snapshots 1 KiB - 2 KiB" });
});
});

describe("and there is a transactional Btrfs volume using snapshots", () => {
beforeEach(() => {
props.volumes = [{ ...volumes.root, transactional: true, snapshots: true }];
});

it("renders 'with snapshots' and 'transactional' legends as part of its information", async () => {
plainRender(<ProposalVolumes {...props} />);

const [, volumes] = await screen.findAllByRole("rowgroup");

within(volumes).getByRole("row", { name: "/ Btrfs partition with snapshots transactional 1 KiB - 2 KiB" });
});
});
});

describe("if there are not volumes", () => {
Expand Down