diff --git a/cmd/admin-handlers-config-kv.go b/cmd/admin-handlers-config-kv.go index 454c98863..46bfe9d98 100644 --- a/cmd/admin-handlers-config-kv.go +++ b/cmd/admin-handlers-config-kv.go @@ -83,7 +83,7 @@ func (a adminAPIHandlers) DelConfigKVHandler(w http.ResponseWriter, r *http.Requ return } - if err = validateConfig(cfg, subSys); err != nil { + if err = validateConfig(ctx, cfg, subSys); err != nil { writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), err.Error(), r.URL) return } @@ -211,7 +211,12 @@ func setConfigKV(ctx context.Context, objectAPI ObjectLayer, kvBytes []byte) (re return } - if verr := validateConfig(result.Cfg, result.SubSys); verr != nil { + tgts, err := config.ParseConfigTargetID(bytes.NewReader(kvBytes)) + if err != nil { + return + } + ctx = context.WithValue(ctx, config.ContextKeyForTargetFromConfig, tgts) + if verr := validateConfig(ctx, result.Cfg, result.SubSys); verr != nil { err = badConfigErr{Err: verr} return } @@ -353,7 +358,7 @@ func (a adminAPIHandlers) RestoreConfigHistoryKVHandler(w http.ResponseWriter, r return } - if err = validateConfig(cfg, ""); err != nil { + if err = validateConfig(ctx, cfg, ""); err != nil { writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), err.Error(), r.URL) return } @@ -464,7 +469,7 @@ func (a adminAPIHandlers) SetConfigHandler(w http.ResponseWriter, r *http.Reques return } - if err = validateConfig(cfg, ""); err != nil { + if err = validateConfig(ctx, cfg, ""); err != nil { writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), err.Error(), r.URL) return } diff --git a/cmd/admin-handlers-idp-config.go b/cmd/admin-handlers-idp-config.go index c3fd7257f..6e378fe27 100644 --- a/cmd/admin-handlers-idp-config.go +++ b/cmd/admin-handlers-idp-config.go @@ -125,7 +125,7 @@ func (a adminAPIHandlers) addOrUpdateIDPHandler(ctx context.Context, w http.Resp return } - if err = validateConfig(cfg, subSys); err != nil { + if err = validateConfig(ctx, cfg, subSys); err != nil { var validationErr ldap.Validation if errors.As(err, &validationErr) { @@ -422,7 +422,7 @@ func (a adminAPIHandlers) DeleteIdentityProviderCfg(w http.ResponseWriter, r *ht writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) return } - if err = validateConfig(cfg, subSys); err != nil { + if err = validateConfig(ctx, cfg, subSys); err != nil { var validationErr ldap.Validation if errors.As(err, &validationErr) { diff --git a/cmd/config-current.go b/cmd/config-current.go index 4c453cc8c..6b3c9082b 100644 --- a/cmd/config-current.go +++ b/cmd/config-current.go @@ -283,7 +283,7 @@ var ( globalServerConfigMu sync.RWMutex ) -func validateSubSysConfig(s config.Config, subSys string, objAPI ObjectLayer) error { +func validateSubSysConfig(ctx context.Context, s config.Config, subSys string, objAPI ObjectLayer) error { switch subSys { case config.SiteSubSys: if _, err := config.LookupSite(s[config.SiteSubSys][config.Default], s[config.RegionSubSys][config.Default]); err != nil { @@ -393,7 +393,7 @@ func validateSubSysConfig(s config.Config, subSys string, objAPI ObjectLayer) er } if config.NotifySubSystems.Contains(subSys) { - if err := notify.TestSubSysNotificationTargets(GlobalContext, s, subSys, NewHTTPTransport()); err != nil { + if err := notify.TestSubSysNotificationTargets(ctx, s, subSys, NewHTTPTransport()); err != nil { return err } } @@ -407,7 +407,7 @@ func validateSubSysConfig(s config.Config, subSys string, objAPI ObjectLayer) er return nil } -func validateConfig(s config.Config, subSys string) error { +func validateConfig(ctx context.Context, s config.Config, subSys string) error { objAPI := newObjectLayerFn() // We must have a global lock for this so nobody else modifies env while we do. @@ -419,12 +419,12 @@ func validateConfig(s config.Config, subSys string) error { // Enable env values to validate KMS. defer env.SetEnvOn() if subSys != "" { - return validateSubSysConfig(s, subSys, objAPI) + return validateSubSysConfig(ctx, s, subSys, objAPI) } // No sub-system passed. Validate all of them. for _, ss := range config.SubSystems.ToSlice() { - if err := validateSubSysConfig(s, ss, objAPI); err != nil { + if err := validateSubSysConfig(ctx, s, ss, objAPI); err != nil { return err } } diff --git a/internal/config/config.go b/internal/config/config.go index d842d2243..de833d202 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -426,6 +426,34 @@ func (c Config) DelFrom(r io.Reader) error { return scanner.Err() } +// ContextKeyString is type(string) for contextKey +type ContextKeyString string + +// ContextKeyForTargetFromConfig - key for context for target from config +const ContextKeyForTargetFromConfig = ContextKeyString("ContextKeyForTargetFromConfig") + +// ParseConfigTargetID - read all targetIDs from reader +func ParseConfigTargetID(r io.Reader) (ids map[string]bool, err error) { + ids = make(map[string]bool) + scanner := bufio.NewScanner(r) + for scanner.Scan() { + // Skip any empty lines, or comment like characters + text := scanner.Text() + if text == "" || strings.HasPrefix(text, KvComment) { + continue + } + _, _, tgt, err := GetSubSys(text) + if err != nil { + return nil, err + } + ids[tgt] = true + } + if err := scanner.Err(); err != nil { + return nil, err + } + return +} + // ReadConfig - read content from input and write into c. // Returns whether all parameters were dynamic. func (c Config) ReadConfig(r io.Reader) (dynOnly bool, err error) { diff --git a/internal/config/notify/parse.go b/internal/config/notify/parse.go index 6230bb239..152cce6d8 100644 --- a/internal/config/notify/parse.go +++ b/internal/config/notify/parse.go @@ -58,13 +58,24 @@ func TestSubSysNotificationTargets(ctx context.Context, cfg config.Config, subSy defer target.Close() } + tgts, ok := ctx.Value(config.ContextKeyForTargetFromConfig).(map[string]bool) + if !ok { + tgts = make(map[string]bool) + } for _, target := range targetList { - yes, err := target.IsActive() - if err == nil && !yes { - err = ErrTargetsOffline - } - if err != nil { - return fmt.Errorf("error (%s): %w", target.ID(), err) + if tgts[target.ID().ID] { + // When target set should be online + yes, err := target.IsActive() + if err == nil && !yes { + err = ErrTargetsOffline + } + if err != nil { + return fmt.Errorf("error (%s): %w", target.ID(), err) + } + } else { + // Just for call init. + // Ignore target is online or offline + _, _ = target.IsActive() } }