mirror of
https://github.com/minio/mc.git
synced 2025-12-08 22:28:28 +03:00
Expose health diagnostics related functions (#4885)
So that dependent projects (e.g. console) can make use of them instead of duplicating the logic.
This commit is contained in:
@@ -67,11 +67,15 @@ var (
|
||||
globalDebug = false // Debug flag set via command line
|
||||
globalNoColor = false // No Color flag set via command line
|
||||
globalInsecure = false // Insecure flag set via command line
|
||||
globalDevMode = false // dev flag set via command line
|
||||
globalAirgapped = false // Airgapped flag set via command line
|
||||
globalSubnetProxyURL *url.URL // Proxy to be used for communication with subnet
|
||||
globalSubnetConfig []madmin.SubsysConfig // Subnet config
|
||||
|
||||
// GlobalDevMode is set to true if the program is running in development mode
|
||||
GlobalDevMode = false
|
||||
|
||||
// GlobalSubnetProxyURL is the proxy to be used for communication with subnet
|
||||
GlobalSubnetProxyURL *url.URL
|
||||
|
||||
globalConnReadDeadline time.Duration
|
||||
globalConnWriteDeadline time.Duration
|
||||
|
||||
@@ -117,7 +121,7 @@ func setGlobalsFromContext(ctx *cli.Context) error {
|
||||
globalJSON = globalJSON || json
|
||||
globalNoColor = globalNoColor || noColor || globalJSONLine
|
||||
globalInsecure = globalInsecure || insecure
|
||||
globalDevMode = globalDevMode || devMode
|
||||
GlobalDevMode = GlobalDevMode || devMode
|
||||
globalAirgapped = globalAirgapped || airgapped
|
||||
|
||||
// Disable colorified messages if requested.
|
||||
|
||||
@@ -106,9 +106,9 @@ func performLicenseRenew(alias string) licUpdateMessage {
|
||||
}
|
||||
|
||||
renewURL := subnetLicenseRenewURL()
|
||||
headers := subnetAPIKeyAuthHeaders(apiKey)
|
||||
headers := SubnetAPIKeyAuthHeaders(apiKey)
|
||||
headers.addDeploymentIDHeader(alias)
|
||||
resp, e := subnetPostReq(renewURL, nil, headers)
|
||||
resp, e := SubnetPostReq(renewURL, nil, headers)
|
||||
fatalIf(probe.NewError(e), "Error renewing license for %s", alias)
|
||||
|
||||
extractAndSaveSubnetCreds(alias, resp)
|
||||
|
||||
132
cmd/subnet-file-uploader.go
Normal file
132
cmd/subnet-file-uploader.go
Normal file
@@ -0,0 +1,132 @@
|
||||
// Copyright (c) 2015-2024 MinIO, Inc.
|
||||
//
|
||||
// This file is part of MinIO Object Storage stack
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/klauspost/compress/zstd"
|
||||
)
|
||||
|
||||
// SubnetFileUploader - struct to upload files to SUBNET
|
||||
type SubnetFileUploader struct {
|
||||
alias string // used for saving api-key and license from response
|
||||
filename string // filename passed in the SUBNET request
|
||||
FilePath string // file to upload
|
||||
ReqURL string // SUBNET upload URL
|
||||
Params url.Values // query params to be sent in the request
|
||||
Headers SubnetHeaders // headers to be sent in the request
|
||||
AutoCompress bool // whether to compress (zst) the file before uploading
|
||||
DeleteAfterUpload bool // whether to delete the file after successful upload
|
||||
}
|
||||
|
||||
// UploadFileToSubnet - uploads the file to SUBNET
|
||||
func (i *SubnetFileUploader) UploadFileToSubnet() (string, error) {
|
||||
req, e := i.subnetUploadReq()
|
||||
if e != nil {
|
||||
return "", e
|
||||
}
|
||||
|
||||
resp, e := subnetReqDo(req, i.Headers)
|
||||
if e != nil {
|
||||
return "", e
|
||||
}
|
||||
|
||||
if i.DeleteAfterUpload {
|
||||
os.Remove(i.FilePath)
|
||||
}
|
||||
|
||||
// ensure that both api-key and license from
|
||||
// SUBNET response are saved in the config
|
||||
if len(i.alias) > 0 {
|
||||
extractAndSaveSubnetCreds(i.alias, resp)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (i *SubnetFileUploader) updateParams() {
|
||||
if i.Params == nil {
|
||||
i.Params = url.Values{}
|
||||
}
|
||||
|
||||
if i.filename == "" {
|
||||
i.filename = filepath.Base(i.FilePath)
|
||||
}
|
||||
|
||||
i.AutoCompress = i.AutoCompress && !strings.HasSuffix(strings.ToLower(i.FilePath), ".zst")
|
||||
if i.AutoCompress {
|
||||
i.filename += ".zst"
|
||||
i.Params.Add("auto-compression", "zstd")
|
||||
}
|
||||
|
||||
i.Params.Add("filename", i.filename)
|
||||
i.ReqURL += "?" + i.Params.Encode()
|
||||
}
|
||||
|
||||
func (i *SubnetFileUploader) subnetUploadReq() (*http.Request, error) {
|
||||
i.updateParams()
|
||||
|
||||
r, w := io.Pipe()
|
||||
mwriter := multipart.NewWriter(w)
|
||||
contentType := mwriter.FormDataContentType()
|
||||
|
||||
go func() {
|
||||
var (
|
||||
part io.Writer
|
||||
e error
|
||||
)
|
||||
defer func() {
|
||||
mwriter.Close()
|
||||
w.CloseWithError(e)
|
||||
}()
|
||||
|
||||
part, e = mwriter.CreateFormFile("file", i.filename)
|
||||
if e != nil {
|
||||
return
|
||||
}
|
||||
|
||||
file, e := os.Open(i.FilePath)
|
||||
if e != nil {
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
if i.AutoCompress {
|
||||
z, _ := zstd.NewWriter(part, zstd.WithEncoderConcurrency(2))
|
||||
defer z.Close()
|
||||
_, e = z.ReadFrom(file)
|
||||
} else {
|
||||
_, e = io.Copy(part, file)
|
||||
}
|
||||
}()
|
||||
|
||||
req, e := http.NewRequest(http.MethodPost, i.ReqURL, r)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
req.Header.Add("Content-Type", contentType)
|
||||
|
||||
return req, nil
|
||||
}
|
||||
@@ -26,17 +26,14 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/klauspost/compress/zstd"
|
||||
"github.com/minio/cli"
|
||||
"github.com/minio/madmin-go/v3"
|
||||
"github.com/minio/mc/pkg/probe"
|
||||
@@ -59,48 +56,51 @@ var subnetCommonFlags = append(supportGlobalFlags, cli.StringFlag{
|
||||
EnvVar: "_MC_SUBNET_API_KEY",
|
||||
})
|
||||
|
||||
func subnetBaseURL() string {
|
||||
return subnet.BaseURL(globalDevMode)
|
||||
// SubnetBaseURL - returns the base URL of SUBNET
|
||||
func SubnetBaseURL() string {
|
||||
return subnet.BaseURL(GlobalDevMode)
|
||||
}
|
||||
|
||||
func subnetIssueURL(issueNum int) string {
|
||||
return fmt.Sprintf("%s/issues/%d", subnetBaseURL(), issueNum)
|
||||
return fmt.Sprintf("%s/issues/%d", SubnetBaseURL(), issueNum)
|
||||
}
|
||||
|
||||
func subnetLogWebhookURL() string {
|
||||
return subnetBaseURL() + "/api/logs"
|
||||
return SubnetBaseURL() + "/api/logs"
|
||||
}
|
||||
|
||||
func subnetUploadURL(uploadType string) string {
|
||||
return fmt.Sprintf("%s/api/%s/upload", subnetBaseURL(), uploadType)
|
||||
// SubnetUploadURL - returns the upload URL for the given upload type
|
||||
func SubnetUploadURL(uploadType string) string {
|
||||
return fmt.Sprintf("%s/api/%s/upload", SubnetBaseURL(), uploadType)
|
||||
}
|
||||
|
||||
func subnetRegisterURL() string {
|
||||
return subnetBaseURL() + "/api/cluster/register"
|
||||
// SubnetRegisterURL - returns the cluster registration URL
|
||||
func SubnetRegisterURL() string {
|
||||
return SubnetBaseURL() + "/api/cluster/register"
|
||||
}
|
||||
|
||||
func subnetUnregisterURL(depID string) string {
|
||||
return subnetBaseURL() + "/api/cluster/unregister?deploymentId=" + depID
|
||||
return SubnetBaseURL() + "/api/cluster/unregister?deploymentId=" + depID
|
||||
}
|
||||
|
||||
func subnetLicenseRenewURL() string {
|
||||
return subnetBaseURL() + "/api/cluster/renew-license"
|
||||
return SubnetBaseURL() + "/api/cluster/renew-license"
|
||||
}
|
||||
|
||||
func subnetOfflineRegisterURL(regToken string) string {
|
||||
return subnetBaseURL() + "/cluster/register?token=" + regToken
|
||||
return SubnetBaseURL() + "/cluster/register?token=" + regToken
|
||||
}
|
||||
|
||||
func subnetLoginURL() string {
|
||||
return subnetBaseURL() + "/api/auth/login"
|
||||
return SubnetBaseURL() + "/api/auth/login"
|
||||
}
|
||||
|
||||
func subnetAPIKeyURL() string {
|
||||
return subnetBaseURL() + "/api/auth/api-key"
|
||||
return SubnetBaseURL() + "/api/auth/api-key"
|
||||
}
|
||||
|
||||
func subnetMFAURL() string {
|
||||
return subnetBaseURL() + "/api/auth/mfa-login"
|
||||
return SubnetBaseURL() + "/api/auth/mfa-login"
|
||||
}
|
||||
|
||||
func checkURLReachable(url string) *probe.Error {
|
||||
@@ -124,12 +124,13 @@ func subnetURLWithAuth(reqURL, apiKey string) (string, map[string]string, error)
|
||||
return "", nil, e
|
||||
}
|
||||
}
|
||||
return reqURL, subnetAPIKeyAuthHeaders(apiKey), nil
|
||||
return reqURL, SubnetAPIKeyAuthHeaders(apiKey), nil
|
||||
}
|
||||
|
||||
type subnetHeaders map[string]string
|
||||
// SubnetHeaders - type for SUBNET request headers
|
||||
type SubnetHeaders map[string]string
|
||||
|
||||
func (h subnetHeaders) addDeploymentIDHeader(alias string) {
|
||||
func (h SubnetHeaders) addDeploymentIDHeader(alias string) {
|
||||
h[minioDeploymentIDHeader] = getAdminInfo(alias).DeploymentID
|
||||
}
|
||||
|
||||
@@ -137,18 +138,20 @@ func subnetTokenAuthHeaders(authToken string) map[string]string {
|
||||
return map[string]string{"Authorization": "Bearer " + authToken}
|
||||
}
|
||||
|
||||
func subnetLicenseAuthHeaders(lic string) map[string]string {
|
||||
// SubnetLicenseAuthHeaders - returns the headers for SUBNET license authentication
|
||||
func SubnetLicenseAuthHeaders(lic string) map[string]string {
|
||||
return map[string]string{"x-subnet-license": lic}
|
||||
}
|
||||
|
||||
func subnetAPIKeyAuthHeaders(apiKey string) subnetHeaders {
|
||||
// SubnetAPIKeyAuthHeaders - returns the headers for SUBNET API key authentication
|
||||
func SubnetAPIKeyAuthHeaders(apiKey string) SubnetHeaders {
|
||||
return map[string]string{"x-subnet-api-key": apiKey}
|
||||
}
|
||||
|
||||
func getSubnetClient() *http.Client {
|
||||
client := httpClient(0)
|
||||
if globalSubnetProxyURL != nil {
|
||||
client.Transport.(*http.Transport).Proxy = http.ProxyURL(globalSubnetProxyURL)
|
||||
if GlobalSubnetProxyURL != nil {
|
||||
client.Transport.(*http.Transport).Proxy = http.ProxyURL(GlobalSubnetProxyURL)
|
||||
}
|
||||
return client
|
||||
}
|
||||
@@ -256,7 +259,8 @@ func subnetGetReq(reqURL string, headers map[string]string) (string, error) {
|
||||
return subnetReqDo(r, headers)
|
||||
}
|
||||
|
||||
func subnetPostReq(reqURL string, payload interface{}, headers map[string]string) (string, error) {
|
||||
// SubnetPostReq - makes a POST request to SUBNET
|
||||
func SubnetPostReq(reqURL string, payload interface{}, headers map[string]string) (string, error) {
|
||||
body, e := json.Marshal(payload)
|
||||
if e != nil {
|
||||
return "", e
|
||||
@@ -318,7 +322,7 @@ func getSubnetAPIKeyFromConfig(alias string) string {
|
||||
}
|
||||
|
||||
func setGlobalSubnetProxyFromConfig(alias string) error {
|
||||
if globalSubnetProxyURL != nil {
|
||||
if GlobalSubnetProxyURL != nil {
|
||||
// proxy already set
|
||||
return nil
|
||||
}
|
||||
@@ -341,7 +345,7 @@ func setGlobalSubnetProxyFromConfig(alias string) error {
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
globalSubnetProxyURL = proxyURL
|
||||
GlobalSubnetProxyURL = proxyURL
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -507,7 +511,7 @@ func subnetLogin() (string, error) {
|
||||
"username": username,
|
||||
"password": string(bytepw),
|
||||
}
|
||||
respStr, e := subnetPostReq(subnetLoginURL(), loginReq, nil)
|
||||
respStr, e := SubnetPostReq(subnetLoginURL(), loginReq, nil)
|
||||
if e != nil {
|
||||
return "", e
|
||||
}
|
||||
@@ -520,7 +524,7 @@ func subnetLogin() (string, error) {
|
||||
fmt.Println()
|
||||
|
||||
mfaLoginReq := SubnetMFAReq{Username: username, OTP: string(byteotp), Token: mfaToken}
|
||||
respStr, e = subnetPostReq(subnetMFAURL(), mfaLoginReq, nil)
|
||||
respStr, e = SubnetPostReq(subnetMFAURL(), mfaLoginReq, nil)
|
||||
if e != nil {
|
||||
return "", e
|
||||
}
|
||||
@@ -581,7 +585,7 @@ func getSubnetAPIKey(alias string) (string, error) {
|
||||
}
|
||||
|
||||
func getSubnetAPIKeyUsingLicense(lic string) (string, error) {
|
||||
return getSubnetAPIKeyUsingAuthHeaders(subnetLicenseAuthHeaders(lic))
|
||||
return getSubnetAPIKeyUsingAuthHeaders(SubnetLicenseAuthHeaders(lic))
|
||||
}
|
||||
|
||||
func getSubnetAPIKeyUsingAuthToken(authToken string) (string, error) {
|
||||
@@ -605,7 +609,7 @@ func getSubnetLicenseUsingAPIKey(alias, apiKey string) (string, error) {
|
||||
// registerClusterOnSubnet - Registers the given cluster on SUBNET using given API key for auth
|
||||
// If the API key is empty, user will be asked to log in using SUBNET credentials.
|
||||
func registerClusterOnSubnet(clusterRegInfo ClusterRegistrationInfo, alias, apiKey string) (string, string, error) {
|
||||
regURL, headers, e := subnetURLWithAuth(subnetRegisterURL(), apiKey)
|
||||
regURL, headers, e := subnetURLWithAuth(SubnetRegisterURL(), apiKey)
|
||||
if e != nil {
|
||||
return "", "", e
|
||||
}
|
||||
@@ -616,7 +620,7 @@ func registerClusterOnSubnet(clusterRegInfo ClusterRegistrationInfo, alias, apiK
|
||||
}
|
||||
|
||||
reqPayload := ClusterRegistrationReq{Token: regToken}
|
||||
resp, e := subnetPostReq(regURL, reqPayload, headers)
|
||||
resp, e := SubnetPostReq(regURL, reqPayload, headers)
|
||||
if e != nil {
|
||||
return "", "", e
|
||||
}
|
||||
@@ -636,7 +640,7 @@ func unregisterClusterFromSubnet(depID, apiKey string) error {
|
||||
return e
|
||||
}
|
||||
|
||||
_, e = subnetPostReq(regURL, nil, headers)
|
||||
_, e = SubnetPostReq(regURL, nil, headers)
|
||||
return e
|
||||
}
|
||||
|
||||
@@ -704,7 +708,7 @@ func parseLicense(license string) (*licverifier.LicenseInfo, error) {
|
||||
Client: *client,
|
||||
ExpiryGracePeriod: 0,
|
||||
}
|
||||
lv.Init(globalDevMode)
|
||||
lv.Init(GlobalDevMode)
|
||||
return lv.ParseLicense(license)
|
||||
}
|
||||
|
||||
@@ -722,104 +726,6 @@ func prepareSubnetUploadURL(uploadURL, alias, apiKey string) (string, map[string
|
||||
return reqURL, headers
|
||||
}
|
||||
|
||||
type subnetFileUploader struct {
|
||||
alias string
|
||||
filePath string
|
||||
filename string
|
||||
reqURL string
|
||||
headers subnetHeaders
|
||||
autoCompress bool
|
||||
deleteAfterUpload bool
|
||||
params url.Values
|
||||
}
|
||||
|
||||
func (i *subnetFileUploader) uploadFileToSubnet() (string, error) {
|
||||
req, e := i.subnetUploadReq()
|
||||
if e != nil {
|
||||
return "", e
|
||||
}
|
||||
|
||||
resp, e := subnetReqDo(req, i.headers)
|
||||
if e != nil {
|
||||
return "", e
|
||||
}
|
||||
|
||||
if i.deleteAfterUpload {
|
||||
os.Remove(i.filePath)
|
||||
}
|
||||
|
||||
// ensure that both api-key and license from
|
||||
// SUBNET response are saved in the config
|
||||
extractAndSaveSubnetCreds(i.alias, resp)
|
||||
|
||||
return resp, e
|
||||
}
|
||||
|
||||
func (i *subnetFileUploader) updateParams() {
|
||||
if i.params == nil {
|
||||
i.params = url.Values{}
|
||||
}
|
||||
|
||||
if i.filename == "" {
|
||||
i.filename = filepath.Base(i.filePath)
|
||||
}
|
||||
|
||||
i.autoCompress = i.autoCompress && !strings.HasSuffix(strings.ToLower(i.filePath), ".zst")
|
||||
if i.autoCompress {
|
||||
i.filename += ".zst"
|
||||
i.params.Add("auto-compression", "zstd")
|
||||
}
|
||||
|
||||
i.params.Add("filename", i.filename)
|
||||
i.reqURL += "?" + i.params.Encode()
|
||||
}
|
||||
|
||||
func (i *subnetFileUploader) subnetUploadReq() (*http.Request, error) {
|
||||
i.updateParams()
|
||||
|
||||
r, w := io.Pipe()
|
||||
mwriter := multipart.NewWriter(w)
|
||||
contentType := mwriter.FormDataContentType()
|
||||
|
||||
go func() {
|
||||
var (
|
||||
part io.Writer
|
||||
e error
|
||||
)
|
||||
defer func() {
|
||||
mwriter.Close()
|
||||
w.CloseWithError(e)
|
||||
}()
|
||||
|
||||
part, e = mwriter.CreateFormFile("file", i.filename)
|
||||
if e != nil {
|
||||
return
|
||||
}
|
||||
|
||||
file, e := os.Open(i.filePath)
|
||||
if e != nil {
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
if i.autoCompress {
|
||||
z, _ := zstd.NewWriter(part, zstd.WithEncoderConcurrency(2))
|
||||
defer z.Close()
|
||||
_, e = z.ReadFrom(file)
|
||||
} else {
|
||||
_, e = io.Copy(part, file)
|
||||
}
|
||||
}()
|
||||
|
||||
req, e := http.NewRequest(http.MethodPost, i.reqURL, r)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
req.Header.Add("Content-Type", contentType)
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func getAPIKeyFlag(ctx *cli.Context) (string, error) {
|
||||
apiKey := ctx.String("api-key")
|
||||
|
||||
@@ -850,7 +756,7 @@ func initSubnetConnectivity(ctx *cli.Context, aliasedURL string, failOnConnErr b
|
||||
e = setGlobalSubnetProxyFromConfig(alias)
|
||||
fatalIf(probe.NewError(e), "Error in setting SUBNET proxy:")
|
||||
|
||||
sbu := subnetBaseURL()
|
||||
sbu := SubnetBaseURL()
|
||||
err := checkURLReachable(sbu)
|
||||
if err != nil && failOnConnErr {
|
||||
fatal(err.Trace(aliasedURL), "Unable to reach %s, please use --airgap if there is no connectivity to SUBNET", sbu)
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
)
|
||||
|
||||
func TestSubnetBaseURL(t *testing.T) {
|
||||
sbu := subnetBaseURL()
|
||||
sbu := SubnetBaseURL()
|
||||
u, err := url.ParseRequestURI(sbu)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
gojson "encoding/json"
|
||||
"errors"
|
||||
@@ -123,26 +124,13 @@ func checkSupportDiagSyntax(ctx *cli.Context) {
|
||||
|
||||
// compress and tar MinIO diagnostics output
|
||||
func tarGZ(healthInfo interface{}, version, filename string) error {
|
||||
f, e := os.OpenFile(filename, os.O_CREATE|os.O_RDWR, 0o666)
|
||||
data, e := TarGZHealthInfo(healthInfo, version)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
gzWriter := gzip.NewWriter(f)
|
||||
defer gzWriter.Close()
|
||||
|
||||
enc := gojson.NewEncoder(gzWriter)
|
||||
|
||||
header := struct {
|
||||
Version string `json:"version"`
|
||||
}{Version: version}
|
||||
|
||||
if e := enc.Encode(header); e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
if e := enc.Encode(healthInfo); e != nil {
|
||||
e = os.WriteFile(filename, data, 0o666)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
@@ -161,6 +149,32 @@ func tarGZ(healthInfo interface{}, version, filename string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TarGZHealthInfo - compress and tar MinIO diagnostics output
|
||||
func TarGZHealthInfo(healthInfo interface{}, version string) ([]byte, error) {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
gzWriter := gzip.NewWriter(buffer)
|
||||
|
||||
enc := gojson.NewEncoder(gzWriter)
|
||||
|
||||
header := struct {
|
||||
Version string `json:"version"`
|
||||
}{Version: version}
|
||||
|
||||
if e := enc.Encode(header); e != nil {
|
||||
return nil, e
|
||||
}
|
||||
|
||||
if e := enc.Encode(healthInfo); e != nil {
|
||||
return nil, e
|
||||
}
|
||||
|
||||
if e := gzWriter.Close(); e != nil {
|
||||
return nil, e
|
||||
}
|
||||
|
||||
return buffer.Bytes(), nil
|
||||
}
|
||||
|
||||
func infoText(s string) string {
|
||||
console.SetColor("INFO", color.New(color.FgGreen, color.Bold))
|
||||
return console.Colorize("INFO", s)
|
||||
@@ -205,7 +219,7 @@ func execSupportDiag(ctx *cli.Context, client *madmin.AdminClient, alias, apiKey
|
||||
if !globalAirgapped {
|
||||
// Retrieve subnet credentials (login/license) beforehand as
|
||||
// it can take a long time to fetch the health information
|
||||
uploadURL := subnetUploadURL("health")
|
||||
uploadURL := SubnetUploadURL("health")
|
||||
reqURL, headers = prepareSubnetUploadURL(uploadURL, alias, apiKey)
|
||||
}
|
||||
|
||||
@@ -228,13 +242,13 @@ func execSupportDiag(ctx *cli.Context, client *madmin.AdminClient, alias, apiKey
|
||||
fatalIf(probe.NewError(e), "Unable to save MinIO diagnostics report")
|
||||
|
||||
if !globalAirgapped {
|
||||
_, e := (&subnetFileUploader{
|
||||
_, e = (&SubnetFileUploader{
|
||||
alias: alias,
|
||||
filePath: filename,
|
||||
reqURL: reqURL,
|
||||
headers: headers,
|
||||
deleteAfterUpload: true,
|
||||
}).uploadFileToSubnet()
|
||||
FilePath: filename,
|
||||
ReqURL: reqURL,
|
||||
Headers: headers,
|
||||
DeleteAfterUpload: true,
|
||||
}).UploadFileToSubnet()
|
||||
fatalIf(probe.NewError(e), "Unable to upload MinIO diagnostics report to SUBNET portal")
|
||||
|
||||
printMsg(supportDiagMessage{})
|
||||
|
||||
@@ -196,18 +196,18 @@ func mainSupportInspect(ctx *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
uploadURL := subnetUploadURL("inspect")
|
||||
uploadURL := SubnetUploadURL("inspect")
|
||||
reqURL, headers := prepareSubnetUploadURL(uploadURL, alias, apiKey)
|
||||
|
||||
tmpFileName := tmpFile.Name()
|
||||
_, e = (&subnetFileUploader{
|
||||
_, e = (&SubnetFileUploader{
|
||||
alias: alias,
|
||||
filePath: tmpFileName,
|
||||
FilePath: tmpFileName,
|
||||
filename: inspectOutputFilename,
|
||||
reqURL: reqURL,
|
||||
headers: headers,
|
||||
deleteAfterUpload: true,
|
||||
}).uploadFileToSubnet()
|
||||
ReqURL: reqURL,
|
||||
Headers: headers,
|
||||
DeleteAfterUpload: true,
|
||||
}).UploadFileToSubnet()
|
||||
if e != nil {
|
||||
console.Errorln("Unable to upload inspect data to SUBNET portal: " + e.Error())
|
||||
saveInspectDataFile(key, tmpFile)
|
||||
|
||||
@@ -490,16 +490,16 @@ func execSupportPerf(ctx *cli.Context, aliasedURL, perfType string) {
|
||||
return
|
||||
}
|
||||
|
||||
uploadURL := subnetUploadURL("perf")
|
||||
uploadURL := SubnetUploadURL("perf")
|
||||
reqURL, headers := prepareSubnetUploadURL(uploadURL, alias, apiKey)
|
||||
|
||||
_, e = (&subnetFileUploader{
|
||||
_, e = (&SubnetFileUploader{
|
||||
alias: alias,
|
||||
filePath: tmpFileName,
|
||||
reqURL: reqURL,
|
||||
headers: headers,
|
||||
deleteAfterUpload: true,
|
||||
}).uploadFileToSubnet()
|
||||
FilePath: tmpFileName,
|
||||
ReqURL: reqURL,
|
||||
Headers: headers,
|
||||
DeleteAfterUpload: true,
|
||||
}).UploadFileToSubnet()
|
||||
if e != nil {
|
||||
errorIf(probe.NewError(e), "Unable to upload performance results to SUBNET portal")
|
||||
savePerfResultFile(tmpFileName, resultFileNamePfx)
|
||||
|
||||
@@ -226,7 +226,7 @@ func execSupportProfile(ctx *cli.Context, client *madmin.AdminClient, alias, api
|
||||
if !globalAirgapped {
|
||||
// Retrieve subnet credentials (login/license) beforehand as
|
||||
// it can take a long time to fetch the profile data
|
||||
uploadURL := subnetUploadURL("profile")
|
||||
uploadURL := SubnetUploadURL("profile")
|
||||
reqURL, headers = prepareSubnetUploadURL(uploadURL, alias, apiKey)
|
||||
}
|
||||
|
||||
@@ -239,13 +239,13 @@ func execSupportProfile(ctx *cli.Context, client *madmin.AdminClient, alias, api
|
||||
saveProfileFile(data)
|
||||
|
||||
if !globalAirgapped {
|
||||
_, e = (&subnetFileUploader{
|
||||
_, e = (&SubnetFileUploader{
|
||||
alias: alias,
|
||||
filePath: profileFile,
|
||||
reqURL: reqURL,
|
||||
headers: headers,
|
||||
deleteAfterUpload: true,
|
||||
}).uploadFileToSubnet()
|
||||
FilePath: profileFile,
|
||||
ReqURL: reqURL,
|
||||
Headers: headers,
|
||||
DeleteAfterUpload: true,
|
||||
}).UploadFileToSubnet()
|
||||
if e != nil {
|
||||
printMsg(supportProfileMessage{
|
||||
Status: "error",
|
||||
|
||||
@@ -128,17 +128,17 @@ func execSupportUpload(ctx *cli.Context, alias, apiKey string) {
|
||||
params.Add("message", msg)
|
||||
}
|
||||
|
||||
uploadURL := subnetUploadURL("attachment")
|
||||
uploadURL := SubnetUploadURL("attachment")
|
||||
reqURL, headers := prepareSubnetUploadURL(uploadURL, alias, apiKey)
|
||||
|
||||
_, e := (&subnetFileUploader{
|
||||
_, e := (&SubnetFileUploader{
|
||||
alias: alias,
|
||||
filePath: filePath,
|
||||
reqURL: reqURL,
|
||||
headers: headers,
|
||||
autoCompress: true,
|
||||
params: params,
|
||||
}).uploadFileToSubnet()
|
||||
FilePath: filePath,
|
||||
ReqURL: reqURL,
|
||||
Headers: headers,
|
||||
AutoCompress: true,
|
||||
Params: params,
|
||||
}).UploadFileToSubnet()
|
||||
if e != nil {
|
||||
fatalIf(probe.NewError(e), "Unable to upload file to SUBNET")
|
||||
}
|
||||
|
||||
@@ -113,9 +113,9 @@ func validateClusterRegistered(alias string, cmdTalksToSubnet bool) string {
|
||||
// Non-registered execution allowed only in following scenarios
|
||||
// command doesn't talk to subnet: dev mode (`--dev` passed)
|
||||
// command talks to subnet: dev+airgapped mode (both `--dev` and `--airgap` passed)
|
||||
requireRegistration := !globalDevMode
|
||||
requireRegistration := !GlobalDevMode
|
||||
if cmdTalksToSubnet {
|
||||
requireRegistration = !(globalDevMode && globalAirgapped)
|
||||
requireRegistration = !(GlobalDevMode && globalAirgapped)
|
||||
}
|
||||
|
||||
apiKey, e := getSubnetAPIKey(alias)
|
||||
|
||||
Reference in New Issue
Block a user