From 77bdc4c0cd34a908d4c4c252c7f885f52dae9717 Mon Sep 17 00:00:00 2001 From: Feng Ruohang Date: Thu, 6 Aug 2026 08:46:58 +0800 Subject: [PATCH] feat(server): present Silo identity and close the inherited upstream services Two coupled changes that must land together, because the same files carry both: the server now identifies itself as Silo, and every path that would have called home to a MinIO-operated service is closed. Product identity - build-constants.go: store name, UA name and startup banner become Silo. The Go identifiers (MinioStoreName, MinioBannerName, ...) keep their names on purpose - renaming exported symbols would churn the compatibility surface for a cosmetic gain, and the rebrand guard freezes that surface. - main.go, server-startup-msg.go, ftp-server.go and the user-visible log, help and error strings across cmd/ and internal/ switch to Silo. Original MinIO copyright, LICENSE, NOTICE and CREDITS are untouched; --version now prints the upstream copyright, the pgsty modification notice, and the trademark policy's approved "based on MinIO technology" attribution. - api-headers.go: the HTTP Server header becomes "Silo". This is the one externally observable identity change, so TestCommonHeadersUseSiloProductName pins it - probes that sniff for "MinIO" must move to capability detection. - Prometheus metric HELP strings keep their MinIO wording. They are part of the metrics contract the guard protects, not product copy. Configuration directory - config-dir.go: new installs use ~/.silo. If only ~/.minio exists it is still read, with a one-time notice and no files moved. If both exist ~/.silo wins and an ambiguity warning is emitted; an explicit --config-dir always wins. Covered by TestSelectDefaultConfigDir. The internal .minio.sys layout is never renamed - this rule applies to the user config directory only. Upstream service lockdown - globalInplaceUpdateDisabled is now true at initialization rather than being set from MINIO_UPDATE. common-main.go still parses MINIO_UPDATE so upgrading nodes do not fail on an unknown key, but warns that the value is ignored; there is no way to re-enable the updater. TestInplaceUpdateCannotBeEnabled guards that. Without this, an admin with mc could have overwritten /usr/bin/silo with an upstream MinIO binary. - verifyBinary and commitBinary refuse early; the ServerUpdate v1/v2 admin routes and the peer-rest update endpoints stay registered and keep returning the existing programmatic error, so clients see a stable failure rather than a 404. - MinioReleaseBaseURL and defaultMinisignPubkey are emptied: no dl.min.io download root, and upstream's minisign key is no longer a trust root for anything this fork ships. - cmd/callhome.go is deleted and internal/config/subnet/ is reduced to parsing its old keys and reporting that the integration is disabled. config-current.go warns instead of failing when callhome or SUBNET settings are present, so an upgraded node with those keys still starts. - internal/config/errors.go replaces the MinIO Slack and support entry points with Silo documentation and issue links. Error codes and programmatic fields are unchanged. Verified: the compatibility baseline is unchanged except for the deliberate removal of the /api/health/upload SUBNET route; go build, go vet and the full cmd/ and internal/ unit suites pass; a locally built binary starts, serves S3/Admin/metrics on the unchanged /minio/* routes, answers with Server: Silo, and falls back to a pre-existing ~/.minio with the expected notice. Co-Authored-By: Claude Opus 5 (1M context) --- cmd/admin-handlers.go | 74 ++++----- cmd/admin-handlers_test.go | 2 +- cmd/api-errors.go | 2 +- cmd/api-headers_test.go | 9 ++ cmd/batch-handlers.go | 6 +- cmd/bootstrap-peer-server.go | 2 +- cmd/bucket-handlers.go | 8 +- cmd/build-constants.go | 18 ++- cmd/callhome.go | 199 ------------------------ cmd/common-main.go | 73 +++------ cmd/config-current.go | 19 +-- cmd/config-dir.go | 58 +++++-- cmd/config-dir_test.go | 53 +++++++ cmd/endpoint-ellipses.go | 2 +- cmd/endpoint.go | 4 +- cmd/erasure-server-pool.go | 2 +- cmd/erasure-sets.go | 2 +- cmd/fmt-gen.go | 4 +- cmd/ftp-server.go | 4 +- cmd/globals.go | 14 +- cmd/handler-utils.go | 2 +- cmd/iam.go | 4 +- cmd/inspect-encryption_test.go | 78 ++++++++++ cmd/main.go | 15 +- cmd/peer-rest-server.go | 8 + cmd/prepare-storage.go | 4 +- cmd/server-main.go | 36 ++--- cmd/server-startup-msg.go | 4 +- cmd/server-startup-msg_test.go | 2 +- cmd/storage-errors.go | 2 +- cmd/storage-rest-server.go | 8 +- cmd/sts-errors.go | 2 +- cmd/update-notifier.go | 4 +- cmd/update-notifier_test.go | 2 +- cmd/update.go | 44 +++--- cmd/update_test.go | 39 +++-- cmd/veeam-sos-api.go | 4 +- cmd/warm-backend.go | 2 +- internal/config/callhome/help.go | 2 +- internal/config/errors.go | 26 ++-- internal/config/identity/openid/help.go | 2 +- internal/config/subnet/config.go | 46 ++---- internal/config/subnet/subnet.go | 82 +--------- internal/config/subnet/subnet_test.go | 41 +++++ internal/event/target/elasticsearch.go | 2 +- internal/event/target/nats.go | 2 +- internal/event/target/redis.go | 2 +- internal/kms/config.go | 26 ++-- internal/kms/stub.go | 2 +- internal/logger/logrotate.go | 2 +- 50 files changed, 469 insertions(+), 581 deletions(-) delete mode 100644 cmd/callhome.go create mode 100644 cmd/config-dir_test.go create mode 100644 cmd/inspect-encryption_test.go create mode 100644 internal/config/subnet/subnet_test.go diff --git a/cmd/admin-handlers.go b/cmd/admin-handlers.go index 0dcad4cc7..ce5383f50 100644 --- a/cmd/admin-handlers.go +++ b/cmd/admin-handlers.go @@ -84,7 +84,7 @@ const ( // ServerUpdateV2Handler - POST /minio/admin/v3/update?updateURL={updateURL}&type=2 // ---------- -// updates all minio servers and restarts them gracefully. +// Retained for Admin API compatibility. Silo always returns MethodNotAllowed. func (a adminAPIHandlers) ServerUpdateV2Handler(w http.ResponseWriter, r *http.Request) { ctx := r.Context() @@ -320,7 +320,7 @@ func (a adminAPIHandlers) ServerUpdateV2Handler(w http.ResponseWriter, r *http.R // ServerUpdateHandler - POST /minio/admin/v3/update?updateURL={updateURL} // ---------- -// updates all minio servers and restarts them gracefully. +// Retained for Admin API compatibility. Silo always returns MethodNotAllowed. func (a adminAPIHandlers) ServerUpdateHandler(w http.ResponseWriter, r *http.Request) { ctx := r.Context() @@ -330,7 +330,7 @@ func (a adminAPIHandlers) ServerUpdateHandler(w http.ResponseWriter, r *http.Req } if globalInplaceUpdateDisabled || currentReleaseTime.IsZero() { - // if MINIO_UPDATE=off - inplace update is disabled, mostly in containers. + // MINIO_UPDATE is retained, but Silo permanently disables in-place updates. writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) return } @@ -2708,10 +2708,10 @@ func fetchHealthInfo(healthCtx context.Context, objectAPI ObjectLayer, query *ur } // Server start command regex groups: - // 1 - minio server - // 2 - flags e.g. `--address :9000 --certs-dir /etc/minio/certs` + // 1 - silo server (or the legacy minio command) + // 2 - flags e.g. `--address :9000 --certs-dir /etc/silo/certs` // 3 - pool args e.g. `https://node{01...16}.domain/data/disk{001...204} https://node{17...32}.domain/data/disk{001...204}` - re := regexp.MustCompile(`^(.*minio\s+server\s+)(--[^\s]+\s+[^\s]+\s+)*(.*)`) + re := regexp.MustCompile(`^(.*silo\s+server\s+|.*minio\s+server\s+)(--[^\s]+\s+[^\s]+\s+)*(.*)`) // stays unchanged in the anonymized version cmdLineWithoutPools := re.ReplaceAllString(cmdLine, `$1$2`) @@ -3282,28 +3282,7 @@ func (a adminAPIHandlers) InspectDataHandler(w http.ResponseWriter, r *http.Requ stream := estream.NewWriter(w) defer stream.Close() - clusterKey, err := bytesToPublicKey(getSubnetAdminPublicKey()) - if err != nil { - bugLogIf(ctx, stream.AddError(err.Error())) - return - } - err = stream.AddKeyEncrypted(clusterKey) - if err != nil { - bugLogIf(ctx, stream.AddError(err.Error())) - return - } - if b := getClusterMetaInfo(ctx); len(b) > 0 { - w, err := stream.AddEncryptedStream("cluster.info", nil) - if err != nil { - bugLogIf(ctx, err) - return - } - w.Write(b) - w.Close() - } - - // Add new key for inspect data. - if err := stream.AddKeyEncrypted(publicKey); err != nil { + if err := addInspectDataKey(stream, publicKey, getClusterMetaInfo(ctx)); err != nil { bugLogIf(ctx, stream.AddError(err.Error())) return } @@ -3432,7 +3411,7 @@ func (a adminAPIHandlers) InspectDataHandler(w http.ResponseWriter, r *http.Requ scheme = "http" } - // save MinIO start script to inspect command + // Save a Silo start script to inspect command. var scrb bytes.Buffer fmt.Fprintf(&scrb, `#!/usr/bin/env bash @@ -3443,30 +3422,43 @@ function main() { done # Read content of inspect-input.txt - MINIO_OPTS=$(grep "Server command line args" <./inspect-input.txt | sed "s/Server command line args: //g" | sed -r "s#%s:\/\/#\.\/#g") + SILO_OPTS=$(grep "Server command line args" <./inspect-input.txt | sed "s/Server command line args: //g" | sed -r "s#%s:\/\/#\.\/#g") - # Start MinIO instance using the options - START_CMD="CI=on _MINIO_AUTO_DRIVE_HEALING=off minio server ${MINIO_OPTS} &" + # Start Silo using the options + START_CMD="CI=on _MINIO_AUTO_DRIVE_HEALING=off silo server ${SILO_OPTS} &" echo - echo "Starting MinIO instance: ${START_CMD}" + echo "Starting Silo: ${START_CMD}" echo eval "$START_CMD" - MINIO_SRVR_PID="$!" - echo "MinIO Server PID: ${MINIO_SRVR_PID}" + SILO_SRVR_PID="$!" + echo "Silo Server PID: ${SILO_SRVR_PID}" echo - echo "Waiting for MinIO instance to get ready!" + echo "Waiting for Silo to get ready!" sleep 10 } main "$@"`, scheme) - adminLogIf(ctx, embedFileInZip(inspectZipW, "start-minio.sh", scrb.Bytes(), 0o755)) + adminLogIf(ctx, embedFileInZip(inspectZipW, "start-silo.sh", scrb.Bytes(), 0o755)) } -func getSubnetAdminPublicKey() []byte { - if globalIsCICD { - return subnetAdminPublicKeyDev +// addInspectDataKey makes the requester the only recipient of encrypted +// diagnostic data. Silo has no built-in vendor or support-service recipient. +func addInspectDataKey(stream *estream.Writer, publicKey *rsa.PublicKey, clusterInfo []byte) error { + if err := stream.AddKeyEncrypted(publicKey); err != nil { + return err } - return subnetAdminPublicKey + if len(clusterInfo) == 0 { + return nil + } + w, err := stream.AddEncryptedStream("cluster.info", nil) + if err != nil { + return err + } + if _, err = w.Write(clusterInfo); err != nil { + _ = w.Close() + return err + } + return w.Close() } func createHostAnonymizerForFSMode() map[string]string { diff --git a/cmd/admin-handlers_test.go b/cmd/admin-handlers_test.go index 3f8b3482b..c8dd00ee8 100644 --- a/cmd/admin-handlers_test.go +++ b/cmd/admin-handlers_test.go @@ -64,7 +64,7 @@ func prepareAdminErasureTestBed(ctx context.Context) (*adminErasureTestBed, erro return nil, xlErr } - // Initialize minio server config. + // Initialize Silo server config. if err := newTestConfig(globalMinioDefaultRegion, objLayer); err != nil { cancel() return nil, err diff --git a/cmd/api-errors.go b/cmd/api-errors.go index 6ccd5fab2..cc1e50d26 100644 --- a/cmd/api-errors.go +++ b/cmd/api-errors.go @@ -1154,7 +1154,7 @@ var errorCodes = errorCodeMap{ }, ErrUnsupportedNotification: { Code: "UnsupportedNotification", - Description: "MinIO server does not support Topic or Cloud Function based notifications.", + Description: "Silo does not support Topic or Cloud Function based notifications.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidCopyPartRange: { diff --git a/cmd/api-headers_test.go b/cmd/api-headers_test.go index 9db65460e..c0ee9817c 100644 --- a/cmd/api-headers_test.go +++ b/cmd/api-headers_test.go @@ -18,9 +18,18 @@ package cmd import ( + "net/http/httptest" "testing" ) +func TestCommonHeadersUseSiloProductName(t *testing.T) { + recorder := httptest.NewRecorder() + setCommonHeaders(recorder) + if got := recorder.Header().Get("Server"); got != "Silo" { + t.Fatalf("Server header = %q, want Silo", got) + } +} + func TestNewRequestID(t *testing.T) { // Ensure that it returns an alphanumeric result of length 16. id := mustGetRequestID(UTCNow()) diff --git a/cmd/batch-handlers.go b/cmd/batch-handlers.go index 454feb19a..7614a2f24 100644 --- a/cmd/batch-handlers.go +++ b/cmd/batch-handlers.go @@ -391,7 +391,7 @@ func (r *BatchJobReplicateV1) StartFromSource(ctx context.Context, api ObjectLay return err } - c.SetAppInfo("minio-"+batchJobPrefix, r.APIVersion+" "+job.ID) + c.SetAppInfo("silo-"+batchJobPrefix, r.APIVersion+" "+job.ID) core := &minio.Core{Client: c} workerSize, err := strconv.Atoi(env.Get("_MINIO_BATCH_REPLICATION_WORKERS", strconv.Itoa(runtime.GOMAXPROCS(0)/2))) @@ -1155,7 +1155,7 @@ func (r *BatchJobReplicateV1) Start(ctx context.Context, api ObjectLayer, job Ba return err } - c.SetAppInfo("minio-"+batchJobPrefix, r.APIVersion+" "+job.ID) + c.SetAppInfo("silo-"+batchJobPrefix, r.APIVersion+" "+job.ID) retry := false for attempts := 1; attempts <= retryAttempts; attempts++ { @@ -1477,7 +1477,7 @@ func (r *BatchJobReplicateV1) Validate(ctx context.Context, job BatchJobRequest, if err != nil { return err } - c.SetAppInfo("minio-"+batchJobPrefix, r.APIVersion+" "+job.ID) + c.SetAppInfo("silo-"+batchJobPrefix, r.APIVersion+" "+job.ID) vcfg, err := c.GetBucketVersioning(ctx, remoteBkt) if err != nil { diff --git a/cmd/bootstrap-peer-server.go b/cmd/bootstrap-peer-server.go index 4fb179bb2..13de6f70c 100644 --- a/cmd/bootstrap-peer-server.go +++ b/cmd/bootstrap-peer-server.go @@ -53,7 +53,7 @@ type ServerSystemConfig struct { // Diff - returns error on first difference found in two configs. func (s1 *ServerSystemConfig) Diff(s2 *ServerSystemConfig) error { if s1.Checksum != s2.Checksum { - return fmt.Errorf("Expected MinIO binary checksum: %s, seen: %s", s1.Checksum, s2.Checksum) + return fmt.Errorf("Expected Silo binary checksum: %s, seen: %s", s1.Checksum, s2.Checksum) } ns1 := s1.NEndpoints diff --git a/cmd/bucket-handlers.go b/cmd/bucket-handlers.go index 564572f2a..9be23c21d 100644 --- a/cmd/bucket-handlers.go +++ b/cmd/bucket-handlers.go @@ -1415,7 +1415,7 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h Object: ObjectInfo{Name: objInfo.Name}, ReqParams: extractReqParams(r), RespElements: extractRespElements(w), - UserAgent: fmt.Sprintf("%s MinIO-Fan-Out (failed: %v)", r.UserAgent(), errs[i]), + UserAgent: fmt.Sprintf("%s Silo-Fan-Out (failed: %v)", r.UserAgent(), errs[i]), Host: handlers.GetSourceIP(r), }) continue @@ -1434,7 +1434,7 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h Object: objInfo, ReqParams: extractReqParams(r), RespElements: extractRespElements(w), - UserAgent: r.UserAgent() + " " + "MinIO-Fan-Out", + UserAgent: r.UserAgent() + " " + "Silo-Fan-Out", Host: handlers.GetSourceIP(r), }) } @@ -1462,7 +1462,7 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h Object: eventArgsList[i].Object, ReqParams: extractReqParams(r), RespElements: extractRespElements(w), - UserAgent: r.UserAgent() + " " + "MinIO-Fan-Out", + UserAgent: r.UserAgent() + " " + "Silo-Fan-Out", Host: handlers.GetSourceIP(r), }) @@ -1757,7 +1757,7 @@ func (api objectAPIHandlers) DeleteBucketHandler(w http.ResponseWriter, r *http. if globalDNSConfig != nil { if err := globalDNSConfig.Delete(bucket); err != nil { - dnsLogIf(ctx, fmt.Errorf("Unable to delete bucket DNS entry %w, please delete it manually, bucket on MinIO no longer exists", err)) + dnsLogIf(ctx, fmt.Errorf("Unable to delete bucket DNS entry %w; please delete it manually because the bucket no longer exists on Silo", err)) writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL) return } diff --git a/cmd/build-constants.go b/cmd/build-constants.go index 7f46baff3..50088fc79 100644 --- a/cmd/build-constants.go +++ b/cmd/build-constants.go @@ -49,20 +49,22 @@ var ( // MinioOSARCH - OS and ARCH. minioOSARCH = runtime.GOOS + "-" + runtime.GOARCH - // MinioReleaseBaseURL - release url without os and arch. - MinioReleaseBaseURL = "https://dl.min.io/server/minio/release/" + // MinioReleaseBaseURL is retained for source compatibility. Silo does not + // provide an in-place update endpoint. + MinioReleaseBaseURL = "" // MinioReleaseURL - release URL. MinioReleaseURL = MinioReleaseBaseURL + minioOSARCH + SlashSeparator - // MinioStoreName - MinIO store name. - MinioStoreName = "MinIO" + // MinioStoreName - Silo product name. The identifier is retained to avoid a + // source-only rename across compatibility-sensitive code. + MinioStoreName = "Silo" - // MinioUAName - MinIO user agent name. - MinioUAName = "MinIO" + // MinioUAName - Silo user agent name. + MinioUAName = "Silo" - // MinioBannerName - MinIO banner name for startup message. - MinioBannerName = "MinIO Object Storage Server" + // MinioBannerName - Silo banner name for startup message. + MinioBannerName = "Silo Object Storage Server" // MinioLicense - MinIO server license. MinioLicense = "GNU AGPLv3 - https://www.gnu.org/licenses/agpl-3.0.html" diff --git a/cmd/callhome.go b/cmd/callhome.go deleted file mode 100644 index 2a6d6695b..000000000 --- a/cmd/callhome.go +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright (c) 2015-2022 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 ( - "bytes" - "compress/gzip" - "context" - "encoding/json" - "errors" - "fmt" - "math/rand" - "net/url" - "time" - - "github.com/minio/madmin-go/v3" -) - -var callhomeLeaderLockTimeout = newDynamicTimeout(30*time.Second, 10*time.Second) - -// initCallhome will start the callhome task in the background. -func initCallhome(ctx context.Context, objAPI ObjectLayer) { - if !globalCallhomeConfig.Enabled() { - return - } - - go func() { - r := rand.New(rand.NewSource(time.Now().UnixNano())) - // Leader node (that successfully acquires the lock inside runCallhome) - // will keep performing the callhome. If the leader goes down for some reason, - // the lock will be released and another node will acquire it and take over - // because of this loop. - for { - if !globalCallhomeConfig.Enabled() { - return - } - - if !runCallhome(ctx, objAPI) { - // callhome was disabled or context was canceled - return - } - - // callhome running on a different node. - // sleep for some time and try again. - duration := max(time.Duration(r.Float64()*float64(globalCallhomeConfig.FrequencyDur())), - // Make sure to sleep at least a second to avoid high CPU ticks. - time.Second) - time.Sleep(duration) - } - }() -} - -func runCallhome(ctx context.Context, objAPI ObjectLayer) bool { - // Make sure only 1 callhome is running on the cluster. - locker := objAPI.NewNSLock(minioMetaBucket, "callhome/runCallhome.lock") - lkctx, err := locker.GetLock(ctx, callhomeLeaderLockTimeout) - if err != nil { - // lock timedout means some other node is the leader, - // cycle back return 'true' - return true - } - - ctx = lkctx.Context() - defer locker.Unlock(lkctx) - - // Perform callhome once and then keep running it at regular intervals. - performCallhome(ctx) - - callhomeTimer := time.NewTimer(globalCallhomeConfig.FrequencyDur()) - defer callhomeTimer.Stop() - - for { - if !globalCallhomeConfig.Enabled() { - // Stop the processing as callhome got disabled - return false - } - - select { - case <-ctx.Done(): - // indicates that we do not need to run callhome anymore - return false - case <-callhomeTimer.C: - if !globalCallhomeConfig.Enabled() { - // Stop the processing as callhome got disabled - return false - } - - performCallhome(ctx) - - // Reset the timer for next cycle. - callhomeTimer.Reset(globalCallhomeConfig.FrequencyDur()) - } - } -} - -func performCallhome(ctx context.Context) { - deadline := 10 * time.Second // Default deadline is 10secs for callhome - objectAPI := newObjectLayerFn() - if objectAPI == nil { - internalLogIf(ctx, errors.New("Callhome: object layer not ready")) - return - } - - healthCtx, healthCancel := context.WithTimeout(ctx, deadline) - defer healthCancel() - - healthInfoCh := make(chan madmin.HealthInfo) - - query := url.Values{} - for _, k := range madmin.HealthDataTypesList { - query.Set(string(k), "true") - } - - healthInfo := madmin.HealthInfo{ - TimeStamp: time.Now().UTC(), - Version: madmin.HealthInfoVersion, - Minio: madmin.MinioHealthInfo{ - Info: madmin.MinioInfo{ - DeploymentID: globalDeploymentID(), - }, - }, - } - - go fetchHealthInfo(healthCtx, objectAPI, &query, healthInfoCh, healthInfo) - - for { - select { - case hi, hasMore := <-healthInfoCh: - if !hasMore { - auditOptions := AuditLogOptions{Event: "callhome:diagnostics"} - // Received all data. Send to SUBNET and return - err := sendHealthInfo(ctx, healthInfo) - if err != nil { - internalLogIf(ctx, fmt.Errorf("Unable to perform callhome: %w", err)) - auditOptions.Error = err.Error() - } - auditLogInternal(ctx, auditOptions) - return - } - healthInfo = hi - case <-healthCtx.Done(): - return - } - } -} - -const ( - subnetHealthPath = "/api/health/upload" -) - -func sendHealthInfo(ctx context.Context, healthInfo madmin.HealthInfo) error { - url := globalSubnetConfig.BaseURL + subnetHealthPath - - filename := fmt.Sprintf("health_%s.json.gz", UTCNow().Format("20060102150405")) - url += "?filename=" + filename - - _, err := globalSubnetConfig.Upload(url, filename, createHealthJSONGzip(ctx, healthInfo)) - return err -} - -func createHealthJSONGzip(ctx context.Context, healthInfo madmin.HealthInfo) []byte { - var b bytes.Buffer - gzWriter := gzip.NewWriter(&b) - - header := struct { - Version string `json:"version"` - }{Version: healthInfo.Version} - - enc := json.NewEncoder(gzWriter) - if e := enc.Encode(header); e != nil { - internalLogIf(ctx, fmt.Errorf("Could not encode health info header: %w", e)) - return nil - } - - if e := enc.Encode(healthInfo); e != nil { - internalLogIf(ctx, fmt.Errorf("Could not encode health info: %w", e)) - return nil - } - - gzWriter.Flush() - gzWriter.Close() - - return b.Bytes() -} diff --git a/cmd/common-main.go b/cmd/common-main.go index 598f1deb1..18aad7346 100644 --- a/cmd/common-main.go +++ b/cmd/common-main.go @@ -83,7 +83,7 @@ func init() { if mousetrap.StartedByExplorer() { fmt.Printf("Don't double-click %s\n", os.Args[0]) fmt.Println("You need to open cmd.exe/PowerShell and run it from the command line") - fmt.Println("Refer to the docs here on how to run it as a Windows Service https://github.com/minio/minio-service/tree/master/windows") + fmt.Println("See Silo deployment documentation: https://silo.pgsty.com/operations/deployments/") fmt.Println("Press the Enter Key to Exit") fmt.Scanln() os.Exit(1) @@ -295,42 +295,6 @@ func initConsoleServer() (*consoleapi.Server, error) { return server, nil } -// Check for updates and print a notification message -func checkUpdate(mode string) { - updateURL := minioReleaseInfoURL - if runtime.GOOS == globalWindowsOSName { - updateURL = minioReleaseWindowsInfoURL - } - - u, err := url.Parse(updateURL) - if err != nil { - return - } - - if currentReleaseTime.IsZero() { - return - } - - _, lrTime, err := getLatestReleaseTime(u, 2*time.Second, mode) - if err != nil { - return - } - - var older time.Duration - var downloadURL string - if lrTime.After(currentReleaseTime) { - older = lrTime.Sub(currentReleaseTime) - downloadURL = getDownloadURL(releaseTimeToReleaseTag(lrTime)) - } - - updateMsg := prepareUpdateMessage(downloadURL, older) - if updateMsg == "" { - return - } - - logger.Info(prepareUpdateMessage("Run `mc admin update ALIAS`", lrTime.Sub(currentReleaseTime))) -} - func newConfigDir(dir string, dirSet bool, getDefaultDir func() string) (*ConfigDir, error) { if dir == "" { dir = getDefaultDir() @@ -510,6 +474,16 @@ func handleCommonArgs(ctxt serverCtxt) { var err error globalConfigDir, err = newConfigDir(configDir, configSet, defaultConfigDir.Get) logger.FatalIf(err, "Unable to initialize the (deprecated) config directory") + if !configSet { + defaultConfigDirWarningOnce.Do(func() { + switch defaultConfigDirSelection { + case defaultConfigDirLegacy: + logger.Info("Using legacy MinIO configuration directory %s because %s does not exist; no files were moved", defaultConfigDir.Get(), filepath.Join(filepath.Dir(defaultConfigDir.Get()), defaultSiloConfigDir)) + case defaultConfigDirAmbiguous: + logger.Warning("Both Silo and legacy MinIO configuration directories exist; using %s. Set --config-dir explicitly before changing either directory", defaultConfigDir.Get()) + } + }) + } globalCertsDir, err = newConfigDir(certsDir, certsSet, defaultCertsDir.Get) logger.FatalIf(err, "Unable to initialize the certs directory") @@ -730,7 +704,7 @@ func serverHandleEnvVars() { } // Look for if URL has invalid values and return error. if !isValidURLEndpoint((*url.URL)(u)) { - err := fmt.Errorf("URL contains unexpected resources, expected URL to be one of http(s)://console.example.com or as a subpath via API endpoint http(s)://minio.example.com/minio format: %v", u) + err := fmt.Errorf("URL contains unexpected resources, expected URL to be one of http(s)://console.example.com or a /minio subpath on an API endpoint such as http(s)://silo.example.com/minio: %v", u) logger.Fatal(err, "Invalid MINIO_BROWSER_REDIRECT_URL value is environment variable") } globalBrowserRedirectURL = u @@ -745,7 +719,7 @@ func serverHandleEnvVars() { } // Look for if URL has invalid values and return error. if !isValidURLEndpoint((*url.URL)(u)) { - err := fmt.Errorf("URL contains unexpected resources, expected URL to be of http(s)://minio.example.com format: %v", u) + err := fmt.Errorf("URL contains unexpected resources, expected a URL such as http(s)://silo.example.com: %v", u) logger.Fatal(err, "Invalid MINIO_SERVER_URL value is environment variable") } u.Path = "" // remove any path component such as `/` @@ -798,7 +772,7 @@ func serverHandleEnvVars() { // Checking if the IP is a DNS entry. addrs, err := globalDNSCache.LookupHost(GlobalContext, endpoint) if err != nil { - logger.FatalIf(err, "Unable to initialize MinIO server with [%s] invalid entry found in MINIO_PUBLIC_IPS", endpoint) + logger.FatalIf(err, "Unable to initialize Silo server with [%s] invalid entry found in MINIO_PUBLIC_IPS", endpoint) } for _, addr := range addrs { domainIPs.Add(addr) @@ -817,10 +791,13 @@ func serverHandleEnvVars() { updateDomainIPs(domainIPs) } - // In place update is true by default if the MINIO_UPDATE is not set - // or is not set to 'off', if MINIO_UPDATE is set to 'off' then - // in-place update is off. - globalInplaceUpdateDisabled = strings.EqualFold(env.Get(config.EnvUpdate, config.EnableOn), config.EnableOff) + // MINIO_UPDATE remains accepted for configuration compatibility, but Silo is + // upgraded only through packages, images, or an orchestrator. It cannot + // re-enable the inherited in-place updater. + if updateSetting := env.Get(config.EnvUpdate, config.EnableOff); !strings.EqualFold(updateSetting, config.EnableOff) { + logger.Warning("%s=%s is ignored: Silo in-place updates are permanently disabled", config.EnvUpdate, updateSetting) + } + globalInplaceUpdateDisabled = true // Check if the supported credential env vars, // "MINIO_ROOT_USER" and "MINIO_ROOT_PASSWORD" are provided @@ -829,14 +806,14 @@ func serverHandleEnvVars() { // Check all error conditions first //nolint:gocritic if !env.IsSet(config.EnvRootUser) && env.IsSet(config.EnvRootPassword) { - logger.Fatal(config.ErrMissingEnvCredentialRootUser(nil), "Unable to start MinIO") + logger.Fatal(config.ErrMissingEnvCredentialRootUser(nil), "Unable to start Silo") } else if env.IsSet(config.EnvRootUser) && !env.IsSet(config.EnvRootPassword) { - logger.Fatal(config.ErrMissingEnvCredentialRootPassword(nil), "Unable to start MinIO") + logger.Fatal(config.ErrMissingEnvCredentialRootPassword(nil), "Unable to start Silo") } else if !env.IsSet(config.EnvRootUser) && !env.IsSet(config.EnvRootPassword) { if !env.IsSet(config.EnvAccessKey) && env.IsSet(config.EnvSecretKey) { - logger.Fatal(config.ErrMissingEnvCredentialAccessKey(nil), "Unable to start MinIO") + logger.Fatal(config.ErrMissingEnvCredentialAccessKey(nil), "Unable to start Silo") } else if env.IsSet(config.EnvAccessKey) && !env.IsSet(config.EnvSecretKey) { - logger.Fatal(config.ErrMissingEnvCredentialSecretKey(nil), "Unable to start MinIO") + logger.Fatal(config.ErrMissingEnvCredentialSecretKey(nil), "Unable to start Silo") } } diff --git a/cmd/config-current.go b/cmd/config-current.go index a87e2876a..9e17c0d78 100644 --- a/cmd/config-current.go +++ b/cmd/config-current.go @@ -92,13 +92,13 @@ func initHelp() { config.HelpKV{ Key: config.SubnetSubSys, Type: "string", - Description: "register Enterprise license for the cluster", + Description: "legacy MinIO SUBNET settings retained for compatibility; external integration is disabled in Silo", Optional: true, }, config.HelpKV{ Key: config.CallhomeSubSys, Type: "string", - Description: "enable callhome to MinIO SUBNET", + Description: "legacy callhome settings retained for compatibility; diagnostic uploads are disabled in Silo", Optional: true, }, config.HelpKV{ @@ -383,14 +383,9 @@ func validateSubSysConfig(ctx context.Context, s config.Config, subSys string, o return err } case config.CallhomeSubSys: - cfg, err := callhome.LookupConfig(s[config.CallhomeSubSys][config.Default]) - if err != nil { + if _, err := callhome.LookupConfig(s[config.CallhomeSubSys][config.Default]); err != nil { return err } - // callhome cannot be enabled if license is not registered yet, throw an error. - if cfg.Enabled() && !globalSubnetConfig.Registered() { - return errors.New("Deployment is not registered with SUBNET. Please register the deployment via 'mc license register ALIAS'") - } case config.DriveSubSys: if _, err := drive.LookupConfig(s[config.DriveSubSys][config.Default]); err != nil { return err @@ -676,11 +671,11 @@ func applyDynamicConfigForSubSys(ctx context.Context, objAPI ObjectLayer, s conf if err != nil { configLogIf(ctx, fmt.Errorf("Unable to load callhome config: %w", err)) } else { - enable := callhomeCfg.Enable && !globalCallhomeConfig.Enabled() - globalCallhomeConfig.Update(callhomeCfg) - if enable { - initCallhome(ctx, objAPI) + if callhomeCfg.Enable { + configLogIf(ctx, errors.New("callhome is configured but ignored: Silo does not upload diagnostics to MinIO SUBNET")) } + callhomeCfg.Enable = false + globalCallhomeConfig.Update(callhomeCfg) } case config.DriveSubSys: driveConfig, err := drive.LookupConfig(s[config.DriveSubSys][config.Default]) diff --git a/cmd/config-dir.go b/cmd/config-dir.go index b03b175b8..2f71b7409 100644 --- a/cmd/config-dir.go +++ b/cmd/config-dir.go @@ -20,13 +20,16 @@ package cmd import ( "os" "path/filepath" + "sync" homedir "github.com/mitchellh/go-homedir" ) const ( - // Default minio configuration directory where below configuration files/directories are stored. - defaultMinioConfigDir = ".minio" + // New installations use the Silo-branded directory. The legacy directory is + // still selected when it is the only existing choice. + defaultSiloConfigDir = ".silo" + legacyMinioConfigDir = ".minio" // Directory contains below files/directories for HTTPS configuration. certsDir = "certs" @@ -41,33 +44,56 @@ const ( privateKeyFile = "private.key" ) +type defaultConfigDirState uint8 + +const ( + defaultConfigDirNew defaultConfigDirState = iota + defaultConfigDirLegacy + defaultConfigDirAmbiguous +) + // ConfigDir - points to a user set directory. type ConfigDir struct { path string } -func getDefaultConfigDir() string { +func selectDefaultConfigDir(homeDir string) (string, defaultConfigDirState) { + siloDir := filepath.Join(homeDir, defaultSiloConfigDir) + minioDir := filepath.Join(homeDir, legacyMinioConfigDir) + _, siloErr := os.Stat(siloDir) + _, minioErr := os.Stat(minioDir) + + siloExists := siloErr == nil || !os.IsNotExist(siloErr) + minioExists := minioErr == nil || !os.IsNotExist(minioErr) + switch { + case siloExists && minioExists: + return siloDir, defaultConfigDirAmbiguous + case siloExists: + return siloDir, defaultConfigDirNew + case minioExists: + return minioDir, defaultConfigDirLegacy + default: + return siloDir, defaultConfigDirNew + } +} + +func getDefaultConfigDir() (string, defaultConfigDirState) { homeDir, err := homedir.Dir() if err != nil { - return "" + return "", defaultConfigDirNew } - return filepath.Join(homeDir, defaultMinioConfigDir) -} - -func getDefaultCertsDir() string { - return filepath.Join(getDefaultConfigDir(), certsDir) -} - -func getDefaultCertsCADir() string { - return filepath.Join(getDefaultCertsDir(), certsCADir) + return selectDefaultConfigDir(homeDir) } var ( + defaultConfigDirPath, defaultConfigDirSelection = getDefaultConfigDir() + defaultConfigDirWarningOnce sync.Once + // Default config, certs and CA directories. - defaultConfigDir = &ConfigDir{path: getDefaultConfigDir()} - defaultCertsDir = &ConfigDir{path: getDefaultCertsDir()} - defaultCertsCADir = &ConfigDir{path: getDefaultCertsCADir()} + defaultConfigDir = &ConfigDir{path: defaultConfigDirPath} + defaultCertsDir = &ConfigDir{path: filepath.Join(defaultConfigDirPath, certsDir)} + defaultCertsCADir = &ConfigDir{path: filepath.Join(defaultConfigDirPath, certsDir, certsCADir)} // Points to current configuration directory -- deprecated, to be removed in future. globalConfigDir = defaultConfigDir diff --git a/cmd/config-dir_test.go b/cmd/config-dir_test.go new file mode 100644 index 000000000..734419325 --- /dev/null +++ b/cmd/config-dir_test.go @@ -0,0 +1,53 @@ +// Copyright 2026 PGSTY contributors. +// +// 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. + +package cmd + +import ( + "os" + "path/filepath" + "testing" +) + +func TestSelectDefaultConfigDir(t *testing.T) { + tests := []struct { + name string + createSilo bool + createMinio bool + wantDir string + wantState defaultConfigDirState + }{ + {name: "new install", wantDir: defaultSiloConfigDir, wantState: defaultConfigDirNew}, + {name: "silo exists", createSilo: true, wantDir: defaultSiloConfigDir, wantState: defaultConfigDirNew}, + {name: "legacy only", createMinio: true, wantDir: legacyMinioConfigDir, wantState: defaultConfigDirLegacy}, + {name: "both exist", createSilo: true, createMinio: true, wantDir: defaultSiloConfigDir, wantState: defaultConfigDirAmbiguous}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + home := t.TempDir() + for name, create := range map[string]bool{ + defaultSiloConfigDir: tt.createSilo, + legacyMinioConfigDir: tt.createMinio, + } { + if create { + if err := os.Mkdir(filepath.Join(home, name), 0o700); err != nil { + t.Fatal(err) + } + } + } + + gotDir, gotState := selectDefaultConfigDir(home) + if want := filepath.Join(home, tt.wantDir); gotDir != want { + t.Fatalf("directory = %q, want %q", gotDir, want) + } + if gotState != tt.wantState { + t.Fatalf("state = %d, want %d", gotState, tt.wantState) + } + }) + } +} diff --git a/cmd/endpoint-ellipses.go b/cmd/endpoint-ellipses.go index f19249457..627eada09 100644 --- a/cmd/endpoint-ellipses.go +++ b/cmd/endpoint-ellipses.go @@ -33,7 +33,7 @@ import ( ) // This file implements and supports ellipses pattern for -// `minio server` command line arguments. +// `silo server` command line arguments. // Endpoint set represents parsed ellipses values, also provides // methods to get the sets of endpoints. diff --git a/cmd/endpoint.go b/cmd/endpoint.go index dcfe2e61b..56a791792 100644 --- a/cmd/endpoint.go +++ b/cmd/endpoint.go @@ -207,7 +207,7 @@ func NewEndpoint(arg string) (ep Endpoint, e error) { // On windows having a preceding SlashSeparator will cause problems, if the // command line already has C:/ 0 { console.Println() @@ -178,6 +178,7 @@ func newApp(name string) *cli.App { func startupBanner(banner io.Writer) { CopyrightYear = strconv.Itoa(time.Now().Year()) fmt.Fprintln(banner, color.Blue("Copyright:")+color.Bold(" 2015-%s MinIO, Inc.", CopyrightYear)) + fmt.Fprintln(banner, color.Blue("Modifications:")+color.Bold(" Copyright 2026 PGSTY contributors")) fmt.Fprintln(banner, color.Blue("License:")+color.Bold(" "+MinioLicense)) fmt.Fprintln(banner, color.Blue("Version:")+color.Bold(" %s (%s %s/%s)", ReleaseTag, runtime.Version(), runtime.GOOS, runtime.GOARCH)) } @@ -188,6 +189,8 @@ func versionBanner(c *cli.Context) io.Reader { fmt.Fprintln(banner, color.Blue("Runtime:")+color.Bold(" %s %s/%s", runtime.Version(), runtime.GOOS, runtime.GOARCH)) fmt.Fprintln(banner, color.Blue("License:")+color.Bold(" GNU AGPLv3 - https://www.gnu.org/licenses/agpl-3.0.html")) fmt.Fprintln(banner, color.Blue("Copyright:")+color.Bold(" 2015-%s MinIO, Inc.", CopyrightYear)) + fmt.Fprintln(banner, color.Blue("Modifications:")+color.Bold(" Copyright 2026 PGSTY contributors")) + fmt.Fprintln(banner, color.Blue("Source compatibility:")+color.Bold(" based on MinIO technology")) return strings.NewReader(banner.String()) } @@ -197,7 +200,7 @@ func printMinIOVersion(c *cli.Context) { var debugNoExit = env.Get("_MINIO_DEBUG_NO_EXIT", "") != "" -// Main main for minio server. +// Main is the Silo server entry point. func Main(args []string) { // Set the minio app name. appName := filepath.Base(args[0]) diff --git a/cmd/peer-rest-server.go b/cmd/peer-rest-server.go index 9335b7613..6062369db 100644 --- a/cmd/peer-rest-server.go +++ b/cmd/peer-rest-server.go @@ -610,6 +610,10 @@ func (s *peerRESTServer) VerifyBinaryHandler(w http.ResponseWriter, r *http.Requ s.writeErrorResponse(w, errors.New("Invalid request")) return } + if globalInplaceUpdateDisabled { + s.writeErrorResponse(w, errInplaceUpdateDisabled) + return + } if r.ContentLength < 0 { s.writeErrorResponse(w, errInvalidArgument) @@ -659,6 +663,10 @@ func (s *peerRESTServer) CommitBinaryHandler(w http.ResponseWriter, r *http.Requ s.writeErrorResponse(w, errors.New("Invalid request")) return } + if globalInplaceUpdateDisabled { + s.writeErrorResponse(w, errInplaceUpdateDisabled) + return + } if err := commitBinary(); err != nil { s.writeErrorResponse(w, err) diff --git a/cmd/prepare-storage.go b/cmd/prepare-storage.go index 578a5fade..63a4621b1 100644 --- a/cmd/prepare-storage.go +++ b/cmd/prepare-storage.go @@ -81,7 +81,7 @@ func bgFormatErasureCleanupTmp(diskPath string) { // |__ e870a2c1-d09c-450c-a69c-6eaa54a89b3e // // In this example, `33a58b40-aecc-4c9f-a22f-ff17bfa33b62` directory contains - // temporary objects from one of the previous runs of minio server. + // temporary objects from one of the previous runs of Silo. tmpID := mustGetUUID() tmpOld := pathJoin(diskPath, minioMetaTmpBucket+"-old", tmpID) if err := renameAll(pathJoin(diskPath, minioMetaTmpBucket), @@ -263,7 +263,7 @@ func waitForFormatErasure(firstDisk bool, endpoints Endpoints, poolCount, setCou defer func() { if err == nil && format != nil { // Assign globalDeploymentID() on first run for the - // minio server managing the first disk + // Silo server managing the first disk globalDeploymentIDPtr.Store(&format.ID) // Set the deployment ID here to avoid races. diff --git a/cmd/server-main.go b/cmd/server-main.go index ade86cca1..a547581f7 100644 --- a/cmd/server-main.go +++ b/cmd/server-main.go @@ -114,7 +114,7 @@ var ServerFlags = []cli.Flag{ }, cli.StringFlag{ Name: "interface", - Usage: "bind to right VRF device for MinIO services", + Usage: "bind to the VRF device used by Silo services", Hidden: true, EnvVar: "MINIO_INTERFACE", }, @@ -220,20 +220,20 @@ FLAGS: {{range .VisibleFlags}}{{.}} {{end}}{{end}} EXAMPLES: - 1. Start MinIO server on "/home/shared" directory. + 1. Start Silo server on "/home/shared" directory. {{.Prompt}} {{.HelpName}} /home/shared 2. Start single node server with 64 local drives "/mnt/data1" to "/mnt/data64". {{.Prompt}} {{.HelpName}} /mnt/data{1...64} - 3. Start distributed MinIO server on an 32 node setup with 32 drives each, run following command on all the nodes + 3. Start distributed Silo server on a 32-node setup with 32 drives each; run the following command on all nodes. {{.Prompt}} {{.HelpName}} http://node{1...32}.example.com/mnt/export{1...32} - 4. Start distributed MinIO server in an expanded setup, run the following command on all the nodes + 4. Start distributed Silo server in an expanded setup; run the following command on all nodes. {{.Prompt}} {{.HelpName}} http://node{1...16}.example.com/mnt/export{1...32} \ http://node{17...64}.example.com/mnt/export{1...64} - 5. Start distributed MinIO server, with FTP and SFTP servers on all interfaces via port 8021, 8022 respectively + 5. Start distributed Silo server with FTP and SFTP on ports 8021 and 8022. {{.Prompt}} {{.HelpName}} http://node{1...4}.example.com/mnt/export{1...4} \ --ftp="address=:8021" --ftp="passive-port-range=30000-40000" \ --sftp="address=:8022" --sftp="ssh-private-key=${HOME}/.ssh/id_rsa" @@ -597,7 +597,7 @@ func initServerConfig(ctx context.Context, newObject ObjectLayer) error { // These messages only meant primarily for distributed setup, so only log during distributed setup. if globalIsDistErasure { - logger.Info("Waiting for all MinIO sub-systems to be initialize...") + logger.Info("Waiting for all Silo subsystems to initialize...") } // Upon success migrating the config, initialize all sub-systems @@ -607,13 +607,13 @@ func initServerConfig(ctx context.Context, newObject ObjectLayer) error { // All successful return. if globalIsDistErasure { // These messages only meant primarily for distributed setup, so only log during distributed setup. - logger.Info("All MinIO sub-systems initialized successfully in %s", time.Since(t1)) + logger.Info("All Silo subsystems initialized successfully in %s", time.Since(t1)) } return nil } if configRetriableErrors(err) { - logger.Info("Waiting for all MinIO sub-systems to be initialized.. possible cause (%v)", err) + logger.Info("Waiting for all Silo subsystems to initialize; possible cause: %v", err) time.Sleep(time.Duration(r.Float64() * float64(5*time.Second))) continue } @@ -742,7 +742,7 @@ func initializeLogRotate(ctx *cli.Context) (io.WriteCloser, error) { return output, nil } -// serverMain handler called for 'minio server' command. +// serverMain handles the 'silo server' command. func serverMain(ctx *cli.Context) { r := rand.New(rand.NewSource(time.Now().UnixNano())) @@ -851,16 +851,6 @@ func serverMain(ctx *cli.Context) { getCert = globalTLSCerts.GetCertificate } - // Check for updates in non-blocking manner. - go func() { - if !globalServerCtxt.Quiet && !globalInplaceUpdateDisabled { - // Check for new updates from dl.min.io. - bootstrapTrace("checkUpdate", func() { - checkUpdate(getMinioMode()) - }) - } - }() - // Set system resources to maximum. bootstrapTrace("setMaxResources", func() { _ = setMaxResources(globalServerCtxt) @@ -868,13 +858,13 @@ func serverMain(ctx *cli.Context) { // Verify kernel release and version. if oldLinux() { - warnings = append(warnings, color.YellowBold("Detected Linux kernel version older than 4.0 release, there are some known potential performance problems with this kernel version. MinIO recommends a minimum of 4.x linux kernel version for best performance")) + warnings = append(warnings, color.YellowBold("Detected a Linux kernel older than 4.0; Silo recommends kernel 4.x or newer to avoid known performance problems")) } maxProcs := runtime.GOMAXPROCS(0) cpuProcs := runtime.NumCPU() if maxProcs < cpuProcs { - warnings = append(warnings, color.YellowBold("Detected GOMAXPROCS(%d) < NumCPU(%d), please make sure to provide all PROCS to MinIO for optimal performance", + warnings = append(warnings, color.YellowBold("Detected GOMAXPROCS(%d) < NumCPU(%d); provide all processors to Silo for optimal performance", maxProcs, cpuProcs)) } @@ -1161,7 +1151,7 @@ func serverMain(ctx *cli.Context) { Transport: globalRemoteTargetTransport, Region: region, }) - logger.FatalIf(err, "Unable to initialize MinIO client") + logger.FatalIf(err, "Unable to initialize the internal S3 client") }) go bootstrapTrace("startResourceMetricsCollection", func() { @@ -1169,7 +1159,7 @@ func serverMain(ctx *cli.Context) { }) // Add User-Agent to differentiate the requests. - globalMinioClient.SetAppInfo("minio-perf-test", ReleaseTag) + globalMinioClient.SetAppInfo("silo-perf-test", ReleaseTag) if serverDebugLog { fmt.Println("== DEBUG Mode enabled ==") diff --git a/cmd/server-startup-msg.go b/cmd/server-startup-msg.go index 1d3a6579b..51bece519 100644 --- a/cmd/server-startup-msg.go +++ b/cmd/server-startup-msg.go @@ -61,7 +61,7 @@ func printStartupMessage(apiEndpoints []string, err error) { // Prints `mc` cli configuration message chooses // first endpoint as default. - printCLIAccessMsg(strippedAPIEndpoints[0], "myminio") + printCLIAccessMsg(strippedAPIEndpoints[0], "mysilo") // Prints documentation message. printObjectAPIMsg() @@ -186,7 +186,7 @@ func printCLIAccessMsg(endPoint string, alias string) { const mcQuickStartGuide = "https://silo.pgsty.com/reference/minio-mc/#quickstart" - // Configure 'mc', following block prints platform specific information for minio client. + // Configure mc and print platform-specific connection information. if color.IsTerminal() && (!globalServerCtxt.Anonymous && globalAPIConfig.permitRootAccess()) { logger.Startup(color.Blue("\nCLI: ") + mcQuickStartGuide) mcMessage := fmt.Sprintf("$ mc alias set '%s' '%s' '%s' '%s'", alias, diff --git a/cmd/server-startup-msg_test.go b/cmd/server-startup-msg_test.go index 08b451827..8e175bc99 100644 --- a/cmd/server-startup-msg_test.go +++ b/cmd/server-startup-msg_test.go @@ -80,7 +80,7 @@ func TestPrintCLIAccessMsg(t *testing.T) { } apiEndpoints := []string{"http://127.0.0.1:9000"} - printCLIAccessMsg(apiEndpoints[0], "myminio") + printCLIAccessMsg(apiEndpoints[0], "mysilo") } // Test print startup message. diff --git a/cmd/storage-errors.go b/cmd/storage-errors.go index b39d7c8ae..b57266bd4 100644 --- a/cmd/storage-errors.go +++ b/cmd/storage-errors.go @@ -26,7 +26,7 @@ import ( var errMaxVersionsExceeded = StorageErr("maximum versions exceeded, please delete few versions to proceed") // errUnexpected - unexpected error, requires manual intervention. -var errUnexpected = StorageErr("unexpected error, please report this issue at https://github.com/minio/minio/issues") +var errUnexpected = StorageErr("unexpected error, please report this issue at https://github.com/pgsty/minio/issues") // errCorruptedFormat - corrupted format. var errCorruptedFormat = StorageErr("corrupted format") diff --git a/cmd/storage-rest-server.go b/cmd/storage-rest-server.go index 5d2a18ed8..803c24a4e 100644 --- a/cmd/storage-rest-server.go +++ b/cmd/storage-rest-server.go @@ -1112,17 +1112,17 @@ func logFatalErrs(err error, endpoint Endpoint, exit bool) { case errors.Is(err, errUnsupportedDisk): var hint string if endpoint.URL != nil { - hint = fmt.Sprintf("Drive '%s' does not support O_DIRECT flags, MinIO erasure coding requires filesystems with O_DIRECT support", endpoint.Path) + hint = fmt.Sprintf("Drive '%s' does not support O_DIRECT flags, Silo erasure coding requires filesystems with O_DIRECT support", endpoint.Path) } else { - hint = "Drives do not support O_DIRECT flags, MinIO erasure coding requires filesystems with O_DIRECT support" + hint = "Drives do not support O_DIRECT flags, Silo erasure coding requires filesystems with O_DIRECT support" } logger.Fatal(config.ErrUnsupportedBackend(err).Hint("%s", hint), "Unable to initialize backend") case errors.Is(err, errDiskNotDir): var hint string if endpoint.URL != nil { - hint = fmt.Sprintf("Drive '%s' is not a directory, MinIO erasure coding needs a directory", endpoint.Path) + hint = fmt.Sprintf("Drive '%s' is not a directory, Silo erasure coding needs a directory", endpoint.Path) } else { - hint = "Drives are not directories, MinIO erasure coding needs directories" + hint = "Drives are not directories, Silo erasure coding needs directories" } logger.Fatal(config.ErrUnableToWriteInBackend(err).Hint("%s", hint), "Unable to initialize backend") case errors.Is(err, errDiskAccessDenied): diff --git a/cmd/sts-errors.go b/cmd/sts-errors.go index c68b68f1d..a06d031b8 100644 --- a/cmd/sts-errors.go +++ b/cmd/sts-errors.go @@ -128,7 +128,7 @@ var stsErrCodes = stsErrorCodeMap{ }, ErrSTSInvalidClientGrantsToken: { Code: "InvalidClientGrantsToken", - Description: "The client grants token that was passed could not be validated by MinIO.", + Description: "The client grants token that was passed could not be validated by Silo.", HTTPStatusCode: http.StatusBadRequest, }, ErrSTSMalformedPolicyDocument: { diff --git a/cmd/update-notifier.go b/cmd/update-notifier.go index 20c169f9b..19ff5489a 100644 --- a/cmd/update-notifier.go +++ b/cmd/update-notifier.go @@ -41,7 +41,7 @@ func prepareUpdateMessage(downloadURL string, older time.Duration) string { newerThan := humanize.RelTime(t, t.Add(older), "before the latest release", "") if globalServerCtxt.JSON { - return fmt.Sprintf("You are running an older version of MinIO released %s, update: %s", newerThan, downloadURL) + return fmt.Sprintf("You are running an older version of Silo released %s, update: %s", newerThan, downloadURL) } // Return the nicely colored and formatted update message. @@ -50,7 +50,7 @@ func prepareUpdateMessage(downloadURL string, older time.Duration) string { // colorizeUpdateMessage - inspired from Yeoman project npm package https://github.com/yeoman/update-notifier func colorizeUpdateMessage(updateString string, newerThan string) string { - msgLine1Fmt := " You are running an older version of MinIO released %s " + msgLine1Fmt := " You are running an older version of Silo released %s " msgLine2Fmt := " Update: %s " // Calculate length *without* color coding: with ANSI terminal diff --git a/cmd/update-notifier_test.go b/cmd/update-notifier_test.go index 64083356f..e89193396 100644 --- a/cmd/update-notifier_test.go +++ b/cmd/update-notifier_test.go @@ -67,7 +67,7 @@ func TestPrepareUpdateMessage(t *testing.T) { {2 * 365 * 24 * time.Hour, "my_download_url", "2 years before the latest release"}, } - plainMsg := "You are running an older version of MinIO released" + plainMsg := "You are running an older version of Silo released" for i, testCase := range testCases { output := prepareUpdateMessage(testCase.dlURL, testCase.older) diff --git a/cmd/update.go b/cmd/update.go index 26f93f370..e35d8dd1d 100644 --- a/cmd/update.go +++ b/cmd/update.go @@ -51,6 +51,8 @@ const ( ) var ( + errInplaceUpdateDisabled = errors.New("Silo in-place updates are disabled; use a package, image, or orchestrator upgrade") + // Newer official download info URLs appear earlier below. minioReleaseInfoURL = MinioReleaseURL + "minio.sha256sum" @@ -223,13 +225,10 @@ func IsPCFTile() bool { return env.Get("MINIO_PCF_TILE_VERSION", "") != "" } -// DO NOT CHANGE USER AGENT STYLE. -// The style should be +// Keep the inherited user agent field order stable while identifying Silo as +// the maintained product. The style is: // -// MinIO (; [; ][; dcos][; kubernetes][; docker][; source]) MinIO/ MinIO/ MinIO/ [MinIO/universe-] [MinIO/helm-] -// -// Any change here should be discussed by opening an issue at -// https://github.com/minio/minio/issues. +// Silo (; [; ][; dcos][; kubernetes][; docker][; source]) [universe-] [helm-] func getUserAgent(mode string) string { userAgentParts := []string{} // Helper function to concisely append a pair of strings to a @@ -438,22 +437,14 @@ func getUpdateTransport(timeout time.Duration) http.RoundTripper { return updateTransport } -func getLatestReleaseTime(u *url.URL, timeout time.Duration, mode string) (sha256Sum []byte, releaseTime time.Time, err error) { - data, err := downloadReleaseURL(u, timeout, mode) - if err != nil { - return sha256Sum, releaseTime, err - } - - sha256Sum, releaseTime, _, err = parseReleaseData(data) - return sha256Sum, releaseTime, err -} - const ( // Kubernetes deployment doc link. kubernetesDeploymentDoc = "https://silo.pgsty.com/operations/deployments/kubernetes/" // Mesos deployment doc link. mesosDeploymentDoc = "https://silo.pgsty.com/operations/deployments/kubernetes/" + + siloDownloadPage = "https://silo.pgsty.com/download/" ) func getDownloadURL(releaseTag string) (downloadURL string) { @@ -472,15 +463,11 @@ func getDownloadURL(releaseTag string) (downloadURL string) { // Check if we are docker environment, return docker update command if IsDocker() { // Construct release tag name. - return fmt.Sprintf("podman pull quay.io/minio/minio:%s", releaseTag) + return fmt.Sprintf("podman pull docker.io/pgsty/silo:%s", releaseTag) } - // For binary only installations, we return link to the latest binary. - if runtime.GOOS == "windows" { - return MinioReleaseURL + "minio.exe" - } - - return MinioReleaseURL + "minio" + // Binary installations are upgraded from a verified release artifact. + return siloDownloadPage } func getUpdateReaderFromURL(u *url.URL, transport http.RoundTripper, mode string) (io.ReadCloser, error) { @@ -551,11 +538,15 @@ func downloadBinary(u *url.URL, mode string) (binCompressed []byte, bin []byte, } const ( - // Update this whenever the official minisign pubkey is rotated. - defaultMinisignPubkey = "RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav" + // Silo has no in-place update trust root. The environment key remains + // recognized by inherited code but cannot re-enable the disabled updater. + defaultMinisignPubkey = "" ) func verifyBinary(u *url.URL, sha256Sum []byte, releaseInfo, mode string, reader io.Reader) (err error) { + if globalInplaceUpdateDisabled { + return errInplaceUpdateDisabled + } if !updateInProgress.CompareAndSwap(0, 1) { return errors.New("update already in progress") } @@ -610,6 +601,9 @@ func verifyBinary(u *url.URL, sha256Sum []byte, releaseInfo, mode string, reader } func commitBinary() (err error) { + if globalInplaceUpdateDisabled { + return errInplaceUpdateDisabled + } if !updateInProgress.CompareAndSwap(0, 1) { return errors.New("update already in progress") } diff --git a/cmd/update_test.go b/cmd/update_test.go index e94e049ea..234903c78 100644 --- a/cmd/update_test.go +++ b/cmd/update_test.go @@ -20,6 +20,7 @@ package cmd import ( "bytes" "encoding/hex" + "errors" "fmt" "net/http" "net/http/httptest" @@ -35,6 +36,9 @@ import ( ) func TestDownloadBinaryReturnsOwnedBuffers(t *testing.T) { + previousDisabled := globalInplaceUpdateDisabled + globalInplaceUpdateDisabled = false + t.Cleanup(func() { globalInplaceUpdateDisabled = previousDisabled }) previousMaxProcs := runtime.GOMAXPROCS(1) t.Cleanup(func() { runtime.GOMAXPROCS(previousMaxProcs) @@ -96,6 +100,19 @@ func TestDownloadBinaryReturnsOwnedBuffers(t *testing.T) { } } +func TestInplaceUpdateCannotBeEnabled(t *testing.T) { + previousDisabled := globalInplaceUpdateDisabled + globalInplaceUpdateDisabled = true + t.Cleanup(func() { globalInplaceUpdateDisabled = previousDisabled }) + + if err := verifyBinary(nil, nil, "", "", nil); !errors.Is(err, errInplaceUpdateDisabled) { + t.Fatalf("verifyBinary error = %v, want %v", err, errInplaceUpdateDisabled) + } + if err := commitBinary(); !errors.Is(err, errInplaceUpdateDisabled) { + t.Fatalf("commitBinary error = %v, want %v", err, errInplaceUpdateDisabled) + } +} + func TestMinioVersionToReleaseTime(t *testing.T) { testCases := []struct { version string @@ -167,19 +184,11 @@ func TestDownloadURL(t *testing.T) { minioVersion1 := releaseTimeToReleaseTag(UTCNow()) durl := getDownloadURL(minioVersion1) if IsDocker() { - if durl != "podman pull quay.io/minio/minio:"+minioVersion1 { - t.Errorf("Expected %s, got %s", "podman pull quay.io/minio/minio:"+minioVersion1, durl) - } - } else { - if runtime.GOOS == "windows" { - if durl != MinioReleaseURL+"minio.exe" { - t.Errorf("Expected %s, got %s", MinioReleaseURL+"minio.exe", durl) - } - } else { - if durl != MinioReleaseURL+"minio" { - t.Errorf("Expected %s, got %s", MinioReleaseURL+"minio", durl) - } + if durl != "podman pull docker.io/pgsty/silo:"+minioVersion1 { + t.Errorf("Expected %s, got %s", "podman pull docker.io/pgsty/silo:"+minioVersion1, durl) } + } else if durl != siloDownloadPage { + t.Errorf("Expected %s, got %s", siloDownloadPage, durl) } t.Setenv("KUBERNETES_SERVICE_HOST", "10.11.148.5") @@ -207,19 +216,19 @@ func TestUserAgent(t *testing.T) { envName: "", envValue: "", mode: globalMinioModeFS, - expectedStr: fmt.Sprintf("MinIO (%s; %s; %s; source DEVELOPMENT.GOGET DEVELOPMENT.GOGET DEVELOPMENT.GOGET", runtime.GOOS, runtime.GOARCH, globalMinioModeFS), + expectedStr: fmt.Sprintf("Silo (%s; %s; %s; source DEVELOPMENT.GOGET DEVELOPMENT.GOGET DEVELOPMENT.GOGET", runtime.GOOS, runtime.GOARCH, globalMinioModeFS), }, { envName: "MESOS_CONTAINER_NAME", envValue: "mesos-11111", mode: globalMinioModeErasure, - expectedStr: fmt.Sprintf("MinIO (%s; %s; %s; %s; source DEVELOPMENT.GOGET DEVELOPMENT.GOGET DEVELOPMENT.GOGET universe-%s", runtime.GOOS, runtime.GOARCH, globalMinioModeErasure, "dcos", "mesos-1111"), + expectedStr: fmt.Sprintf("Silo (%s; %s; %s; %s; source DEVELOPMENT.GOGET DEVELOPMENT.GOGET DEVELOPMENT.GOGET universe-%s", runtime.GOOS, runtime.GOARCH, globalMinioModeErasure, "dcos", "mesos-1111"), }, { envName: "KUBERNETES_SERVICE_HOST", envValue: "10.11.148.5", mode: globalMinioModeErasure, - expectedStr: fmt.Sprintf("MinIO (%s; %s; %s; %s; source DEVELOPMENT.GOGET DEVELOPMENT.GOGET DEVELOPMENT.GOGET", runtime.GOOS, runtime.GOARCH, globalMinioModeErasure, "kubernetes"), + expectedStr: fmt.Sprintf("Silo (%s; %s; %s; %s; source DEVELOPMENT.GOGET DEVELOPMENT.GOGET DEVELOPMENT.GOGET", runtime.GOOS, runtime.GOARCH, globalMinioModeErasure, "kubernetes"), }, } diff --git a/cmd/veeam-sos-api.go b/cmd/veeam-sos-api.go index 33ff9e132..03523e8e1 100644 --- a/cmd/veeam-sos-api.go +++ b/cmd/veeam-sos-api.go @@ -156,11 +156,11 @@ func veeamSOSAPIGetObject(ctx context.Context, bucket, object string, rs *HTTPRa case systemXMLObject: si := systemInfo{ ProtocolVersion: `"1.0"`, - ModelName: "\"MinIO " + ReleaseTag + "\"", + ModelName: "\"Silo " + ReleaseTag + "\"", } si.ProtocolCapabilities.CapacityInfo = true - // Default recommended block size with MinIO + // Default recommended block size with Silo. si.SystemRecommendations.KBBlockSize = 4096 buf = encodeResponse(&si) diff --git a/cmd/warm-backend.go b/cmd/warm-backend.go index 91a936004..53ea514e0 100644 --- a/cmd/warm-backend.go +++ b/cmd/warm-backend.go @@ -49,7 +49,7 @@ const probeObject = "probeobject" // checkWarmBackend checks if tier config credentials have sufficient privileges // to perform all operations defined in the WarmBackend interface. func checkWarmBackend(ctx context.Context, w WarmBackend) error { - remoteVersionID, err := w.Put(ctx, probeObject, strings.NewReader("MinIO"), 5) + remoteVersionID, err := w.Put(ctx, probeObject, strings.NewReader("Silo!"), 5) if err != nil { if _, ok := err.(BackendDown); ok { return err diff --git a/internal/config/callhome/help.go b/internal/config/callhome/help.go index 8def3fa5b..75d083984 100644 --- a/internal/config/callhome/help.go +++ b/internal/config/callhome/help.go @@ -29,7 +29,7 @@ var ( config.HelpKV{ Key: Enable, Type: "on|off", - Description: "set to enable callhome" + defaultHelpPostfix(Enable), + Description: "legacy callhome setting; retained for compatibility but unsupported by Silo" + defaultHelpPostfix(Enable), Optional: true, }, config.HelpKV{ diff --git a/internal/config/errors.go b/internal/config/errors.go index f43a01370..845249969 100644 --- a/internal/config/errors.go +++ b/internal/config/errors.go @@ -21,8 +21,8 @@ package config var ( ErrInvalidXLValue = newErrFn( "Invalid drive path", - "Please provide a fresh drive for single drive MinIO setup", - "MinIO only supports fresh drive paths", + "Please provide a fresh drive for a single-drive Silo setup", + "Silo only supports fresh drive paths", ) ErrInvalidBrowserValue = newErrFn( @@ -118,14 +118,14 @@ var ( ErrStorageClassValue = newErrFn( "Invalid storage class value", "Please check the value", - `MINIO_STORAGE_CLASS_STANDARD: Format "EC:" (e.g. "EC:3"). This sets the number of parity drives for MinIO server in Standard mode. Objects are stored in Standard mode, if storage class is not defined in Put request -MINIO_STORAGE_CLASS_RRS: Format "EC:" (e.g. "EC:3"). This sets the number of parity drives for MinIO server in Reduced Redundancy mode. Objects are stored in Reduced Redundancy mode, if Put request specifies RRS storage class -Refer to the link https://github.com/minio/minio/tree/master/docs/erasure/storage-class for more information`, + `MINIO_STORAGE_CLASS_STANDARD: Format "EC:" (e.g. "EC:3"). This sets the number of parity drives for Silo in Standard mode. Objects are stored in Standard mode if no storage class is defined in the Put request. +MINIO_STORAGE_CLASS_RRS: Format "EC:" (e.g. "EC:3"). This sets the number of parity drives for Silo in Reduced Redundancy mode. Objects are stored in Reduced Redundancy mode if the Put request specifies the RRS storage class. +See https://silo.pgsty.com/operations/concepts/erasure-coding/ for more information.`, ) ErrUnexpectedBackendVersion = newErrFn( "Backend version seems to be too recent", - "Please update to the latest MinIO version", + "Please update to the latest Silo version", "", ) @@ -143,8 +143,8 @@ Refer to the link https://github.com/minio/minio/tree/master/docs/erasure/storag "Please check the endpoint", `Single-Node modes requires absolute path without hostnames: Examples: - $ minio server /data/minio/ #Single Node Single Drive - $ minio server /data-{1...4}/minio # Single Node Multi Drive`, + $ silo server /data/silo/ # Single Node Single Drive + $ silo server /data-{1...4}/silo # Single Node Multi Drive`, ) ErrUnsupportedBackend = newErrFn( @@ -155,8 +155,8 @@ Examples: ErrUnableToWriteInBackend = newErrFn( "Unable to write to the backend", - "Please ensure MinIO binary has write permissions for the backend", - `Verify if MinIO binary is running as the same user who has write permissions for the backend`, + "Please ensure the Silo binary has write permissions for the backend", + `Verify that the Silo binary is running as the same user who has write permissions for the backend`, ) ErrPortAlreadyInUse = newErrFn( @@ -167,8 +167,8 @@ Examples: ErrPortAccess = newErrFn( "Unable to use specified port", - "Please ensure MinIO binary has 'cap_net_bind_service=+ep' permissions", - `Use 'sudo setcap cap_net_bind_service=+ep /path/to/minio' to provide sufficient permissions`, + "Please ensure the Silo binary has 'cap_net_bind_service=+ep' permissions", + `Use 'sudo setcap cap_net_bind_service=+ep /path/to/silo' to provide sufficient permissions`, ) ErrTLSReadError = newErrFn( @@ -209,7 +209,7 @@ Examples: ErrUnexpectedError = newErrFn( "Unexpected error", - "Please contact MinIO at https://slack.min.io", + "Please report this Silo error at https://github.com/pgsty/minio/issues", "", ) diff --git a/internal/config/identity/openid/help.go b/internal/config/identity/openid/help.go index 1469034c5..2ca96411a 100644 --- a/internal/config/identity/openid/help.go +++ b/internal/config/identity/openid/help.go @@ -69,7 +69,7 @@ var ( }, config.HelpKV{ Key: Vendor, - Description: `Specify vendor type for vendor specific behavior to checking validity of temporary credentials and service accounts on MinIO` + defaultHelpPostfix(Vendor), + Description: `Specify vendor type for vendor-specific behavior when checking temporary credentials and service accounts on Silo` + defaultHelpPostfix(Vendor), Optional: true, Type: "string", }, diff --git a/internal/config/subnet/config.go b/internal/config/subnet/config.go index 9e2420a64..3665add3a 100644 --- a/internal/config/subnet/config.go +++ b/internal/config/subnet/config.go @@ -29,11 +29,6 @@ import ( xnet "github.com/minio/pkg/v3/net" ) -const ( - baseURL = "https://subnet.min.io" - baseURLDev = "http://localhost:9000" -) - // DefaultKVS - default KV config for subnet settings var DefaultKVS = config.KVS{ config.KV{ @@ -70,29 +65,21 @@ type Config struct { var configLock sync.RWMutex -// Registered indicates if cluster is registered or not +// Registered reports false because Silo does not use MinIO SUBNET. The +// inherited credentials remain parseable for configuration compatibility. func (c *Config) Registered() bool { - configLock.RLock() - defer configLock.RUnlock() - - return len(c.APIKey) > 0 + return false } // ApplyEnv - applies the current subnet config to Console UI specific environment variables. func (c *Config) ApplyEnv() { - configLock.RLock() - defer configLock.RUnlock() - - if c.License != "" { - os.Setenv("CONSOLE_SUBNET_LICENSE", c.License) - } - if c.APIKey != "" { - os.Setenv("CONSOLE_SUBNET_API_KEY", c.APIKey) - } - if c.Proxy != "" { - os.Setenv("CONSOLE_SUBNET_PROXY", c.Proxy) - } - os.Setenv("CONSOLE_SUBNET_URL", c.BaseURL) + // Do not expose inherited commercial-service credentials or an endpoint to + // the embedded Console. These names are outputs, not the MINIO_* input + // compatibility surface. + os.Unsetenv("CONSOLE_SUBNET_LICENSE") + os.Unsetenv("CONSOLE_SUBNET_API_KEY") + os.Unsetenv("CONSOLE_SUBNET_PROXY") + os.Unsetenv("CONSOLE_SUBNET_URL") } // Update - in-place update with new license and registration information. @@ -103,15 +90,12 @@ func (c *Config) Update(ncfg Config, isDevEnv bool) { c.License = ncfg.License c.APIKey = ncfg.APIKey c.Proxy = ncfg.Proxy - c.transport = ncfg.transport - c.BaseURL = baseURL + c.transport = nil + c.BaseURL = "" - if isDevEnv { - c.BaseURL = os.Getenv("_MINIO_SUBNET_URL") - if c.BaseURL == "" { - c.BaseURL = baseURLDev - } - } + // Retain the hidden compatibility input but deliberately ignore its value. + _ = os.Getenv("_MINIO_SUBNET_URL") + _ = isDevEnv } // LookupConfig - lookup config and override with valid environment settings if any. diff --git a/internal/config/subnet/subnet.go b/internal/config/subnet/subnet.go index c4ba01982..5e069907f 100644 --- a/internal/config/subnet/subnet.go +++ b/internal/config/subnet/subnet.go @@ -18,97 +18,27 @@ package subnet import ( - "bytes" - "encoding/json" "errors" - "fmt" - "io" - "mime/multipart" "net/http" - "time" - - xhttp "github.com/minio/minio/internal/http" ) const ( - respBodyLimit = 1 << 20 // 1 MiB - // LoggerWebhookName - subnet logger webhook target LoggerWebhookName = "subnet" ) +var errSiloSubnetDisabled = errors.New("MinIO SUBNET integration is disabled in Silo") + // Upload given file content (payload) to specified URL func (c Config) Upload(reqURL string, filename string, payload []byte) (string, error) { - if !c.Registered() { - return "", errors.New("Deployment is not registered with SUBNET. Please register the deployment via 'mc license register ALIAS'") - } - - var body bytes.Buffer - writer := multipart.NewWriter(&body) - part, e := writer.CreateFormFile("file", filename) - if e != nil { - return "", e - } - - if _, e = part.Write(payload); e != nil { - return "", e - } - writer.Close() - - r, e := http.NewRequest(http.MethodPost, reqURL, &body) - if e != nil { - return "", e - } - r.Header.Add("Content-Type", writer.FormDataContentType()) - - return c.submitPost(r) + return "", errSiloSubnetDisabled } -func (c Config) submitPost(r *http.Request) (string, error) { - configLock.RLock() - r.Header.Set(xhttp.SubnetAPIKey, c.APIKey) - configLock.RUnlock() - r.Header.Set(xhttp.MinioDeploymentID, xhttp.GlobalDeploymentID) - - client := &http.Client{ - Timeout: 10 * time.Second, - Transport: c.transport, - } - - resp, err := client.Do(r) - if err != nil { - return "", err - } - defer xhttp.DrainBody(resp.Body) - - respBytes, err := io.ReadAll(io.LimitReader(resp.Body, respBodyLimit)) - if err != nil { - return "", err - } - respStr := string(respBytes) - - if resp.StatusCode == http.StatusOK { - return respStr, nil - } - - return respStr, fmt.Errorf("SUBNET request failed with code %d and error: %s", resp.StatusCode, respStr) +func (c Config) submitPost(_ *http.Request) (string, error) { + return "", errSiloSubnetDisabled } // Post submit 'payload' to specified URL func (c Config) Post(reqURL string, payload any) (string, error) { - if !c.Registered() { - return "", errors.New("Deployment is not registered with SUBNET. Please register the deployment via 'mc license register ALIAS'") - } - body, err := json.Marshal(payload) - if err != nil { - return "", err - } - r, err := http.NewRequest(http.MethodPost, reqURL, bytes.NewReader(body)) - if err != nil { - return "", err - } - - r.Header.Set("Content-Type", "application/json") - - return c.submitPost(r) + return "", errSiloSubnetDisabled } diff --git a/internal/config/subnet/subnet_test.go b/internal/config/subnet/subnet_test.go new file mode 100644 index 000000000..ede15ce13 --- /dev/null +++ b/internal/config/subnet/subnet_test.go @@ -0,0 +1,41 @@ +// Copyright 2026 PGSTY contributors. +// +// 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. + +package subnet + +import ( + "errors" + "os" + "testing" +) + +func TestSiloSubnetIsPermanentlyDisabled(t *testing.T) { + cfg := Config{License: "legacy-license", APIKey: "legacy-key", BaseURL: "https://example.invalid"} + if cfg.Registered() { + t.Fatal("legacy SUBNET credentials must not register a Silo deployment") + } + + for _, name := range []string{"CONSOLE_SUBNET_LICENSE", "CONSOLE_SUBNET_API_KEY", "CONSOLE_SUBNET_PROXY", "CONSOLE_SUBNET_URL"} { + t.Setenv(name, "must-be-cleared") + } + cfg.ApplyEnv() + for _, name := range []string{"CONSOLE_SUBNET_LICENSE", "CONSOLE_SUBNET_API_KEY", "CONSOLE_SUBNET_PROXY", "CONSOLE_SUBNET_URL"} { + if _, ok := os.LookupEnv(name); ok { + t.Fatalf("%s remains set", name) + } + } + + if _, err := cfg.Upload("https://example.invalid", "health.json", nil); !errors.Is(err, errSiloSubnetDisabled) { + t.Fatalf("Upload error = %v, want %v", err, errSiloSubnetDisabled) + } + if _, err := cfg.Post("https://example.invalid", struct{}{}); !errors.Is(err, errSiloSubnetDisabled) { + t.Fatalf("Post error = %v, want %v", err, errSiloSubnetDisabled) + } + if _, err := cfg.submitPost(nil); !errors.Is(err, errSiloSubnetDisabled) { + t.Fatalf("submitPost error = %v, want %v", err, errSiloSubnetDisabled) + } +} diff --git a/internal/event/target/elasticsearch.go b/internal/event/target/elasticsearch.go index 9cdd861bb..bccb873db 100644 --- a/internal/event/target/elasticsearch.go +++ b/internal/event/target/elasticsearch.go @@ -331,7 +331,7 @@ func (target *ElasticsearchTarget) checkAndInitClient(ctx context.Context) error return errors.New("unable to determine support status of ES (should not happen)") case ESSDeprecated: - return errors.New("there is no currently deprecated version of ES in MinIO") + return errors.New("there is no currently deprecated version of ES in Silo") case ESSSupported: target.client = clientV7 diff --git a/internal/event/target/nats.go b/internal/event/target/nats.go index 9011de5eb..f205a1713 100644 --- a/internal/event/target/nats.go +++ b/internal/event/target/nats.go @@ -172,7 +172,7 @@ func (n NATSArgs) Validate() error { // To obtain a nats connection from args. func (n NATSArgs) connectNats() (*nats.Conn, error) { - connOpts := []nats.Option{nats.Name("Minio Notification"), nats.MaxReconnects(-1)} + connOpts := []nats.Option{nats.Name("Silo Notification"), nats.MaxReconnects(-1)} if n.Username != "" && n.Password != "" { connOpts = append(connOpts, nats.UserInfo(n.Username, n.Password)) } diff --git a/internal/event/target/redis.go b/internal/event/target/redis.go index 8f7d42729..53082a515 100644 --- a/internal/event/target/redis.go +++ b/internal/event/target/redis.go @@ -352,7 +352,7 @@ func NewRedisTarget(id string, args RedisArgs, loggerOnce logger.LogOnce) (*Redi } // Must be done after AUTH - if _, err = conn.Do("CLIENT", "SETNAME", "MinIO"); err != nil { + if _, err = conn.Do("CLIENT", "SETNAME", "Silo"); err != nil { conn.Close() return nil, err } diff --git a/internal/kms/config.go b/internal/kms/config.go index 158bd0d60..a319e6cb9 100644 --- a/internal/kms/config.go +++ b/internal/kms/config.go @@ -358,11 +358,11 @@ func IsPresent() (bool, error) { switch { case kmsPresent && kesPresent: - return false, errors.New("kms: configuration for MinIO KMS and MinIO KES is present") + return false, errors.New("kms: both KMS and KES configuration are present") case kmsPresent && staticKeyPresent: - return false, errors.New("kms: configuration for MinIO KMS and static KMS key is present") + return false, errors.New("kms: both KMS and static-key configuration are present") case kesPresent && staticKeyPresent: - return false, errors.New("kms: configuration for MinIO KES and static KMS key is present") + return false, errors.New("kms: both KES and static-key configuration are present") } // Next, we check that all required configuration for the concrete @@ -375,16 +375,16 @@ func IsPresent() (bool, error) { return false, nil // No KMS config present case kmsPresent: if !isPresent(EnvKMSEndpoint) { - return false, fmt.Errorf("kms: incomplete configuration for MinIO KMS: missing '%s'", EnvKMSEndpoint) + return false, fmt.Errorf("kms: incomplete KMS configuration: missing '%s'", EnvKMSEndpoint) } if !isPresent(EnvKMSEnclave) { - return false, fmt.Errorf("kms: incomplete configuration for MinIO KMS: missing '%s'", EnvKMSEnclave) + return false, fmt.Errorf("kms: incomplete KMS configuration: missing '%s'", EnvKMSEnclave) } if !isPresent(EnvKMSDefaultKey) { - return false, fmt.Errorf("kms: incomplete configuration for MinIO KMS: missing '%s'", EnvKMSDefaultKey) + return false, fmt.Errorf("kms: incomplete KMS configuration: missing '%s'", EnvKMSDefaultKey) } if !isPresent(EnvKMSAPIKey) { - return false, fmt.Errorf("kms: incomplete configuration for MinIO KMS: missing '%s'", EnvKMSAPIKey) + return false, fmt.Errorf("kms: incomplete KMS configuration: missing '%s'", EnvKMSAPIKey) } return true, nil case staticKeyPresent: @@ -394,24 +394,24 @@ func IsPresent() (bool, error) { return true, nil case kesPresent: if !isPresent(EnvKESEndpoint) { - return false, fmt.Errorf("kms: incomplete configuration for MinIO KES: missing '%s'", EnvKESEndpoint) + return false, fmt.Errorf("kms: incomplete KES configuration: missing '%s'", EnvKESEndpoint) } if !isPresent(EnvKESDefaultKey) { - return false, fmt.Errorf("kms: incomplete configuration for MinIO KES: missing '%s'", EnvKESDefaultKey) + return false, fmt.Errorf("kms: incomplete KES configuration: missing '%s'", EnvKESDefaultKey) } if isPresent(EnvKESClientKey, EnvKESClientCert, EnvKESClientPassword) { if isPresent(EnvKESAPIKey) { - return false, fmt.Errorf("kms: invalid configuration for MinIO KES: '%s' and client certificate is present", EnvKESAPIKey) + return false, fmt.Errorf("kms: invalid KES configuration: '%s' and client certificate are both present", EnvKESAPIKey) } if !isPresent(EnvKESClientCert) { - return false, fmt.Errorf("kms: incomplete configuration for MinIO KES: missing '%s'", EnvKESClientCert) + return false, fmt.Errorf("kms: incomplete KES configuration: missing '%s'", EnvKESClientCert) } if !isPresent(EnvKESClientKey) { - return false, fmt.Errorf("kms: incomplete configuration for MinIO KES: missing '%s'", EnvKESClientKey) + return false, fmt.Errorf("kms: incomplete KES configuration: missing '%s'", EnvKESClientKey) } } else if !isPresent(EnvKESAPIKey) { - return false, errors.New("kms: incomplete configuration for MinIO KES: missing authentication method") + return false, errors.New("kms: incomplete KES configuration: missing authentication method") } return true, nil } diff --git a/internal/kms/stub.go b/internal/kms/stub.go index 2df1e9d8b..154df2cfb 100644 --- a/internal/kms/stub.go +++ b/internal/kms/stub.go @@ -32,7 +32,7 @@ var ( // StubCreatedAt is a constant timestamp for testing StubCreatedAt = time.Date(2024, time.January, 1, 15, 0, 0, 0, time.UTC) // StubCreatedBy is a constant created identity for testing - StubCreatedBy = "MinIO" + StubCreatedBy = "Silo" ) // NewStub returns a stub of KMS for testing diff --git a/internal/logger/logrotate.go b/internal/logger/logrotate.go index 0f47901c9..bf4bd989d 100644 --- a/internal/logger/logrotate.go +++ b/internal/logger/logrotate.go @@ -31,7 +31,7 @@ import ( ) func defaultFilenameFunc() string { - return fmt.Sprintf("minio-%s.log", fmt.Sprintf("%X", time.Now().UTC().UnixNano())) + return fmt.Sprintf("silo-%s.log", fmt.Sprintf("%X", time.Now().UTC().UnixNano())) } // Options define configuration options for Writer