Line data Source code
1 : /*
2 : * Copyright (C) 2019 Red Hat, Inc.
3 : * SPDX-License-Identifier: LGPL-2.1-or-later
4 : */
5 94 : import React from 'react';
6 : import { Button } from "@patternfly/react-core/dist/esm/components/Button/index.js";
7 : import { Card, CardBody, CardFooter, CardTitle } from "@patternfly/react-core/dist/esm/components/Card/index.js";
8 :
9 94 : import cockpit from "cockpit";
10 : import * as machine_info from "machine-info.js";
11 : import * as timeformat from "timeformat";
12 :
13 : import "./systemInformationCard.scss";
14 :
15 94 : const _ = cockpit.gettext;
16 :
17 94 : export class SystemInformationCard extends React.Component {
18 94 : constructor(props) {
19 94 : super(props);
20 :
21 94 : this.state = {
22 94 : machineID: null,
23 94 : model: null,
24 94 : assetTag: null,
25 94 : systemUptime: null,
26 94 : };
27 94 : this.getSystemUptime = this.getSystemUptime.bind(this);
28 94 : }
29 :
30 94 : componentDidMount() {
31 94 : this.getDMIInfo();
32 94 : this.getMachineId();
33 94 : this.getSystemUptime();
34 :
35 94 : this.uptimeTimer = setInterval(this.getSystemUptime, 60000);
36 94 : }
37 :
38 0 : componentWillUnmount() {
39 0 : clearInterval(this.uptimeTimer); // not-covered: callers currently never unmount this
40 0 : }
41 :
42 94 : getMachineId() {
43 94 : const machine_id = cockpit.file("/etc/machine-id");
44 :
45 94 : machine_id.read()
46 93 : .then(machineID => this.setState({ machineID }))
47 0 : .catch(ex => console.error("Error reading machine id", ex.toString())) // not-covered: OS error
48 94 : .finally(machine_id.close);
49 94 : }
50 :
51 94 : getDMIInfo() {
52 94 : machine_info.dmi_info()
53 86 : .then(fields => {
54 86 : let vendor = fields.sys_vendor;
55 86 : let name = fields.product_name;
56 16 : if (!vendor || !name) {
57 16 : vendor = fields.board_vendor;
58 16 : name = fields.board_name;
59 16 : }
60 86 : if (!vendor || !name)
61 16 : this.setState({ model: null });
62 : else
63 86 : this.setState({ model: vendor + " " + name });
64 :
65 86 : this.setState({ assetTag: fields.product_serial || fields.chassis_serial });
66 86 : })
67 0 : .catch(ex => {
68 : // try DeviceTree
69 0 : machine_info.devicetree_info() // not-covered: coverage only runs on x86_64
70 0 : .then(fields => this.setState({ assetTag: fields.serial, model: fields.model }))
71 0 : .catch(dmiex => {
72 0 : console.debug("couldn't read dmi info: " + ex.toString());
73 0 : console.debug("couldn't read DeviceTree info: " + dmiex.toString());
74 0 : this.setState({ assetTag: null, model: null });
75 0 : });
76 0 : });
77 94 : }
78 :
79 94 : getSystemUptime() {
80 94 : cockpit.file("/proc/uptime").read()
81 93 : .then(content => {
82 93 : const uptime = parseFloat(content.split(' ')[0]);
83 93 : const bootTime = new Date().valueOf() - uptime * 1000;
84 93 : this.setState({ systemUptime: timeformat.distanceToNow(bootTime) });
85 93 : })
86 0 : .catch(ex => console.error("Error reading system uptime", ex.toString())); // not-covered: OS error
87 94 : }
88 :
89 94 : render() {
90 94 : return (
91 94 : <Card className="system-information">
92 94 : <CardTitle>{_("System information")}</CardTitle>
93 94 : <CardBody>
94 94 : <table className="pf-v6-c-table pf-m-grid-md pf-m-compact">
95 94 : <tbody className="pf-v6-c-table__tbody">
96 86 : {this.state.model && <tr className="pf-v6-c-table__tr">
97 86 : <th className="pf-v6-c-table__th" scope="row">{_("Model")}</th>
98 86 : <td className="pf-v6-c-table__td">
99 86 : <div id="system_information_hardware_text">{this.state.model}</div>
100 86 : </td>
101 86 : </tr>}
102 16 : {this.state.assetTag && <tr className="pf-v6-c-table__tr">
103 16 : <th className="pf-v6-c-table__th" scope="row">{_("Asset tag")}</th>
104 16 : <td className="pf-v6-c-table__td">
105 16 : <div id="system_information_asset_tag_text">{this.state.assetTag}</div>
106 16 : </td>
107 16 : </tr>}
108 94 : <tr className="pf-v6-c-table__tr">
109 94 : <th className="pf-v6-c-table__th system-information-machine-id" scope="row">{_("Machine ID")}</th>
110 94 : <td className="pf-v6-c-table__td">
111 94 : <div id="system_machine_id">{this.state.machineID}</div>
112 94 : </td>
113 94 : </tr>
114 94 : <tr className="pf-v6-c-table__tr">
115 94 : <th className="pf-v6-c-table__th system-information-uptime" scope="row">{_("Up since")}</th>
116 94 : <td className="pf-v6-c-table__td">
117 94 : <div id="system_uptime">{this.state.systemUptime}</div>
118 94 : </td>
119 94 : </tr>
120 94 : </tbody>
121 94 : </table>
122 94 : </CardBody>
123 94 : <CardFooter>
124 0 : <Button isInline variant="link" component="a" onClick={ev => { ev.preventDefault(); cockpit.jump("/system/hwinfo", cockpit.transport.host) }}>
125 94 : {_("View hardware details")}
126 94 : </Button>
127 94 : </CardFooter>
128 94 : </Card>
129 : );
130 94 : }
131 94 : }
|