Skip to content

Commit c75b8dd

Browse files
committed
storage: Support for Stratis r8 API
This brings multiple passphrases and keyservers per pool.
1 parent a70142a commit c75b8dd

File tree

7 files changed

+820
-378
lines changed

7 files changed

+820
-378
lines changed

pkg/storaged/client.js

Lines changed: 46 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -728,31 +728,13 @@ function update_indices() {
728728
}
729729

730730
client.blocks_stratis_stopped_pool = { };
731-
client.stratis_stopped_pool_key_description = { };
732-
client.stratis_stopped_pool_clevis_info = { };
733731
for (const uuid in client.stratis_manager.StoppedPools) {
734732
const devs = client.stratis_manager.StoppedPools[uuid].devs.v;
735733
for (const d of devs) {
736734
block = client.slashdevs_block[d.devnode];
737735
if (block)
738736
client.blocks_stratis_stopped_pool[block.path] = uuid;
739737
}
740-
const kinfo = client.stratis_manager.StoppedPools[uuid].key_description;
741-
if (kinfo &&
742-
kinfo.t == "(bv)" &&
743-
kinfo.v[0] &&
744-
kinfo.v[1].t == "(bs)" &&
745-
kinfo.v[1].v[0]) {
746-
client.stratis_stopped_pool_key_description[uuid] = kinfo.v[1].v[1];
747-
}
748-
const cinfo = client.stratis_manager.StoppedPools[uuid].clevis_info;
749-
if (cinfo &&
750-
cinfo.t == "(bv)" &&
751-
cinfo.v[0] &&
752-
cinfo.v[1].t == "(b(ss))" &&
753-
cinfo.v[1].v[0]) {
754-
client.stratis_stopped_pool_clevis_info[uuid] = cinfo.v[1].v[1];
755-
}
756738
}
757739

