Fix: compress health diagnostics file when download (#1821)

This commit is contained in:
Lenin Alevski
2022-04-12 18:29:19 -07:00
committed by GitHub
parent d8e7d343ba
commit 68f9019d0e
3 changed files with 85 additions and 31 deletions

View File

@@ -27,6 +27,7 @@ import {
DiagStatInProgress,
DiagStatSuccess,
HealthInfoMessage,
ReportMessage,
} from "./types";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
@@ -84,22 +85,6 @@ const styles = (theme: Theme) =>
...containerForHeader(theme.spacing(4)),
});
const download = (filename: string, text: string) => {
let element = document.createElement("a");
element.setAttribute(
"href",
"data:text/plain;charset=utf-8," + encodeURIComponent(text)
);
element.setAttribute("download", filename);
element.style.display = "none";
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
};
interface IHealthInfo {
classes: any;
healthInfoMessageReceived: typeof healthInfoMessageReceived;
@@ -126,6 +111,23 @@ const HealthInfo = ({
const [downloadDisabled, setDownloadDisabled] = useState(true);
const [localMessage, setMessage] = useState<string>("");
const [title, setTitle] = useState<string>("New Diagnostic");
const [diagFileContent, setDiagFileContent] = useState<string>("");
const download = () => {
let element = document.createElement("a");
element.setAttribute(
"href",
`data:application/gzip;base64,${diagFileContent}`
);
element.setAttribute("download", "diagnostic.json.gz");
element.style.display = "none";
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
};
useEffect(() => {
if (serverDiagnosticStatus === DiagStatInProgress) {
@@ -164,6 +166,7 @@ const HealthInfo = ({
useEffect(() => {
if (startDiagnostic) {
healthInfoResetMessage();
setDiagFileContent("");
const url = new URL(window.location.toString());
const isDev = process.env.NODE_ENV === "development";
const port = isDev ? "9090" : url.port;
@@ -189,10 +192,16 @@ const HealthInfo = ({
setServerDiagStat(DiagStatInProgress);
};
c.onmessage = (message: IMessageEvent) => {
let m: HealthInfoMessage = JSON.parse(message.data.toString());
m.timestamp = new Date(m.timestamp.toString());
healthInfoMessageReceived(m);
let m: ReportMessage = JSON.parse(message.data.toString());
if (m.serverHealthInfo) {
m.serverHealthInfo.timestamp = new Date(
m.serverHealthInfo.timestamp.toString()
);
healthInfoMessageReceived(m.serverHealthInfo);
}
if (m.encoded !== "") {
setDiagFileContent(m.encoded);
}
};
c.onerror = (error: Error) => {
console.log("error closing websocket:", error.message);
@@ -275,12 +284,7 @@ const HealthInfo = ({
type="submit"
variant="contained"
color="primary"
onClick={() => {
download(
"diagnostic.json",
JSON.stringify(message, null, 2)
);
}}
onClick={() => download()}
disabled={downloadDisabled}
>
Download

View File

@@ -25,6 +25,11 @@ export interface HealthInfoMessage {
sys: sysHealthInfo;
}
export interface ReportMessage {
encoded: string;
serverHealthInfo: HealthInfoMessage;
}
export interface perfInfo {
drives: serverDrivesInfo[];
net: serverNetHealthInfo[];

View File

@@ -17,15 +17,19 @@
package restapi
import (
"bytes"
"context"
b64 "encoding/base64"
"encoding/json"
"net/http"
"time"
"errors"
"github.com/klauspost/compress/gzip"
"github.com/gorilla/websocket"
madmin "github.com/minio/madmin-go"
"github.com/minio/madmin-go"
)
// startHealthInfo starts fetching mc.ServerHealthInfo and
@@ -51,19 +55,60 @@ func startHealthInfo(ctx context.Context, conn WSConn, client MinioAdmin, deadli
madmin.HealthDataTypeSysProcess,
}
healthInfo, _, err := client.serverHealthInfo(ctx, healthDataTypes, *deadline)
var err error
// Fetch info of all servers (cluster or single server)
healthInfo, version, err := client.serverHealthInfo(ctx, healthDataTypes, *deadline)
if err != nil {
return err
}
// Serialize message to be sent
bytes, err := json.Marshal(healthInfo)
compressedDiag, err := tarGZ(healthInfo, version)
if err != nil {
return err
}
encodedDiag := b64.StdEncoding.EncodeToString(compressedDiag)
type messageReport struct {
Encoded string `json:"encoded"`
ServerHealthInfo interface{} `json:"serverHealthInfo"`
}
report := messageReport{
Encoded: encodedDiag,
ServerHealthInfo: healthInfo,
}
message, err := json.Marshal(report)
if err != nil {
return err
}
// Send Message through websocket connection
return conn.writeMessage(websocket.TextMessage, bytes)
return conn.writeMessage(websocket.TextMessage, message)
}
// compress and tar MinIO diagnostics output
func tarGZ(healthInfo interface{}, version string) ([]byte, error) {
buffer := bytes.NewBuffer(nil)
gzWriter := gzip.NewWriter(buffer)
enc := json.NewEncoder(gzWriter)
header := struct {
Version string `json:"version"`
}{Version: version}
if err := enc.Encode(header); err != nil {
return nil, err
}
if err := enc.Encode(healthInfo); err != nil {
return nil, err
}
err := gzWriter.Close()
if err != nil {
return nil, err
}
return buffer.Bytes(), nil
}
// getHealthInfoOptionsFromReq gets duration for startHealthInfo request