Fix: compress health diagnostics file when download (#1821)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -25,6 +25,11 @@ export interface HealthInfoMessage {
|
||||
sys: sysHealthInfo;
|
||||
}
|
||||
|
||||
export interface ReportMessage {
|
||||
encoded: string;
|
||||
serverHealthInfo: HealthInfoMessage;
|
||||
}
|
||||
|
||||
export interface perfInfo {
|
||||
drives: serverDrivesInfo[];
|
||||
net: serverNetHealthInfo[];
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user