fix health report upload error (#3275)

This commit is contained in:
Shireesh Anjal
2024-04-05 01:20:22 +05:30
committed by GitHub
parent 3aac62cc81
commit 6c50c38f83
7 changed files with 57 additions and 125 deletions

View File

@@ -17,22 +17,22 @@
package api
import (
"bytes"
"context"
b64 "encoding/base64"
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
"net/url"
"os"
"time"
"github.com/minio/console/pkg/logger"
"github.com/minio/console/pkg/utils"
"github.com/klauspost/compress/gzip"
xhttp "github.com/minio/console/pkg/http"
subnet "github.com/minio/console/pkg/subnet"
"github.com/minio/madmin-go/v3"
mc "github.com/minio/mc/cmd"
"github.com/minio/websocket"
)
@@ -63,7 +63,7 @@ func startHealthInfo(ctx context.Context, conn WSConn, client MinioAdmin, deadli
return err
}
compressedDiag, err := tarGZ(healthInfo, version)
compressedDiag, err := mc.TarGZHealthInfo(healthInfo, version)
if err != nil {
return err
}
@@ -75,11 +75,11 @@ func startHealthInfo(ctx context.Context, conn WSConn, client MinioAdmin, deadli
}
ctx = context.WithValue(ctx, utils.ContextClientIP, conn.remoteAddress())
subnetResp, err := sendHealthInfoToSubnet(ctx, healthInfo, client)
err = sendHealthInfoToSubnet(ctx, healthInfo, client)
report := messageReport{
Encoded: encodedDiag,
ServerHealthInfo: healthInfo,
SubnetResponse: subnetResp,
SubnetResponse: mc.SubnetBaseURL() + "/health",
}
if err != nil {
report.SubnetResponse = fmt.Sprintf("Error: %s", err.Error())
@@ -94,31 +94,6 @@ func startHealthInfo(ctx context.Context, conn WSConn, client MinioAdmin, deadli
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
// path come as : `/health-info?deadline=2h`
func getHealthInfoOptionsFromReq(req *http.Request) (*time.Duration, error) {
@@ -129,16 +104,27 @@ func getHealthInfoOptionsFromReq(req *http.Request) (*time.Duration, error) {
return &deadlineDuration, nil
}
func sendHealthInfoToSubnet(ctx context.Context, healthInfo interface{}, client MinioAdmin) (string, error) {
filename := fmt.Sprintf("health_%d.json", time.Now().Unix())
func updateMcGlobals(subnetTokenConfig subnet.LicenseTokenConfig) error {
mc.GlobalDevMode = getConsoleDevMode()
if len(subnetTokenConfig.Proxy) > 0 {
proxyURL, e := url.Parse(subnetTokenConfig.Proxy)
if e != nil {
return e
}
mc.GlobalSubnetProxyURL = proxyURL
}
return nil
}
clientIP := utils.ClientIPFromContext(ctx)
subnetUploadURL := subnet.UploadURL("health", filename)
subnetHTTPClient := &xhttp.Client{Client: GetConsoleHTTPClient("", clientIP)}
func sendHealthInfoToSubnet(ctx context.Context, healthInfo interface{}, client MinioAdmin) error {
filename := fmt.Sprintf("health_%d.json.gz", time.Now().Unix())
subnetTokenConfig, e := GetSubnetKeyFromMinIOConfig(ctx, client)
if e != nil {
return "", e
return e
}
e = updateMcGlobals(*subnetTokenConfig)
if e != nil {
return e
}
var apiKey string
if len(subnetTokenConfig.APIKey) != 0 {
@@ -146,32 +132,41 @@ func sendHealthInfoToSubnet(ctx context.Context, healthInfo interface{}, client
} else {
apiKey, e = subnet.GetSubnetAPIKeyUsingLicense(subnetTokenConfig.License)
if e != nil {
return "", e
return e
}
}
headers := subnet.UploadAuthHeaders(apiKey)
uploadInfo, formDataType, e := subnet.ProcessUploadInfo(healthInfo, "health", filename)
compressedHealthInfo, e := mc.TarGZHealthInfo(healthInfo, madmin.HealthInfoVersion)
if e != nil {
return "", e
return e
}
e = os.WriteFile(filename, compressedHealthInfo, 0o666)
if e != nil {
return e
}
headers := mc.SubnetAPIKeyAuthHeaders(apiKey)
resp, e := (&mc.SubnetFileUploader{
FilePath: filename,
ReqURL: mc.SubnetUploadURL("health"),
Headers: headers,
DeleteAfterUpload: true,
}).UploadFileToSubnet()
if e != nil {
// file gets deleted only if upload is successful
// so we delete explicitly here as we already have the bytes
logger.LogIf(ctx, os.Remove(filename))
return e
}
resp, e := subnet.UploadFileToSubnet(uploadInfo, subnetHTTPClient, subnetUploadURL, headers, formDataType)
if e != nil {
return "", e
}
type SubnetResponse struct {
ClusterURL string `json:"cluster_url,omitempty"`
LicenseV2 string `json:"license_v2,omitempty"`
APIKey string `json:"api_key,omitempty"`
}
var subnetResp SubnetResponse
e = json.Unmarshal([]byte(resp), &subnetResp)
if e != nil {
return "", e
}
if len(subnetResp.ClusterURL) != 0 {
subnetClusterURL := strings.ReplaceAll(subnetResp.ClusterURL, "%2f", "/")
return subnetClusterURL, nil
return e
}
return "", ErrSubnetUploadFail
return nil
}

View File

@@ -506,7 +506,7 @@ func replaceBaseInIndex(indexPageBytes []byte, basePath string) []byte {
func replaceLicense(indexPageBytes []byte) []byte {
indexPageStr := string(indexPageBytes)
newPlan := fmt.Sprintf("<meta name=\"minio-license\" content=\"%s\" />", InstanceLicensePlan.String())
indexPageStr = strings.Replace(indexPageStr, "<meta name=\"minio-license\" content=\"apgl\"/>", newPlan, 1)
indexPageStr = strings.Replace(indexPageStr, "<meta name=\"minio-license\" content=\"agpl\"/>", newPlan, 1)
indexPageBytes = []byte(indexPageStr)
return indexPageBytes
}

View File

@@ -72,7 +72,6 @@ var (
ErrEncryptionConfigNotFound = errors.New("encryption configuration not found")
ErrPolicyNotFound = errors.New("policy does not exist")
ErrLoginNotAllowed = errors.New("login not allowed")
ErrSubnetUploadFail = errors.New("SUBNET upload failed")
ErrHealthReportFail = errors.New("failure to generate Health report")
)

4
go.mod
View File

@@ -21,8 +21,8 @@ require (
github.com/minio/cli v1.24.2
github.com/minio/highwayhash v1.0.2
github.com/minio/kes v0.23.0
github.com/minio/madmin-go/v3 v3.0.50-0.20240307075442-63b4fc3ac1fd
github.com/minio/mc v0.0.0-20240320210729-9043bbf545d2
github.com/minio/madmin-go/v3 v3.0.50
github.com/minio/mc v0.0.0-20240330152952-9f8147bf0e03
github.com/minio/minio-go/v7 v7.0.69
github.com/minio/selfupdate v0.6.0
github.com/minio/websocket v1.6.0

8
go.sum
View File

@@ -184,10 +184,10 @@ github.com/minio/kes v0.23.0 h1:T0zHtyDoI3JdKrVvzdM4xwVryYYyh5pKwNUVBoqxsNs=
github.com/minio/kes v0.23.0/go.mod h1:vvXVGcgu9mYLkbVWlEvFFl6bYR196RQlOU2Q+rHApl8=
github.com/minio/kes-go v0.2.1 h1:KnqS+p6xoSFJZbQhmJaz/PbxeA6nQyRqT/ywrn5lU2o=
github.com/minio/kes-go v0.2.1/go.mod h1:76xf7l41Wrh+IifisABXK2S8uZWYgWV1IGBKC3GdOJk=
github.com/minio/madmin-go/v3 v3.0.50-0.20240307075442-63b4fc3ac1fd h1:oZycRrLgzEg4+lGZ5Tkua3BKvK7rOtDlmoOR3gq58l4=
github.com/minio/madmin-go/v3 v3.0.50-0.20240307075442-63b4fc3ac1fd/go.mod h1:ZDF7kf5fhmxLhbGTqyq5efs4ao0v4eWf7nOuef/ljJs=
github.com/minio/mc v0.0.0-20240320210729-9043bbf545d2 h1:zF4kiN6HJp4B5IFp+riDA8roY0r+UJV0RvaaVitchH4=
github.com/minio/mc v0.0.0-20240320210729-9043bbf545d2/go.mod h1:YgeY0RTYvbm/H6Gzwb+rpRsQ/XREi3NwITZUcTNATOQ=
github.com/minio/madmin-go/v3 v3.0.50 h1:+RQMetVFvPQmAOEDN/xmLhwk9+xOzu3rqwnlZEskgvg=
github.com/minio/madmin-go/v3 v3.0.50/go.mod h1:ZDF7kf5fhmxLhbGTqyq5efs4ao0v4eWf7nOuef/ljJs=
github.com/minio/mc v0.0.0-20240330152952-9f8147bf0e03 h1:xF1hntqvs/CVEHGBETSrIMTW3iSU3k2j/YCFXGDWoBs=
github.com/minio/mc v0.0.0-20240330152952-9f8147bf0e03/go.mod h1:RMCe706GTL9EOO6pxzFXd9Vp+3w2L1uctPiycmLDr9U=
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
github.com/minio/minio-go/v7 v7.0.69 h1:l8AnsQFyY1xiwa/DaQskY4NXSLA2yrGsW5iD9nRPVS0=

View File

@@ -18,14 +18,11 @@ package subnet
import (
"bytes"
"compress/gzip"
"crypto/tls"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io"
"mime/multipart"
"net"
"net/http"
"time"
@@ -79,65 +76,6 @@ func UploadAuthHeaders(apiKey string) map[string]string {
return map[string]string{"x-subnet-api-key": apiKey}
}
func ProcessUploadInfo(info interface{}, uploadType string, filename string) ([]byte, string, error) {
if uploadType == "health" {
return processHealthReport(info, filename)
}
return nil, "", errors.New("invalid SUBNET upload type")
}
func UploadFileToSubnet(info []byte, client *xhttp.Client, reqURL string, headers map[string]string, formDataType string) (string, error) {
req, e := subnetUploadReq(info, reqURL, formDataType)
if e != nil {
return "", e
}
resp, e := subnetReqDo(client, req, headers)
return resp, e
}
func processHealthReport(info interface{}, filename string) ([]byte, string, error) {
var body bytes.Buffer
writer := multipart.NewWriter(&body)
zipWriter := gzip.NewWriter(&body)
version := "3"
enc := json.NewEncoder(zipWriter)
header := struct {
Version string `json:"version"`
}{Version: version}
if e := enc.Encode(header); e != nil {
return nil, "", e
}
if e := enc.Encode(info); e != nil {
return nil, "", e
}
zipWriter.Close()
temp := body
part, e := writer.CreateFormFile("file", filename)
if e != nil {
return nil, "", e
}
if _, e = io.Copy(part, &temp); e != nil {
return nil, "", e
}
writer.Close()
return body.Bytes(), writer.FormDataContentType(), nil
}
func subnetUploadReq(body []byte, url string, formDataType string) (*http.Request, error) {
uploadDataBody := bytes.NewReader(body)
r, e := http.NewRequest(http.MethodPost, url, uploadDataBody)
if e != nil {
return nil, e
}
r.Header.Add("Content-Type", formDataType)
return r, nil
}
func GenerateRegToken(clusterRegInfo mc.ClusterRegistrationInfo) (string, error) {
token, e := json.Marshal(clusterRegInfo)
if e != nil {

View File

@@ -15,7 +15,7 @@
name="theme-color"
/>
<meta content="MinIO Console" name="description" />
<meta name="minio-license" content="apgl" />
<meta name="minio-license" content="agpl" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/