diff --git a/pkg/storaged/side-panel.jsx b/pkg/storaged/side-panel.jsx index ece48fd54762..93357f26e0c9 100644 --- a/pkg/storaged/side-panel.jsx +++ b/pkg/storaged/side-panel.jsx @@ -135,7 +135,7 @@ class SidePanelRow extends React.Component { ); else if (client.path_jobs[job_path]) decoration = ; - else if (client.path_warnings[job_path]) + else if (client.path_warnings[job_path] || this.props.hasWarning) decoration = ; return ( diff --git a/pkg/storaged/stratis-details.jsx b/pkg/storaged/stratis-details.jsx index 43bb0b2ffc9f..c493c41ba3b1 100644 --- a/pkg/storaged/stratis-details.jsx +++ b/pkg/storaged/stratis-details.jsx @@ -265,6 +265,7 @@ export function stratis_content_rows(client, pool, options) { const stats = client.stratis_pool_stats[pool.path]; const forced_options = ["x-systemd.requires=stratis-fstab-setup@" + pool.Uuid + ".service"]; const managed_fsys_sizes = client.features.stratis_managed_fsys_sizes && !pool.Overprovisioning; + function render_fsys(fsys, offset) { const block = client.slashdevs_block[fsys.Devnode]; @@ -641,13 +642,13 @@ export const StratisPoolDetails = ({ client, pool }) => { return for_each_async(blockdevs, bd => pool.GrowPhysicalDevice(bd.Uuid)); } - let alert = null; + const alerts = []; if (client.features.stratis_grow_blockdevs && blockdevs.some(bd => bd.NewPhysicalSize[0] && Number(bd.NewPhysicalSize[1]) > Number(bd.TotalPhysicalSize))) { - alert = ( + alerts.push( {_("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.")}
{_("Grow the pool to take all space")} @@ -655,6 +656,26 @@ export const StratisPoolDetails = ({ client, pool }) => { ); } + if (pool.AvailableActions !== "fully_functional") { + let alert_msg = null; + if (pool.AvailableActions === "no_ipc_requests") + alert_msg = _("Some actions are unavailable until the issue is resolved manually."); + if (pool.AvailableActions === "no_pool_changes") + alert_msg = _("Maintainance operations are not possible. Please migrate the data to a new pool."); + + const goToStratisLogs = () => cockpit.jump("/system/logs/#/?prio=warn&_SYSTEMD_UNIT=stratisd.service"); + + alerts.push( + {alert_msg} +
+ {_("View logs")} +
+
); + } + function add_passphrase() { dialog_open({ Title: _("Add passphrase"), @@ -894,7 +915,7 @@ export const StratisPoolDetails = ({ client, pool }) => { ); return ; diff --git a/pkg/storaged/stratis-panel.jsx b/pkg/storaged/stratis-panel.jsx index 9306ee7c3789..a4211296379e 100644 --- a/pkg/storaged/stratis-panel.jsx +++ b/pkg/storaged/stratis-panel.jsx @@ -56,6 +56,7 @@ function stratis_pool_row(client, path) { return { client, name: pool.Name, + hasWarning: pool.AvailableActions !== "fully_operational", key: path, devname: "/dev/stratis/" + pool.Name + "/", detail: cockpit.format(_("$0 Stratis pool"), fmt_size(pool.TotalPhysicalSize)), diff --git a/test/verify/check-storage-stratis b/test/verify/check-storage-stratis index 866a3fcbdb97..b9a74a67f93f 100755 --- a/test/verify/check-storage-stratis +++ b/test/verify/check-storage-stratis @@ -408,6 +408,53 @@ class TestStorageStratis(storagelib.StorageCase): # Check that the entry has disappeared from fstab self.assertEqual(m.execute("grep /run/fsys1 /etc/fstab || true"), "") + def testAlerts(self): + m = self.machine + b = self.browser + + self.login_and_go("/storage") + + dev_1 = "/dev/sda" + m.add_disk("4G", serial="DISK1") + b.wait_in_text("#drives", dev_1) + + dev_2 = "/dev/sdb" + m.add_disk("4G", serial="DISK2") + b.wait_in_text("#drives", dev_2) + + # Create an encrypted pool with two block devices + self.devices_dropdown("Create Stratis pool") + self.dialog_wait_open() + self.dialog_set_val("encrypt_pass.on", val=True) + self.dialog_set_val("passphrase", "foodeeboodeebar") + self.dialog_set_val("passphrase2", "foodeeboodeebar") + self.dialog_set_val("disks", {dev_1: True}) + self.dialog_set_val("disks", {dev_2: True}) + self.dialog_apply() + self.dialog_wait_close() + + b.wait_in_text("#devices", "pool0") + + m.execute(""" +JSON=$(sudo cryptsetup token export --token-id=1 /dev/sda + | jq '.key_description = "stratis-1-key-no-other-is-the-same"') +sudo cryptsetup token remove --token-id=1 /dev/sda +echo $JSON | sudo cryptsetup token import --token-id=1 /dev/sda +systemctl restart stratisd + """) + + b.wait_visible('.sidepanel-row:contains(pool0) .ct-icon-exclamation-triangle') + + b.click('.sidepanel-row:contains("pool0")') + b.wait_visible('.pf-v5-c-alert:contains("This pool is in a degraded state")') + + b.click("button:contains(Create new filesystem)") + self.dialog_wait_open() + self.dialog_set_val("name", "fsys1") + self.dialog_set_val("mount_point", "/run/fsys1") + self.dialog_apply() + self.dialog_wait_alert("Pool is in state NoRequests where this action cannot be performed until the issue is resolved manually") + def testCli(self): m = self.machine b = self.browser