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 { CardBody } from "@patternfly/react-core/dist/esm/components/Card/index.js";
11 : import { DescriptionList } from "@patternfly/react-core/dist/esm/components/DescriptionList/index.js";
12 :
13 : import { HDDIcon, SSDIcon, MediaDriveIcon } from "../icons/gnome-icons.jsx";
14 : import { StorageCard, StorageDescription, new_card, new_page } from "../pages.jsx";
15 : import { block_name, drive_name, fmt_size_long, should_ignore } from "../utils.js";
16 : import { make_block_page } from "../block/create-pages.jsx";
17 : import { partitionable_block_actions } from "../partitions/actions.jsx";
18 : import { isSmartOK, SmartCard } from "./smart-details.jsx";
19 :
20 113 : const _ = cockpit.gettext;
21 :
22 112 : export function make_drive_page(parent, drive) {
23 112 : let block = client.drives_block[drive.path];
24 :
25 19 : if (!block) {
26 : // A drive without a primary block device might be
27 : // a unconfigured multipath device. Try to hobble
28 : // along here by arbitrarily picking one of the
29 : // multipath devices.
30 19 : block = client.drives_multipath_blocks[drive.path][0];
31 19 : }
32 :
33 112 : if (!block)
34 112 : return;
35 :
36 112 : if (should_ignore(client, block.path))
37 112 : return;
38 :
39 109 : let cls;
40 109 : if (client.drives_iscsi_session[drive.path])
41 13 : cls = "iscsi";
42 109 : else if (drive.MediaRemovable || drive.Media)
43 102 : cls = "media";
44 : else
45 58 : cls = (drive.RotationRate === 0) ? "ssd" : "hdd";
46 :
47 109 : const drive_title = {
48 109 : media: _("Media drive"),
49 109 : ssd: _("Solid State Drive"),
50 109 : hdd: _("Hard Disk Drive"),
51 109 : iscsi: _("iSCSI Drive"),
52 109 : };
53 :
54 109 : const drive_icon = {
55 109 : media: MediaDriveIcon,
56 109 : ssd: SSDIcon,
57 109 : hdd: HDDIcon,
58 109 : };
59 :
60 109 : let card = new_card({
61 12 : title: drive_title[cls] || _("Drive"),
62 112 : next: null,
63 112 : page_block: block,
64 112 : page_icon: drive_icon[cls],
65 112 : for_summary: true,
66 112 : id_extra: drive_name(drive),
67 112 : job_path: drive.path,
68 112 : component: DriveCard,
69 112 : props: { drive },
70 13 : actions: block.Size > 0 ? partitionable_block_actions(block) : [],
71 112 : });
72 :
73 112 : let smart_info, drive_type;
74 102 : if (client.drives_ata[drive.path]) {
75 102 : smart_info = client.drives_ata[drive.path];
76 102 : drive_type = "ata";
77 12 : } else if (client.nvme_controller[drive.path]) {
78 12 : smart_info = client.nvme_controller[drive.path];
79 12 : drive_type = "nvme";
80 12 : }
81 :
82 13 : if (smart_info !== undefined && (cls === "hdd" || cls === "ssd")) {
83 13 : card = new_card({
84 13 : title: _("Device health (SMART)"),
85 13 : next: card,
86 13 : has_danger: !isSmartOK(drive_type, smart_info),
87 13 : has_warning: (smart_info.SmartNumBadSectors > 0 || smart_info.SmartNumAttributesFailing > 0),
88 13 : component: SmartCard,
89 13 : props: { smart_info, drive_type },
90 13 : });
91 13 : }
92 :
93 109 : if (block.Size > 0) {
94 109 : make_block_page(parent, block, card, { partitionable: true });
95 13 : } else {
96 13 : new_page(parent, card);
97 13 : }
98 112 : }
99 :
100 37 : const DriveCard = ({ card, page, drive }) => {
101 37 : const block = client.drives_block[drive.path];
102 37 : const multipath_blocks = client.drives_multipath_blocks[drive.path];
103 :
104 37 : return (
105 37 : <StorageCard card={card}>
106 37 : <CardBody>
107 37 : <DescriptionList className="pf-m-horizontal-on-sm">
108 37 : <StorageDescription title={_("Vendor")} value={drive.Vendor} />
109 37 : <StorageDescription title={_("Model")} value={drive.Model} />
110 37 : <StorageDescription title={_("Firmware version")} value={drive.Revision} />
111 37 : <StorageDescription title={_("Serial number")} value={drive.Serial} />
112 37 : <StorageDescription title={_("World wide name")} value={drive.WWN} />
113 37 : <StorageDescription title={_("Capacity")}>
114 37 : {drive.Size
115 37 : ? fmt_size_long(drive.Size)
116 2 : : _("No media inserted")
117 : }
118 37 : </StorageDescription>
119 37 : <StorageDescription title={_("Device file")}
120 3 : value={block ? block_name(block) : "-"} />
121 37 : { multipath_blocks.length > 0 &&
122 3 : <StorageDescription title={_("Multipathed devices")}
123 3 : value={multipath_blocks.map(block_name).join(" ")} />
124 : }
125 37 : </DescriptionList>
126 37 : </CardBody>
127 37 : </StorageCard>
128 : );
129 37 : };
|