Line data Source code
1 : /*
2 : * Copyright (C) 2019 Red Hat, Inc.
3 : * SPDX-License-Identifier: LGPL-2.1-or-later
4 : */
5 93 : 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 93 : 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 93 : const _ = cockpit.gettext;
16 :
17 93 : export class SystemInformationCard extends React.Component {
18 93 : constructor(props) {
19 93 : super(props);
20 :
21 93 : this.state = {
22 93 : machineID: null,
23 93 : model: null,
24 93 : assetTag: null,
25 93 : systemUptime: null,
26 93 : };
27 93 : this.getSystemUptime = this.getSystemUptime.bind(this);
28 93 : }
29 :
30 93 : componentDidMount() {
31 93 : this.getDMIInfo();
32 93 : this.getMachineId();
33 93 : this.getSystemUptime();
34 :
35 93 : this.uptimeTimer = setInterval(this.getSystemUptime, 60000);
36 93 : }
37 :
38 0 : componentWillUnmount() {
39 0 : clearInterval(this.uptimeTimer); // not-covered: callers currently never unmount this
40 0 : }
41 :
42 93 : getMachineId() {
43 93 : const machine_id = cockpit.file("/etc/machine-id");
44 :
45 93 : machine_id.read()
46 92 : .then(machineID => this.setState({ machineID }))
47 0 : .catch(ex => console.error("Error reading machine id", ex.toString())) // not-covered: OS error
48 93 : .finally(machine_id.close);
49 93 : }
50 :
51 93 : getDMIInfo() {
52 93 : machine_info.dmi_info()
53 82 : .then(fields => {
54 82 : let vendor = fields.sys_vendor;
55 82 : 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 82 : if (!vendor || !name)
61 16 : this.setState({ model: null });
62 : else
63 82 : this.setState({ model: vendor + " " + name });
64 :
65 82 : this.setState({ assetTag: fields.product_serial || fields.chassis_serial });
66 82 : })
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 93 : }
78 :
79 93 : getSystemUptime() {
80 93 : cockpit.file("/proc/uptime").read()
81 92 : .then(content => {
82 92 : const uptime = parseFloat(content.split(' ')[0]);
83 92 : const bootTime = new Date().valueOf() - uptime * 1000;
84 92 : this.setState({ systemUptime: timeformat.distanceToNow(bootTime) });
85 92 : })
86 0 : .catch(ex => console.error("Error reading system uptime", ex.toString())); // not-covered: OS error
87 93 : }
88 :
89 93 : render() {
90 93 : return (
91 93 : <Card className="system-information">
92 93 : <CardTitle>{_("System information")}</CardTitle>
93 93 : <CardBody>
94 93 : <table className="pf-v6-c-table pf-m-grid-md pf-m-compact">
95 93 : <tbody className="pf-v6-c-table__tbody">
96 82 : {this.state.model && <tr className="pf-v6-c-table__tr">
97 82 : <th className="pf-v6-c-table__th" scope="row">{_("Model")}</th>
98 82 : <td className="pf-v6-c-table__td">
99 82 : <div id="system_information_hardware_text">{this.state.model}</div>
100 82 : </td>
101 82 : </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 93 : <tr className="pf-v6-c-table__tr">
109 93 : <th className="pf-v6-c-table__th system-information-machine-id" scope="row">{_("Machine ID")}</th>
110 93 : <td className="pf-v6-c-table__td">
111 93 : <div id="system_machine_id">{this.state.machineID}</div>
112 93 : </td>
113 93 : </tr>
114 93 : <tr className="pf-v6-c-table__tr">
115 93 : <th className="pf-v6-c-table__th system-information-uptime" scope="row">{_("Up since")}</th>
116 93 : <td className="pf-v6-c-table__td">
117 93 : <div id="system_uptime">{this.state.systemUptime}</div>
118 93 : </td>
119 93 : </tr>
120 93 : </tbody>
121 93 : </table>
122 93 : </CardBody>
123 93 : <CardFooter>
124 0 : <Button isInline variant="link" component="a" onClick={ev => { ev.preventDefault(); cockpit.jump("/system/hwinfo", cockpit.transport.host) }}>
125 93 : {_("View hardware details")}
126 93 : </Button>
127 93 : </CardFooter>
128 93 : </Card>
129 : );
130 93 : }
131 93 : }
|