Line data Source code
1 : /*
2 : * Copyright (C) 2023 Red Hat, Inc.
3 : * SPDX-License-Identifier: LGPL-2.1-or-later
4 : */
5 :
6 113 : import cockpit from "cockpit";
7 113 : import React from "react";
8 : import client from "../client";
9 :
10 : import { Button } from "@patternfly/react-core/dist/esm/components/Button/index.js";
11 : import { CardBody } from "@patternfly/react-core/dist/esm/components/Card/index.js";
12 : import { DescriptionList } from "@patternfly/react-core/dist/esm/components/DescriptionList/index.js";
13 :
14 : import { StorageCard, StorageDescription, new_card, register_crossref } from "../pages.jsx";
15 : import { std_format_action } from "../block/actions.jsx";
16 : import { block_short_name, fmt_size, mdraid_name } from "../utils.js";
17 : import { std_lock_action } from "../crypto/actions.jsx";
18 :
19 113 : const _ = cockpit.gettext;
20 :
21 7 : export function make_mdraid_disk_card(next, backing_block, content_block) {
22 7 : const mdraid = client.mdraids[content_block.MDRaidMember];
23 7 : const mdraid_block = mdraid && client.mdraids_block[mdraid.path];
24 :
25 7 : const disk_card = new_card({
26 7 : title: _("MDRAID disk"),
27 7 : next,
28 7 : location: {
29 6 : label: mdraid_block ? block_short_name(mdraid_block) : (mdraid ? mdraid_name(mdraid) : null),
30 7 : to: mdraid ? ["mdraid", mdraid.UUID] : null,
31 7 : },
32 7 : component: MDRaidDiskCard,
33 7 : props: { backing_block, content_block, mdraid },
34 7 : actions: [
35 7 : std_lock_action(backing_block, content_block),
36 7 : std_format_action(backing_block, content_block),
37 7 : ]
38 7 : });
39 :
40 7 : if (mdraid) {
41 1 : const members = client.mdraids_members[mdraid.path] || [];
42 7 : let n_spares = 0;
43 7 : let n_recovering = 0;
44 6 : mdraid.ActiveDevices.forEach(function(as) {
45 3 : if (as[2].indexOf("spare") >= 0) {
46 3 : if (as[1] < 0)
47 3 : n_spares += 1;
48 : else
49 3 : n_recovering += 1;
50 3 : }
51 6 : });
52 :
53 6 : const active_state = mdraid.ActiveDevices.find(as => as[0] == content_block.path);
54 :
55 6 : const state_text = (state) => {
56 6 : return {
57 6 : faulty: _("Failed"),
58 6 : in_sync: _("In sync"),
59 2 : spare: active_state[1] < 0 ? _("Spare") : _("Recovering"),
60 6 : write_mostly: _("Write-mostly"),
61 6 : blocked: _("Blocked")
62 1 : }[state] || cockpit.format(_("Unknown ($0)"), state);
63 6 : };
64 :
65 7 : const slot = active_state && active_state[1] >= 0 && active_state[1].toString();
66 7 : let states = active_state && active_state[2].map(state_text).join(", ");
67 :
68 7 : if (slot)
69 7 : states = cockpit.format(_("Slot $0"), slot) + ", " + states;
70 :
71 7 : const is_in_sync = (active_state && active_state[2].indexOf("in_sync") >= 0);
72 4 : const is_recovering = (active_state && active_state[2].indexOf("spare") >= 0 && active_state[1] >= 0);
73 :
74 7 : let remove_excuse = null;
75 7 : if (!mdraid_block)
76 6 : remove_excuse = _("The MDRAID device must be running");
77 7 : else if ((is_in_sync && n_recovering > 0) || is_recovering)
78 4 : remove_excuse = _("MDRAID device is recovering");
79 7 : else if (is_in_sync && n_spares < 1)
80 6 : remove_excuse = _("Need a spare disk");
81 6 : else if (members.length <= 1)
82 4 : remove_excuse = _("Last disk can not be removed");
83 :
84 7 : let remove_action = null;
85 7 : if (mdraid.Level != "raid0")
86 7 : remove_action = {
87 7 : title: _("Remove"),
88 2 : action: () => mdraid.RemoveDevice(content_block.path, { wipe: { t: 'b', v: true } }),
89 7 : excuse: remove_excuse
90 7 : };
91 :
92 7 : register_crossref({
93 7 : key: mdraid,
94 7 : card: disk_card,
95 7 : actions: [
96 7 : remove_action
97 7 : ],
98 7 : size: fmt_size(content_block.Size),
99 7 : extra: states,
100 7 : });
101 7 : }
102 :
103 7 : return disk_card;
104 7 : }
105 :
106 2 : export const MDRaidDiskCard = ({ card, backing_block, content_block, mdraid }) => {
107 2 : return (
108 2 : <StorageCard card={card}>
109 2 : <CardBody>
110 2 : <DescriptionList className="pf-m-horizontal-on-sm">
111 2 : <StorageDescription title={_("MDRAID device")}>
112 2 : {mdraid
113 2 : ? <Button variant="link" isInline role="link"
114 1 : onClick={() => cockpit.location.go(["mdraid", mdraid.UUID])}>
115 2 : {mdraid_name(mdraid)}
116 2 : </Button>
117 0 : : "-"
118 : }
119 2 : </StorageDescription>
120 2 : </DescriptionList>
121 2 : </CardBody>
122 2 : </StorageCard>
123 : );
124 2 : };
|