Skip to content

Commit

Permalink
storage: Detect unused space in Stratis pools in general
Browse files Browse the repository at this point in the history
  • Loading branch information
mvollmer committed Aug 25, 2023
1 parent 65a7050 commit c491765
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 0 deletions.
32 changes: 32 additions & 0 deletions pkg/storaged/stratis-details.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import cockpit from "cockpit";
import React from "react";

import { Alert } from "@patternfly/react-core/dist/esm/components/Alert/index.js";
import { Card, CardBody, CardHeader, CardTitle } from '@patternfly/react-core/dist/esm/components/Card/index.js';
import { DescriptionList, DescriptionListDescription, DescriptionListGroup, DescriptionListTerm } from "@patternfly/react-core/dist/esm/components/DescriptionList/index.js";
import { Flex, FlexItem } from "@patternfly/react-core/dist/esm/layouts/Flex/index.js";
Expand Down Expand Up @@ -57,6 +58,17 @@ const _ = cockpit.gettext;

const fsys_min_size = 512 * 1024 * 1024;

export function check_stratis_warnings(client, enter_warning) {
if (!client.features.stratis_grow_blockdevs)
return;

for (const p in client.stratis_pools) {
const blockdevs = client.stratis_pool_blockdevs[p] || [];
if (blockdevs.some(bd => bd.NewPhysicalSize[0] && Number(bd.NewPhysicalSize[1]) > Number(bd.TotalPhysicalSize)))
enter_warning(p, { warning: "unused-blockdevs" });
}
}

function teardown_block(block) {
return for_each_async(block.Configuration, c => block.RemoveConfigurationItem(c, {}));
}
Expand Down Expand Up @@ -621,9 +633,28 @@ export const StratisPoolDetails = ({ client, pool }) => {
pool.ClevisInfo[0] && // pool has consistent clevis config
(!pool.ClevisInfo[1][0] || pool.ClevisInfo[1][1][0] == "tang")); // not bound or bound to "tang"
const tang_url = can_tang && pool.ClevisInfo[1][0] ? JSON.parse(pool.ClevisInfo[1][1][1]).url : null;
const blockdevs = client.stratis_pool_blockdevs[pool.path] || [];
const managed_fsys_sizes = client.features.stratis_managed_fsys_sizes && !pool.Overprovisioning;
const stats = client.stratis_pool_stats[pool.path];

function grow_blockdevs() {
return for_each_async(blockdevs, bd => pool.GrowPhysicalDevice(bd.Uuid));
}

let alert = null;
if (client.features.stratis_grow_blockdevs &&
blockdevs.some(bd => bd.NewPhysicalSize[0] && Number(bd.NewPhysicalSize[1]) > Number(bd.TotalPhysicalSize))) {
alert = (<Alert key="unused-space"
isInline
variant="warning"
title={_("This pool does not use all the space on its block devices.")}>
{_("Some block devices of this pool have grown in size after the pool was created. The pool can be safely grown to use the newly available space.")}
<div className="storage_alert_action_buttons">
<StorageButton onClick={grow_blockdevs}>{_("Grow the pool to take all space")}</StorageButton>
</div>
</Alert>);
}

