Skip to content

Commit

Permalink
storage: Redesign
Browse files Browse the repository at this point in the history
Co-authored-by: Garrett LeSage <garrett@redhat.com>
  • Loading branch information
mvollmer and garrett committed Dec 1, 2023
1 parent e82aa59 commit a5f87a9
Show file tree
Hide file tree
Showing 115 changed files with 9,069 additions and 8,944 deletions.
58 changes: 0 additions & 58 deletions pkg/storaged/block-details.jsx

This file was deleted.

110 changes: 110 additions & 0 deletions pkg/storaged/block/create-pages.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* This file is part of Cockpit.
*
* Copyright (C) 2023 Red Hat, Inc.
*
* Cockpit is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* Cockpit is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
*/

import client from "../client";

import { get_fstab_config } from "../filesystem/utils.jsx";

import { make_partition_table_page } from "../partitions/partition-table.jsx";
import { make_legacy_vdo_page } from "../legacy-vdo/legacy-vdo.jsx";

import { make_unrecognized_data_card } from "./unrecognized-data.jsx";
import { make_unformatted_data_card } from "./unformatted-data.jsx";
import { make_locked_encrypted_data_card } from "../crypto/locked-encrypted-data.jsx";
import { make_filesystem_card } from "../filesystem/filesystem.jsx";
import { make_lvm2_physical_volume_card } from "../lvm2/physical-volume.jsx";
import { make_mdraid_disk_card } from "../mdraid/mdraid-disk.jsx";
import { make_stratis_blockdev_card } from "../stratis/blockdev.jsx";
import { make_swap_card } from "../swap/swap.jsx";
import { make_encryption_card } from "../crypto/encryption.jsx";

import { new_page } from "../pages.jsx";

/* CARD must have page_name, page_location, and page_size set.
*/

export function make_block_page(parent, block, card) {
let is_crypto = block.IdUsage == 'crypto';
let content_block = is_crypto ? client.blocks_cleartext[block.path] : block;
const fstab_config = get_fstab_config(content_block || block, true);

const block_stratis_blockdev = client.blocks_stratis_blockdev[block.path];
const block_stratis_stopped_pool = client.blocks_stratis_stopped_pool[block.path];
const legacy_vdo = client.legacy_vdo_overlay.find_by_backing_block(block);

const is_stratis = ((content_block && content_block.IdUsage == "raid" && content_block.IdType == "stratis") ||
(block_stratis_blockdev && client.stratis_pools[block_stratis_blockdev.Pool]) ||
block_stratis_stopped_pool);

if (client.blocks_ptable[block.path]) {
make_partition_table_page(parent, block, card);
return;
}

if (legacy_vdo) {
make_legacy_vdo_page(parent, legacy_vdo, block, card);
return;
}

// Adjust for encryption leaking out of Stratis
if (is_crypto && is_stratis) {
is_crypto = false;
content_block = block;
}

if (is_crypto)
card = make_encryption_card(card, block);

if (!content_block) {
if (!is_crypto) {
// can not happen unless there is a bug in the code above.
console.error("Assertion failure: is_crypto == false");
}
if (fstab_config.length > 0) {
card = make_filesystem_card(card, block, null, fstab_config);
} else {
card = make_locked_encrypted_data_card(card, block);
}
} else {
const is_filesystem = content_block.IdUsage == 'filesystem';
const block_pvol = client.blocks_pvol[content_block.path];
const block_swap = client.blocks_swap[content_block.path];

if (is_filesystem) {
card = make_filesystem_card(card, block, content_block, fstab_config);
} else if ((content_block.IdUsage == "raid" && content_block.IdType == "LVM2_member") ||
(block_pvol && client.vgroups[block_pvol.VolumeGroup])) {
card = make_lvm2_physical_volume_card(card, block, content_block);
} else if (is_stratis) {
card = make_stratis_blockdev_card(card, block, content_block);
} else if ((content_block.IdUsage == "raid") ||
(client.mdraids[content_block.MDRaidMember])) {
card = make_mdraid_disk_card(card, block, content_block);
} else if (block_swap ||
(content_block.IdUsage == "other" && content_block.IdType == "swap")) {
card = make_swap_card(card, block, content_block);
} else if (client.blocks_available[content_block.path]) {
card = make_unformatted_data_card(card, block, content_block);
} else {
card = make_unrecognized_data_card(card, block, content_block);
}
}

new_page(parent, card);
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,13 @@
*/

import cockpit from "cockpit";
import * as utils from "./utils.js";
import { edit_crypto_config, parse_options, unparse_options, extract_option } from "./utils.js";
import {
edit_crypto_config, parse_options, unparse_options, extract_option,
get_parent_blocks, is_netdev,
decode_filename, encode_filename, block_name,
get_active_usage, reload_systemd, teardown_active_usage,
validate_fsys_label,
} from "../utils.js";

import React from "react";
import { FormHelperText } from "@patternfly/react-core/dist/esm/components/Form/index.js";
Expand All @@ -31,26 +36,26 @@ import {
TextInput, PassInput, CheckBoxes, SelectOne, SizeSlider,
BlockingMessage, TeardownMessage,
init_active_usage_processes
} from "./dialog.jsx";
} from "../dialog.jsx";

