Skip to content

Commit

Permalink
storage: Expose Stratis virtual filesystem sizes
Browse files Browse the repository at this point in the history
Instead of the "Managed filesystem sizes" concept. This makes Cockpit
easier to discover when you know the real Stratis concepts and exposes
its full capabilities.
  • Loading branch information
mvollmer committed Jun 18, 2024
1 parent c4d697d commit a62d313
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 54 deletions.
8 changes: 4 additions & 4 deletions pkg/storaged/stratis/create-dialog.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,13 @@ export function create_stratis_pool() {
}),
]
}),
CheckBoxes("managed", "",
CheckBoxes("overprov", "",
{
value: { "on": true },
fields: [
{
tag: "on",
title: _("Manage filesystem sizes"),
tooltip: _("When this option is checked, the new pool will not allow overprovisioning. You need to specify a maximum size for each filesystem that is created in the pool. Filesystems can not be made larger after creation. Snapshots are fully allocated on creation. The sum of all maximum sizes can not exceed the size of the pool. The advantage of this is that filesystems in this pool can not run out of space in a surprising way. The disadvantage is that you need to know the maximum size for each filesystem in advance and creation of snapshots is limited.")
title: _("Overprovisioning"),
}
]
})
Expand All @@ -130,7 +130,7 @@ export function create_stratis_pool() {
clevis_info ? [true, clevis_info] : [false, ["", ""]])
.then(std_reply)
.then(result => {
if (vals.managed && vals.managed.on && result[0]) {
if (vals.overprov && !vals.overprov.on && result[0]) {
const path = result[1][0];
return client.wait_for(() => client.stratis_pools[path])
.then(pool => {
Expand Down
75 changes: 52 additions & 23 deletions pkg/storaged/stratis/filesystem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { CardBody } from "@patternfly/react-core/dist/esm/components/Card/index.
import { DescriptionList } from "@patternfly/react-core/dist/esm/components/DescriptionList/index.js";

import {
dialog_open, TextInput, BlockingMessage, TeardownMessage,
dialog_open, TextInput, CheckBoxes, SizeSlider, BlockingMessage, TeardownMessage,
init_teardown_usage,
} from "../dialog.jsx";
import { StorageUsageBar, StorageLink } from "../storage-controls.jsx";
Expand All @@ -47,7 +47,7 @@ import { std_reply, validate_fs_name, set_mount_options, destroy_filesystem } fr
const _ = cockpit.gettext;

export function make_stratis_filesystem_page(parent, pool, fsys,
offset, forced_options, managed_fsys_sizes) {
offset, forced_options) {
const filesystems = client.stratis_pool_filesystems[pool.path];
const stats = client.stratis_pool_stats[pool.path];
const block = client.slashdevs_block[fsys.Devnode];
Expand All @@ -70,15 +70,6 @@ export function make_stratis_filesystem_page(parent, pool, fsys,
}

function snapshot_fsys() {
if (managed_fsys_sizes && stats.pool_free < Number(fsys.Size)) {
dialog_open({
Title: _("Not enough space"),
Body: cockpit.format(_("There is not enough space in the pool to make a snapshot of this filesystem. At least $0 are required but only $1 are available."),
fmt_size(Number(fsys.Size)), fmt_size(stats.pool_free))
});
return;
}

dialog_open({
Title: cockpit.format(_("Create a snapshot of filesystem $0"), fsys.Name),
Fields: [
Expand Down Expand Up @@ -157,14 +148,11 @@ export function make_stratis_filesystem_page(parent, pool, fsys,
next: null,
page_location: ["pool", pool.Name, fsys.Name],
page_name: fsys.Name,
page_size: (!managed_fsys_sizes
? <StorageUsageBar stats={[Number(fsys.Used[0] && Number(fsys.Used[1])), stats.pool_total]}
critical={1} total={stats.fsys_total_used} offset={offset} short />
: <StorageUsageBar stats={[Number(fsys.Used[0] && Number(fsys.Used[1])), Number(fsys.Size)]}
critical={0.95} short />),
page_size: <StorageUsageBar stats={[Number(fsys.Used[0] && Number(fsys.Used[1])), stats.pool_total]}
critical={1} total={stats.fsys_total_used} offset={offset} short />,
has_warning: !!mismount_warning,
component: StratisFilesystemCard,
props: { pool, fsys, fstab_config, forced_options, managed_fsys_sizes, mismount_warning, offset },
props: { pool, fsys, fstab_config, forced_options, mismount_warning, offset },
actions: [
client.in_anaconda_mode() &&
{ title: _("Edit mount point"), action: () => edit_mount_point(block, forced_options) },
Expand All @@ -180,7 +168,7 @@ export function make_stratis_filesystem_page(parent, pool, fsys,
}

const StratisFilesystemCard = ({
card, pool, fsys, fstab_config, forced_options, managed_fsys_sizes, mismount_warning, offset,
card, pool, fsys, fstab_config, forced_options, mismount_warning, offset,
}) => {
const filesystems = client.stratis_pool_filesystems[pool.path];
const stats = client.stratis_pool_stats[pool.path];
Expand All @@ -206,6 +194,44 @@ const StratisFilesystemCard = ({
});
}

function set_limit() {
dialog_open({
Title: _("Set limit of virtual filesystem size"),
Fields: [
CheckBoxes("size_options", _("Options"),
{
value: {
"custom_limit": fsys.SizeLimit[0],
},
fields: [
{ tag: "custom_limit", title: _("Limit virtual filesystem size") },
]
}),
SizeSlider("limit", _("Virtual size limit"),
{
visible: vals => vals.size_options.custom_limit,
value: fsys.SizeLimit[0] && Number(fsys.SizeLimit[1]),
min: Number(fsys.Size),
max: pool.Overprovisioning ? stats.pool_total : stats.pool_free + Number(fsys.Size),
allow_infinite: true,
round: 512
}),
],
Action: {
Title: _("Set"),
action: async function (vals) {
await client.stratis_set_property(fsys,
"SizeLimit",
"(bs)",(vals.size_options.custom_limit
? [true, vals.limit.toString()]
: [false, ""]));
}
}
});
}

console.log("FS", fsys);

return (
<StorageCard card={card}
alert={mismount_warning &&
Expand All @@ -224,13 +250,16 @@ const StratisFilesystemCard = ({
backing_block={block} content_block={block} />
</StorageDescription>
<StorageDescription title={_("Usage")}>
{(!managed_fsys_sizes
? <StorageUsageBar stats={[Number(fsys.Used[0] && Number(fsys.Used[1])), stats.pool_total]}
<StorageUsageBar stats={[Number(fsys.Used[0] && Number(fsys.Used[1])), stats.pool_total]}
critical={1} total={stats.fsys_total_used} offset={offset} />
: <StorageUsageBar stats={[Number(fsys.Used[0] && Number(fsys.Used[1])), Number(fsys.Size)]}
critical={0.95} />)
}
</StorageDescription>
<StorageDescription title={_("Virtual size")}
value={fmt_size(Number(fsys.Size))}/>
<StorageDescription title={_("Virtual size limit")}
value={fsys.SizeLimit[0] ? fmt_size(Number(fsys.SizeLimit[1])) : _("none")}
action={<StorageLink onClick={set_limit}>
{_("edit")}
</StorageLink>} />
</DescriptionList>
</CardBody>
</StorageCard>
Expand Down
74 changes: 47 additions & 27 deletions pkg/storaged/stratis/pool.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { Flex, FlexItem } from "@patternfly/react-core/dist/esm/layouts/Flex/ind
import { VolumeIcon } from "../icons/gnome-icons.jsx";
import { fmt_to_fragments } from "utils.jsx";

import { StorageButton, StorageUsageBar, StorageLink } from "../storage-controls.jsx";
import { StorageButton, StorageUsageBar, StorageLink, StorageOnOff } from "../storage-controls.jsx";
import {
StorageCard, StorageDescription, ChildrenTable, PageTable,
new_page, new_card, PAGE_CATEGORY_VIRTUAL,
Expand All @@ -43,7 +43,7 @@ import {
} from "../utils.js";

import {
dialog_open, SelectSpaces, TextInput, PassInput, SelectOne, SizeSlider,
dialog_open, SelectSpaces, TextInput, PassInput, SelectOne, SizeSlider, CheckBoxes,
BlockingMessage, TeardownMessage,
init_teardown_usage
} from "../dialog.jsx";
Expand Down Expand Up @@ -72,7 +72,6 @@ function create_fs(pool) {
const filesystems = client.stratis_pool_filesystems[pool.path];
const stats = client.stratis_pool_stats[pool.path];
const forced_options = ["x-systemd.requires=stratis-fstab-setup@" + pool.Uuid + ".service"];
const managed_fsys_sizes = !pool.Overprovisioning;

let action_variants;
if (!client.in_anaconda_mode()) {
Expand All @@ -93,11 +92,31 @@ function create_fs(pool) {
{
validate: name => validate_fs_name(null, name, filesystems)
}),
SizeSlider("size", _("Size"),
CheckBoxes("size_options", _("Manage virtual size"),
{
visible: () => managed_fsys_sizes,
value: {
"custom_size": !pool.Overprovisioning,
"custom_limit": false,
},
fields: [
{ tag: "custom_size", title: _("Specify initial virtual filesystem size") },
{ tag: "custom_limit", title: _("Limit virtual filesystem size") },
]
}),
SizeSlider("size", _("Initial virtual size"),
{
visible: vals => vals.size_options.custom_size,
min: fsys_min_size,
max: pool.Overprovisioning ? stats.pool_total : stats.pool_free,
allow_infinite: pool.Overprovisioning,
round: 512
}),
SizeSlider("limit", _("Virtual size limit"),
{
visible: vals => vals.size_options.custom_limit,
min: fsys_min_size,
max: stats.pool_free,
max: pool.Overprovisioning ? stats.pool_total : stats.pool_free,
allow_infinite: true,
round: 512
}),
TextInput("mount_point", _("Mount point"),
Expand All @@ -116,12 +135,12 @@ function create_fs(pool) {
Action: {
Variants: action_variants,
action: async function (vals) {
let size_spec = [false, ""];

if (managed_fsys_sizes)
let size_spec = [false, ""], limit_spec = [false, ""];
if (vals.size_options.custom_size)
size_spec = [true, vals.size.toString()];

const result = await pool.CreateFilesystems([[vals.name, size_spec, [false, ""]]]).then(std_reply);
if (vals.size_options.custom_limit)
limit_spec = [true, vals.limit.toString()];
const result = await pool.CreateFilesystems([[vals.name, size_spec, limit_spec]]).then(std_reply);
if (result[0])
await set_mount_options(result[1][0][0], vals, forced_options);
}
Expand Down Expand Up @@ -244,20 +263,17 @@ function make_stratis_filesystem_pages(parent, pool) {
const filesystems = client.stratis_pool_filesystems[pool.path];
const stats = client.stratis_pool_stats[pool.path];
const forced_options = ["x-systemd.requires=stratis-fstab-setup@" + pool.Uuid + ".service"];
const managed_fsys_sizes = !pool.Overprovisioning;

filesystems.forEach((fs, i) => make_stratis_filesystem_page(parent, pool, fs,
stats.fsys_offsets[i],
forced_options,
managed_fsys_sizes));
forced_options));
}

export function make_stratis_pool_page(parent, pool) {
const degraded_ops = pool.AvailableActions && pool.AvailableActions !== "fully_operational";
const blockdevs = client.stratis_pool_blockdevs[pool.path] || [];
const can_grow = blockdevs.some(bd => (bd.NewPhysicalSize[0] &&
Number(bd.NewPhysicalSize[1]) > Number(bd.TotalPhysicalSize)));
const managed_fsys_sizes = !pool.Overprovisioning;
const stats = client.stratis_pool_stats[pool.path];

const use = pool.TotalPhysicalUsed[0] && [Number(pool.TotalPhysicalUsed[1]), Number(pool.TotalPhysicalSize)];
Expand All @@ -272,11 +288,11 @@ export function make_stratis_pool_page(parent, pool) {
page_name: pool.Name,
page_icon: VolumeIcon,
page_category: PAGE_CATEGORY_VIRTUAL,
page_size: ((!managed_fsys_sizes && use)
page_size: (use
? <StorageUsageBar key="s" stats={use} short />
: Number(pool.TotalPhysicalSize)),
component: StratisPoolCard,
props: { pool, degraded_ops, can_grow, managed_fsys_sizes, stats },
props: { pool, degraded_ops, can_grow, stats },
actions: [
{
title: _("Add block devices"),
Expand All @@ -295,14 +311,11 @@ export function make_stratis_pool_page(parent, pool) {
next: pool_card,
has_warning: degraded_ops || can_grow,
component: StratisFilesystemsCard,
props: { pool, degraded_ops, can_grow, managed_fsys_sizes, stats },
props: { pool, degraded_ops, can_grow, stats },
actions: [
{
title: _("Create new filesystem"),
action: () => create_fs(pool),
excuse: (managed_fsys_sizes && stats.pool_free < fsys_min_size
? _("Not enough space")
: null),
},
],

Expand All @@ -312,7 +325,7 @@ export function make_stratis_pool_page(parent, pool) {
make_stratis_filesystem_pages(p, pool);
}

const StratisFilesystemsCard = ({ card, pool, degraded_ops, can_grow, managed_fsys_sizes, stats }) => {
const StratisFilesystemsCard = ({ card, pool, degraded_ops, can_grow, stats }) => {
const blockdevs = client.stratis_pool_blockdevs[pool.path] || [];

function grow_blockdevs() {
Expand Down Expand Up @@ -359,7 +372,7 @@ const StratisFilesystemsCard = ({ card, pool, degraded_ops, can_grow, managed_fs
);
};

const StratisPoolCard = ({ card, pool, degraded_ops, can_grow, managed_fsys_sizes, stats }) => {
const StratisPoolCard = ({ card, pool, degraded_ops, can_grow, stats }) => {
const key_desc = (pool.Encrypted &&
pool.KeyDescription[0] &&
pool.KeyDescription[1][1]);
Expand Down Expand Up @@ -514,11 +527,18 @@ const StratisPoolCard = ({ card, pool, degraded_ops, can_grow, managed_fsys_size
{_("edit")}
</StorageLink>} />
<StorageDescription title={_("UUID")} value={pool.Uuid} />
{ !managed_fsys_sizes && use &&
<StorageDescription title={_("Usage")}>
<StorageUsageBar stats={use} critical={0.95} />
</StorageDescription>
{ use &&
<StorageDescription title={_("Usage")}>
<StorageUsageBar stats={use} critical={0.95} />
</StorageDescription>
}
<StorageDescription title={_("Overprovisioning")}>
<StorageOnOff state={pool.Overprovisioning}
aria-label={_("Allow overprovisioning")}
onChange={() => client.stratis_set_property(pool,
"Overprovisioning",
"b", !pool.Overprovisioning)} />
</StorageDescription>
{ pool.Encrypted &&
<StorageDescription title={_("Passphrase")}>
<Flex>
Expand Down

0 comments on commit a62d313

Please sign in to comment.