function add_passphrase() {
dialog_open({
Title: _("Add passphrase"),
Expand Down Expand Up @@ -863,6 +894,7 @@ export const StratisPoolDetails = ({ client, pool }) => {
</Card>);

return <StdDetailsLayout client={client}
alerts={[alert]}
header={header}
sidebar={sidebar}
content={content} />;
Expand Down
3 changes: 3 additions & 0 deletions pkg/storaged/warnings.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import { get_parent } from "./utils.js";
import { check_mismounted_fsys } from "./fsys-tab.jsx";
import { check_stratis_warnings } from "./stratis-details.jsx";

export function find_warnings(client) {
const path_warnings = { };
Expand Down Expand Up @@ -104,5 +105,7 @@ export function find_warnings(client) {
check_mismounted_fsys(client, path, enter_warning);
}

check_stratis_warnings(client, enter_warning);

return path_warnings;
}
64 changes: 64 additions & 0 deletions test/verify/check-storage-stratis
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,70 @@ class TestStorageStratis(storagelib.StorageCase):
# And the pool should be full again
b.wait_visible("button:contains(Create new filesystem):disabled")

@testlib.skipImage("Stratis too old", "rhel-8-*", "centos-8-*")
def testPoolResize(self):
m = self.machine
b = self.browser

self.login_and_go("/storage")

dev = "/dev/sda"
m.add_disk("4G", serial="DISK1")
b.wait_in_text("#drives", dev)

# Create a logical volume that we will later grow
m.execute(f"vgcreate vgroup0 {dev}; lvcreate vgroup0 -n lvol0 -L 1500000256b")
b.wait_in_text("#devices", "vgroup0")

# Create a pool
self.dialog_with_retry(trigger=lambda: self.devices_dropdown("Create Stratis pool"),
expect=lambda: self.dialog_is_present('disks', "lvol0"),
values={"disks": {"lvol0": True}})
b.wait_in_text("#devices", "pool0")
b.wait_in_text("#devices", "1.50 GB Stratis pool")

# Grow the logical volume in Cockpit, the pool should grow automatically
b.click('.sidepanel-row:contains("vgroup0")')
b.wait_visible('#storage-detail')
self.content_tab_action(1, 1, "Grow")
self.dialog({"size": 1600})
b.go("#/")
b.wait_in_text("#devices", "1.60 GB Stratis pool")

# Grow the logical volume from outside of Cockpit, the pool should complain
m.execute("lvresize vgroup0/lvol0 -L +100000256b")
b.wait_visible('.sidepanel-row:contains(pool0) .ct-icon-exclamation-triangle')
b.click('.sidepanel-row:contains("pool0")')
b.wait_visible('#storage-detail')
b.wait_visible('.pf-v5-c-alert:contains("This pool does not use all the space")')
b.click('button:contains("Grow the pool")')
b.wait_not_present('.pf-v5-c-alert')
b.wait_in_text("#detail-header", "1.7 GB")

b.go("#/")

# Grow the logical volume from outside of Cockpit, the logical volume should also complain
m.execute("lvresize vgroup0/lvol0 -L +100000256b")
b.wait_visible('.sidepanel-row:contains(vgroup0) .ct-icon-exclamation-triangle')
b.click('.sidepanel-row:contains("vgroup0")')
b.wait_visible('#storage-detail')
vol_tab = self.content_tab_expand(1, 1)
# First shrink the volume to test whether Cockpit can figure out the right size for that
b.wait_in_text("#detail-content td[data-label=Size]", "1.80 GB")
b.wait_visible(vol_tab + " button:contains(Shrink volume)")
self.content_tab_action(1, 1, "Shrink volume")
b.wait_in_text("#detail-content td[data-label=Size]", "1.70 GB")
b.wait_not_present(vol_tab + " button:contains(Shrink volume)")
# Then enlarge the volume from the outside again and grow the blockdev
m.execute("lvresize vgroup0/lvol0 -L +100000256b")
b.wait_in_text("#detail-content td[data-label=Size]", "1.80 GB")
b.wait_visible(vol_tab + " button:contains(Grow content)")
self.content_tab_action(1, 1, "Grow content")
vol_tab = self.content_tab_expand(1, 1)
b.wait_not_present(vol_tab + " button:contains(Grow content)")
b.go("#/")
b.wait_in_text("#devices", "1.80 GB Stratis pool")


@testlib.skipImage("No Stratis", "debian-*", "ubuntu-*", "arch")
class TestStoragePackagesStratis(packagelib.PackageCase, storagelib.StorageCase):
Expand Down

0 comments on commit c491765

Please sign in to comment.