diff --git a/api/admin_health_info.go b/api/admin_health_info.go index a9467549f..d467f65ee 100644 --- a/api/admin_health_info.go +++ b/api/admin_health_info.go @@ -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 } diff --git a/api/configure_console.go b/api/configure_console.go index e84c026ac..f44dfaa01 100644 --- a/api/configure_console.go +++ b/api/configure_console.go @@ -506,7 +506,7 @@ func replaceBaseInIndex(indexPageBytes []byte, basePath string) []byte { func replaceLicense(indexPageBytes []byte) []byte { indexPageStr := string(indexPageBytes) newPlan := fmt.Sprintf("", InstanceLicensePlan.String()) - indexPageStr = strings.Replace(indexPageStr, "", newPlan, 1) + indexPageStr = strings.Replace(indexPageStr, "", newPlan, 1) indexPageBytes = []byte(indexPageStr) return indexPageBytes } diff --git a/api/errors.go b/api/errors.go index bc067bdd0..d1e0341bf 100644 --- a/api/errors.go +++ b/api/errors.go @@ -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") ) diff --git a/go.mod b/go.mod index c12220cb0..632ec91f4 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index 981dac4c3..3eedebb2d 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/pkg/subnet/utils.go b/pkg/subnet/utils.go index 1111521cf..a7e6001fb 100644 --- a/pkg/subnet/utils.go +++ b/pkg/subnet/utils.go @@ -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 { diff --git a/web-app/public/index.html b/web-app/public/index.html index 806d86d3f..76a4bb79f 100644 --- a/web-app/public/index.html +++ b/web-app/public/index.html @@ -15,7 +15,7 @@ name="theme-color" /> - +