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