758740
client.stratis_pool_stats = { };
@@ -1432,62 +1414,63 @@ client.stratis_start = () => {
14321414
// not allowed. If we need to bump it, it should be bumped here for all
14331415
// of them at the same time.
14341416
//
1435-
const stratis3_interface_revision = "r6";
1417+
const stratis3_interface_revisions = [8, 6];
14361418

1437-
function stratis3_start() {
1419+
async function stratis3_start() {
14381420
const stratis = cockpit.dbus("org.storage.stratis3", { superuser: "try" });
1439-
client.stratis_manager = stratis.proxy("org.storage.stratis3.Manager." + stratis3_interface_revision,
1440-
"/org/storage/stratis3");
14411421

14421422
// The rest of the code expects these to be initialized even if no
14431423
// stratisd is found.
14441424
client.stratis_pools = { };
14451425
client.stratis_blockdevs = { };
14461426
client.stratis_filesystems = { };
1447-
client.stratis_manager.StoppedPools = {};
14481427

1449-
return client.stratis_manager.wait()
1450-
.then(() => {
1451-
client.stratis_store_passphrase = (desc, passphrase) => {
1452-
return python.spawn(stratis3_set_key_py, [desc], { superuser: "require" })
1453-
.input(passphrase);
1454-
};
1428+
for (const rev of stratis3_interface_revisions) {
1429+
client.stratis_manager = stratis.proxy("org.storage.stratis3.Manager.r" + rev, "/org/storage/stratis3");
1430+
client.stratis_manager.StoppedPools = {};
1431+
try {
1432+
await client.stratis_manager.wait();
1433+
client.stratis_interface_revision = rev;
1434+
break;
1435+
} catch {
1436+
}
1437+
}
14551438

1456-
client.stratis_set_property = (proxy, prop, sig, value) => {
1457-
// DBusProxy is smart enough to allow "proxy.Prop
1458-
// = value" to just work, but we want to catch any
1459-
// error ourselves, and we want to wait for the
1460-
// method call to complete.
1461-
return stratis.call(proxy.path, "org.freedesktop.DBus.Properties", "Set",
1462-
[proxy.iface, prop, cockpit.variant(sig, value)]);
1463-
};
1439+
if (!client.stratis_interface_revision)
1440+
throw new Error("No supported stratisd API revision found");
14641441

1465-
client.features.stratis = true;
1466-
client.stratis_pools = client.stratis_manager.client.proxies("org.storage.stratis3.pool." +
1467-
stratis3_interface_revision,
1468-
"/org/storage/stratis3",
1469-
{ watch: false });
1470-
client.stratis_blockdevs = client.stratis_manager.client.proxies("org.storage.stratis3.blockdev." +
1471-
stratis3_interface_revision,
1472-
"/org/storage/stratis3",
1473-
{ watch: false });
1474-
client.stratis_filesystems = client.stratis_manager.client.proxies("org.storage.stratis3.filesystem." +
1475-
stratis3_interface_revision,
1476-
"/org/storage/stratis3",
1477-
{ watch: false });
1478-
1479-
// HACK - give us a sneak preview of the "r8"
1480-
// manager. It is used to start V2 pools.
1481-
client.stratis_manager_r8 = stratis.proxy(
1482-
"org.storage.stratis3.Manager.r8",
1483-
"/org/storage/stratis3");
1484-
1485-
return stratis.watch({ path_namespace: "/org/storage/stratis3" }).then(() => {
1486-
client.stratis_manager.client.addEventListener('notify', (event, data) => {
1487-
client.update();
1488-
});
1489-
});
1490-
});
1442+
client.stratis_store_passphrase = (desc, passphrase) => {
1443+
return python.spawn(stratis3_set_key_py, [desc], { superuser: "require" })
1444+
.input(passphrase);
1445+
};
1446+
1447+
client.stratis_set_property = (proxy, prop, sig, value) => {
1448+
// DBusProxy is smart enough to allow "proxy.Prop
1449+
// = value" to just work, but we want to catch any
1450+
// error ourselves, and we want to wait for the
1451+
// method call to complete.
1452+
return stratis.call(proxy.path, "org.freedesktop.DBus.Properties", "Set",
1453+
[proxy.iface, prop, cockpit.variant(sig, value)]);
1454+
};
1455+
1456+
client.features.stratis = true;
1457+
client.stratis_pools = client.stratis_manager.client.proxies("org.storage.stratis3.pool.r" +
1458+
client.stratis_interface_revision,
1459+
"/org/storage/stratis3",
1460+
{ watch: false });
1461+
client.stratis_blockdevs = client.stratis_manager.client.proxies("org.storage.stratis3.blockdev.r" +
1462+
client.stratis_interface_revision,
1463+
"/org/storage/stratis3",
1464+
{ watch: false });
1465+
client.stratis_filesystems = client.stratis_manager.client.proxies("org.storage.stratis3.filesystem.r" +
1466+
client.stratis_interface_revision,
1467+
"/org/storage/stratis3",
1468+
{ watch: false });
1469+
1470+
await stratis.watch({ path_namespace: "/org/storage/stratis3" });
1471+
client.stratis_manager.client.addEventListener('notify', (event, data) => {
1472+
client.update();
1473+
});
14911474
}
14921475

14931476
function init_client(manager, callback) {

pkg/storaged/pages.jsx

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,14 @@ import { Bullseye } from "@patternfly/react-core/dist/esm/layouts/Bullseye/index
3232
import { Button } from "@patternfly/react-core/dist/esm/components/Button/index.js";
3333
import { Table, Thead, Tbody, Tr, Th, Td } from '@patternfly/react-table';
3434
import { EmptyState, EmptyStateBody } from "@patternfly/react-core/dist/esm/components/EmptyState/index.js";
35-
import { ExclamationTriangleIcon, ExclamationCircleIcon } from "@patternfly/react-icons";
35+
import { ExclamationTriangleIcon, ExclamationCircleIcon, HelpIcon } from "@patternfly/react-icons";
3636
import { Page, PageBreadcrumb, PageSection } from "@patternfly/react-core/dist/esm/components/Page/index.js";
3737
import { Breadcrumb, BreadcrumbItem } from "@patternfly/react-core/dist/esm/components/Breadcrumb/index.js";
3838
import { Spinner } from "@patternfly/react-core/dist/esm/components/Spinner/index.js";
3939
import { DescriptionListDescription, DescriptionListGroup, DescriptionListTerm } from "@patternfly/react-core/dist/esm/components/DescriptionList/index.js";
4040
import { Flex, FlexItem } from "@patternfly/react-core/dist/esm/layouts/Flex/index.js";
41+
import { Icon } from "@patternfly/react-core/dist/esm/components/Icon";
42+
import { Popover } from "@patternfly/react-core/dist/esm/components/Popover";
4143

4244
import { decode_filename, block_short_name, fmt_size } from "./utils.js";
4345
import { StorageButton, StorageBarMenu, StorageMenuItem, StorageSize } from "./storage-controls.jsx";
@@ -358,15 +360,15 @@ function make_actions_kebab(actions) {
358360
return <StorageBarMenu menuItems={actions.map(make_menu_item)} isKebab />;
359361
}
360362

361-
const ActionButtons = ({ card }) => {
363+
export const Actions = ({ actions, onlyMenu }) => {
362364
const narrow = useIsNarrow();
363365

364366
function for_menu(action) {
365367
// Determine whether a action should get a button or be in the
366368
// menu
367369

368-
// In a narrow layout, everything goes to the menu
369-
if (narrow)
370+
// When requested or when in a narrow layout, put everything into the menu
371+
if (onlyMenu || narrow)
370372
return true;
371373

372374
// Everything that is dangerous goes to the menu
@@ -379,16 +381,17 @@ const ActionButtons = ({ card }) => {
379381
const buttons = [];
380382
const items = [];
381383

382-
if (!card.actions)
384+
if (!actions)
383385
return null;
384386

385-
for (const a of card.actions) {
387+
for (const a of actions) {
386388
if (for_menu(a))
387389
items.push(make_menu_item(a));
388390
else
389391
buttons.push(
390392
<StorageButton key={a.title} onClick={() => a.action(false)}
391-
kind={a.danger ? "danger" : null} excuse={a.excuse}>
393+
kind={a.danger ? "danger" : null} excuse={a.excuse}
394+
spinner={a.spinner}>
392395
{a.title}
393396
</StorageButton>);
394397
}
@@ -806,7 +809,7 @@ export const StorageCard = ({ card, alert, alerts, actions, children }) => {
806809
<StorageBreadcrumb page={card.page} />
807810
</CardBody>
808811
}
809-
<CardHeader actions={{ actions: actions || <ActionButtons card={card} /> }}>
812+
<CardHeader actions={{ actions: actions || <Actions actions={card.actions} /> }}>
810813
<CardTitle>{card.title}</CardTitle>
811814
</CardHeader>
812815
{(alert || (alerts && alerts.length > 0)) && <CardBody><AlertGroup>{alert}{alerts}</AlertGroup></CardBody>}
@@ -815,7 +818,7 @@ export const StorageCard = ({ card, alert, alerts, actions, children }) => {
815818
</Card>);
816819
};
817820

818-
export const StorageDescription = ({ title, value, action, children }) => {
821+
export const StorageDescription = ({ title, value, action, help, children }) => {
819822
if (!value && !action && !children)
820823
return null;
821824

@@ -830,9 +833,22 @@ export const StorageDescription = ({ title, value, action, children }) => {
830833
content = value || action;
831834
}
832835

836+
let help_popover;
837+
if (help) {
838+
help_popover = (
839+
<Popover headerContent={help}>
840+
<Button component="span" isInline variant="link" aria-label={_("more info")}>
841+
<Icon status="info">
842+
<HelpIcon />
843+
</Icon>
844+
</Button>
845+
</Popover>
846+
);
847+
}
848+
833849
return (
834850
<DescriptionListGroup data-test-desc-title={title}>
835-
<DescriptionListTerm>{title}</DescriptionListTerm>
851+
<DescriptionListTerm>{title} {help_popover}</DescriptionListTerm>
836852
<DescriptionListDescription data-test-value={!(action && value)}>
837853
{content}{children}
838854
</DescriptionListDescription>

pkg/storaged/stratis/create-dialog.jsx

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,23 @@ import { validate_url, get_tang_adv } from "../crypto/tang.jsx";
2828

2929
const _ = cockpit.gettext;
3030

31+
function manager_create_pool(name, devs, key_desc, clevis_info) {
32+
if (client.stratis_interface_revision < 8) {
33+
return client.stratis_manager.CreatePool(name,
34+
devs,
35+
key_desc ? [true, key_desc] : [false, ""],
36+
clevis_info ? [true, clevis_info] : [false, ["", ""]]);
37+
} else {
38+
return client.stratis_manager.CreatePool(name,
39+
devs,
40+
key_desc ? [[[false, 0], key_desc]] : [],
41+
clevis_info ? [[[false, 0], clevis_info[0], clevis_info[1]]] : [],
42+
[false, 0], // journal_size
43+
[false, ""], // tag_spec
44+
[false, false]); // allocate_superblock
45+
}
46+
}
47+
3148
export function create_stratis_pool() {
3249
function find_pool(name) {
3350
for (const p in client.stratis_pools) {
@@ -124,10 +141,7 @@ export function create_stratis_pool() {
124141
let clevis_info = null;
125142
if (adv)
126143
clevis_info = ["tang", JSON.stringify({ url: vals.tang_url, adv })];
127-
return client.stratis_manager.CreatePool(vals.name,
128-
devs,
129-
key_desc ? [true, key_desc] : [false, ""],
130-
clevis_info ? [true, clevis_info] : [false, ["", ""]])
144+
return manager_create_pool(vals.name, devs, key_desc, clevis_info)
131145
.then(std_reply)
132146
.then(result => {
133147
if (vals.overprov && !vals.overprov.on && result[0]) {

0 commit comments

Comments
 (0)