Skip to content

Commit

Permalink
Fix: compress health diagnostics file when download
Browse files Browse the repository at this point in the history
- subnet expects the generated health diagnostics file to be gz compressed to work

Signed-off-by: Lenin Alevski <alevsk.8772@gmail.com>
  • Loading branch information
Alevsk committed Apr 11, 2022
1 parent 2d26eb4 commit c4076eb
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 31 deletions.
56 changes: 30 additions & 26 deletions portal-ui/src/screens/Console/HealthInfo/HealthInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
DiagStatInProgress,
DiagStatSuccess,
HealthInfoMessage,
ReportMessage,
} from "./types";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
Expand Down Expand Up @@ -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;
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions portal-ui/src/screens/Console/HealthInfo/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ export interface HealthInfoMessage {
sys: sysHealthInfo;
}

export interface ReportMessage {
encoded: string;
serverHealthInfo: HealthInfoMessage;
}

export interface perfInfo {
drives: serverDrivesInfo[];
net: serverNetHealthInfo[];
Expand Down
55 changes: 50 additions & 5 deletions restapi/admin_health_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down

0 comments on commit c4076eb

Please sign in to comment.