import { get_fstab_config, is_valid_mount_point } from "./fsys-tab.jsx";
import { init_existing_passphrase, unlock_with_type } from "./crypto-keyslots.jsx";
import { job_progress_wrapper } from "./jobs-panel.jsx";
import { get_fstab_config, is_valid_mount_point } from "../filesystem/utils.jsx";
import { init_existing_passphrase, unlock_with_type } from "../crypto/keyslots.jsx";
import { job_progress_wrapper } from "../jobs-panel.jsx";

const _ = cockpit.gettext;

export function initial_tab_options(client, block, for_fstab) {
const options = { };

utils.get_parent_blocks(client, block.path).forEach(p => {
get_parent_blocks(client, block.path).forEach(p => {
// "nofail" is the default for new filesystems with Cockpit so
// that a failure to mount one of them will not prevent
// Cockpit from starting. This allows people to debug and fix
// these failures with Cockpit itself.
//
options.nofail = true;

if (utils.is_netdev(client, p)) {
if (is_netdev(client, p)) {
options._netdev = true;
}
// HACK - https://bugzilla.redhat.com/show_bug.cgi?id=1589541
Expand Down Expand Up @@ -126,7 +131,7 @@ export const mount_explanation = {
export function format_dialog(client, path, start, size, enable_dos_extended) {
const block = client.blocks[path];
if (block.IdUsage == "crypto") {
cockpit.spawn(["cryptsetup", "luksDump", utils.decode_filename(block.Device)], { superuser: true })
cockpit.spawn(["cryptsetup", "luksDump", decode_filename(block.Device)], { superuser: true })
.then(output => {
if (output.indexOf("Keyslots:") >= 0) // This is what luksmeta-monitor-hack looks for
return 2;
Expand Down Expand Up @@ -155,9 +160,9 @@ function format_dialog_internal(client, path, start, size, enable_dos_extended,

let title;
if (create_partition)
title = cockpit.format(_("Create partition on $0"), utils.block_name(block));
title = cockpit.format(_("Create partition on $0"), block_name(block));
else
title = cockpit.format(_("Format $0"), utils.block_name(block));
title = cockpit.format(_("Format $0"), block_name(block));

function is_filesystem(vals) {
return vals.type != "empty" && vals.type != "dos-extended";
Expand Down Expand Up @@ -206,11 +211,11 @@ function format_dialog_internal(client, path, start, size, enable_dos_extended,
add_crypto_type("luks1", "LUKS1", false);
add_crypto_type("luks2", "LUKS2", true);

const usage = utils.get_active_usage(client, create_partition ? null : path, _("format"), _("delete"));
const usage = get_active_usage(client, create_partition ? null : path, _("format"), _("delete"));

if (usage.Blocking) {
dialog_open({
Title: cockpit.format(_("$0 is in use"), utils.block_name(block)),
Title: cockpit.format(_("$0 is in use"), block_name(block)),
Body: BlockingMessage(usage)
});
return;
Expand All @@ -219,7 +224,7 @@ function format_dialog_internal(client, path, start, size, enable_dos_extended,
const crypto_config = block.Configuration.find(c => c[0] == "crypttab");
let crypto_options;
if (crypto_config) {
crypto_options = (utils.decode_filename(crypto_config[1].options.v)
crypto_options = (decode_filename(crypto_config[1].options.v)
.split(",")
.filter(function (s) { return s.indexOf("x-parent") !== 0 })
.join(","));
Expand Down Expand Up @@ -266,7 +271,7 @@ function format_dialog_internal(client, path, start, size, enable_dos_extended,
Fields: [
TextInput("name", _("Name"),
{
validate: (name, vals) => utils.validate_fsys_label(name, vals.type),
validate: (name, vals) => validate_fsys_label(name, vals.type),
visible: is_filesystem
}),
TextInput("mount_point", _("Mount point"),
Expand Down Expand Up @@ -429,17 +434,17 @@ function format_dialog_internal(client, path, start, size, enable_dos_extended,
}

opts = opts.concat(parse_options(vals.crypto_options));
new_crypto_options = { t: 'ay', v: utils.encode_filename(unparse_options(opts)) };
new_crypto_options = { t: 'ay', v: encode_filename(unparse_options(opts)) };
const item = {
options: new_crypto_options,
"track-parents": { t: 'b', v: true }
};

if (!keep_keys) {
if (vals.store_passphrase.on) {
item["passphrase-contents"] = { t: 'ay', v: utils.encode_filename(vals.passphrase) };
item["passphrase-contents"] = { t: 'ay', v: encode_filename(vals.passphrase) };
} else {
item["passphrase-contents"] = { t: 'ay', v: utils.encode_filename("") };
item["passphrase-contents"] = { t: 'ay', v: encode_filename("") };
}
config_items.push(["crypttab", item]);
options["encrypt.passphrase"] = { t: 's', v: vals.passphrase };
Expand Down Expand Up @@ -471,9 +476,9 @@ function format_dialog_internal(client, path, start, size, enable_dos_extended,
mount_point = "/" + mount_point;

config_items.push(["fstab", {
dir: { t: 'ay', v: utils.encode_filename(mount_point) },
type: { t: 'ay', v: utils.encode_filename("auto") },
opts: { t: 'ay', v: utils.encode_filename(mount_options.join(",") || "defaults") },
dir: { t: 'ay', v: encode_filename(mount_point) },
type: { t: 'ay', v: encode_filename("auto") },
opts: { t: 'ay', v: encode_filename(mount_options.join(",") || "defaults") },
freq: { t: 'i', v: 0 },
passno: { t: 'i', v: 0 },
"track-parents": { t: 'b', v: true }
Expand Down Expand Up @@ -547,10 +552,10 @@ function format_dialog_internal(client, path, start, size, enable_dos_extended,
.then(block_crypto => block_crypto.Lock({ })));
}

return utils.teardown_active_usage(client, usage)
.then(utils.reload_systemd)
return teardown_active_usage(client, usage)
.then(reload_systemd)
.then(format)
.then(new_path => utils.reload_systemd().then(() => new_path))
.then(new_path => reload_systemd().then(() => new_path))
.then(maybe_mount);
}
},
Expand Down
61 changes: 61 additions & 0 deletions pkg/storaged/block/other.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* This file is part of Cockpit.
*
* Copyright (C) 2023 Red Hat, Inc.
*
* Cockpit is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* Cockpit is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
*/

import cockpit from "cockpit";
import React from "react";

import { DescriptionList } from "@patternfly/react-core/dist/esm/components/DescriptionList/index.js";
import { CardBody } from "@patternfly/react-core/dist/esm/components/Card/index.js";

import { StorageCard, StorageDescription, new_card } from "../pages.jsx";
import { block_name } from "../utils.js";
import { partitionable_block_actions } from "../partitions/actions.jsx";

import { make_block_page } from "../block/create-pages.jsx";

const _ = cockpit.gettext;

export function make_other_page(parent, block) {
const other_card = new_card({
title: _("Block device"),
next: null,
page_block: block,
for_summary: true,
job_path: block.path,
component: OtherCard,
props: { block },
actions: partitionable_block_actions(block),
});

make_block_page(parent, block, other_card);
}

const OtherCard = ({ card, block }) => {
return (
<StorageCard card={card}>
<CardBody>
<DescriptionList className="pf-m-horizontal-on-sm">
<StorageDescription title={_("Device number")}
value={(block.DeviceNumber >> 8) + ":" + (block.DeviceNumber & 0xFF)} />
<StorageDescription title={_("Device file")} value={block_name(block)} />
</DescriptionList>
</CardBody>
</StorageCard>
);
};
Loading

0 comments on commit a5f87a9

Please sign in to comment.