diff --git a/cmd/globals.go b/cmd/globals.go index 4c355bdb..5add31f8 100644 --- a/cmd/globals.go +++ b/cmd/globals.go @@ -61,16 +61,20 @@ const ( ) var ( - globalQuiet = false // Quiet flag set via command line - globalJSON = false // Json flag set via command line - globalJSONLine = false // Print json as single line. - 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 + globalQuiet = false // Quiet flag set via command line + globalJSON = false // Json flag set via command line + globalJSONLine = false // Print json as single line. + 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 + globalAirgapped = false // Airgapped flag set via command line + 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. diff --git a/cmd/license-update.go b/cmd/license-update.go index 847763b6..fbe7173d 100644 --- a/cmd/license-update.go +++ b/cmd/license-update.go @@ -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) diff --git a/cmd/subnet-file-uploader.go b/cmd/subnet-file-uploader.go new file mode 100644 index 00000000..dce3d8bf --- /dev/null +++ b/cmd/subnet-file-uploader.go @@ -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 . + +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 +} diff --git a/cmd/subnet-utils.go b/cmd/subnet-utils.go index c7a19c2b..5596b9da 100644 --- a/cmd/subnet-utils.go +++ b/cmd/subnet-utils.go @@ -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) diff --git a/cmd/subnet-utils_test.go b/cmd/subnet-utils_test.go index 3aefe640..d7dab06f 100644 --- a/cmd/subnet-utils_test.go +++ b/cmd/subnet-utils_test.go @@ -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) diff --git a/cmd/support-diag.go b/cmd/support-diag.go index 19af028f..c1415b32 100644 --- a/cmd/support-diag.go +++ b/cmd/support-diag.go @@ -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{}) diff --git a/cmd/support-inspect.go b/cmd/support-inspect.go index a008ae20..83ac712d 100644 --- a/cmd/support-inspect.go +++ b/cmd/support-inspect.go @@ -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) diff --git a/cmd/support-perf.go b/cmd/support-perf.go index de3a8432..0d2603f8 100644 --- a/cmd/support-perf.go +++ b/cmd/support-perf.go @@ -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) diff --git a/cmd/support-profile.go b/cmd/support-profile.go index f1785ea9..7ba0accc 100644 --- a/cmd/support-profile.go +++ b/cmd/support-profile.go @@ -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", diff --git a/cmd/support-upload.go b/cmd/support-upload.go index aaaa10c1..d6e72d79 100644 --- a/cmd/support-upload.go +++ b/cmd/support-upload.go @@ -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") } diff --git a/cmd/support.go b/cmd/support.go index ce469740..eb0fb3bb 100644 --- a/cmd/support.go +++ b/cmd/support.go @@ -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)