diff --git a/CHANGELOG.md b/CHANGELOG.md index d7ff6f29ad1..05cc082db08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,14 @@ * [CHANGE] Updated Prometheus dependency to v2.16.0. This Prometheus version uses Active Query Tracker to limit concurrent queries. In order to keep `-querier.max-concurrent` working, Active Query Tracker is enabled by default, and is configured to store its data to `active-query-tracker` directory (relative to current directory when Cortex started). This can be changed by using `-querier.active-query-tracker-dir` option. Purpose of Active Query Tracker is to log queries that were running when Cortex crashes. This logging happens on next Cortex start. #2088 * [CHANGE] Experimental TSDB: TSDB head compaction interval and concurrency is now configurable (defaults to 1 min interval and 5 concurrent head compactions). New options: `-experimental.tsdb.head-compaction-interval` and `-experimental.tsdb.head-compaction-concurrency`. #2172 * [CHANGE] Remove fluentd-based billing infrastructure and flags such as `-distributor.enable-billing`. #1491 +* [CHANGE] Renamed Configs configuration options. #2187 + * configuration options + * `-database.*` -> `-configs.database.*` + * `-database.migrations` -> `-configs.database.migrations-dir` + * config file + * `configdb.uri:` -> `configs.database.uri:` + * `configdb.migrationsdir:` -> `configs.database.migrations_dir:` + * `configdb.passwordfile:` -> `configs.database.password_file:` * [CHANGE] Experimental TSDB: the querier in-memory index cache used by the experimental blocks storage shifted from per-tenant to per-querier. The `-experimental.tsdb.bucket-store.index-cache-size-bytes` now configures the per-querier index cache max size instead of a per-tenant cache and its default has been increased to 1GB. #2189 * [CHANGE] If you are vendoring Cortex and use its components in your project, be aware that many Cortex components no longer start automatically when they are created. You may want to review PR and attached document. #2166 * [CHANGE] Cortex now has /ready probe for all services, not just ingester and querier as before. In single-binary mode, /ready reports 204 only if all components are running properly. #2166 @@ -34,8 +42,11 @@ * `--experimental.distributor.user-subring-size` * [FEATURE] Added flag `-experimental.ruler.enable-api` to enable the ruler api which implements the Prometheus API `/api/v1/rules` and `/api/v1/alerts` endpoints under the configured `-http.prefix`. #1999 * [FEATURE] Added sharding support to compactor when using the experimental TSDB blocks storage. #2113 -* [FEATURE] Add ability to override YAML config file settings using environment variables. #2147 +* [FEATURE] Added ability to override YAML config file settings using environment variables. #2147 * `-config.expand-env` +* [FEATURE] Added flags to disable Alertmanager notifications methods. #2187 + * `-configs.notifications.disable-email` + * `-configs.notifications.disable-webhook` * [FEATURE] Add /config HTTP endpoint which exposes the current Cortex configuration as YAML. #2165 * [FEATURE] Allow Prometheus remote write directly to ingesters. #1491 * [FEATURE] Add flag `-experimental.tsdb.stripe-size` to expose TSDB stripe size option. #2185 diff --git a/docs/configuration/config-file-reference.md b/docs/configuration/config-file-reference.md index 68456ea515e..816ac572cf9 100644 --- a/docs/configuration/config-file-reference.md +++ b/docs/configuration/config-file-reference.md @@ -118,9 +118,8 @@ Where default_value is the value to use if the environment variable is undefined # The ruler_config configures the Cortex ruler. [ruler: ] -# The configdb_config configures the config database storing rules and alerts, -# and used by the 'configs' service to expose APIs to manage them. -[configdb: ] +# The configs_config configures the Cortex Configs DB and API. +[configs: ] # The alertmanager_config configures the Cortex alertmanager. [alertmanager: ] @@ -2081,22 +2080,33 @@ The `fifo_cache_config` configures the local in-memory cache. [validity: | default = 0s] ``` -### `configdb_config` +### `configs_config` -The `configdb_config` configures the config database storing rules and alerts, and used by the 'configs' service to expose APIs to manage them. +The `configs_config` configures the Cortex Configs DB and API. ```yaml -# URI where the database can be found (for dev you can use memory://) -# CLI flag: -database.uri -[uri: | default = "postgres://postgres@configs-db.weave.local/configs?sslmode=disable"] +database: + # URI where the database can be found (for dev you can use memory://) + # CLI flag: -configs.database.uri + [uri: | default = "postgres://postgres@configs-db.weave.local/configs?sslmode=disable"] -# Path where the database migration files can be found -# CLI flag: -database.migrations -[migrationsdir: | default = ""] + # Path where the database migration files can be found + # CLI flag: -configs.database.migrations-dir + [migrations_dir: | default = ""] -# File containing password (username goes in URI) -# CLI flag: -database.password-file -[passwordfile: | default = ""] + # File containing password (username goes in URI) + # CLI flag: -configs.database.password-file + [password_file: | default = ""] + +api: + notifications: + # Disable Email notifications for Alertmanager. + # CLI flag: -configs.notifications.disable-email + [disable_email: | default = false] + + # Disable WebHook notifications for Alertmanager. + # CLI flag: -configs.notifications.disable-webhook + [disable_webhook: | default = false] ``` ### `configstore_config` diff --git a/pkg/alertmanager/alerts/configdb/store.go b/pkg/alertmanager/alerts/configdb/store.go index 786ca29a461..92dd964d9af 100644 --- a/pkg/alertmanager/alerts/configdb/store.go +++ b/pkg/alertmanager/alerts/configdb/store.go @@ -3,15 +3,16 @@ package configdb import ( "context" + "github.com/cortexproject/cortex/pkg/configs/userconfig" + "github.com/cortexproject/cortex/pkg/alertmanager/alerts" - "github.com/cortexproject/cortex/pkg/configs" "github.com/cortexproject/cortex/pkg/configs/client" ) // Store is a concrete implementation of RuleStore that sources rules from the config service type Store struct { configClient client.Client - since configs.ID + since userconfig.ID alertConfigs map[string]alerts.AlertConfigDesc } diff --git a/pkg/configs/api/api.go b/pkg/configs/api/api.go index d5a2b2d048b..5418ba87fe2 100644 --- a/pkg/configs/api/api.go +++ b/pkg/configs/api/api.go @@ -3,6 +3,8 @@ package api import ( "database/sql" "encoding/json" + "errors" + "flag" "fmt" "html/template" "io/ioutil" @@ -18,20 +20,46 @@ import ( amconfig "github.com/prometheus/alertmanager/config" "github.com/weaveworks/common/user" - "github.com/cortexproject/cortex/pkg/configs" "github.com/cortexproject/cortex/pkg/configs/db" + "github.com/cortexproject/cortex/pkg/configs/userconfig" "github.com/cortexproject/cortex/pkg/util" ) +var ( + ErrEmailNotificationsAreDisabled = errors.New("email notifications are disabled") + ErrWebhookNotificationsAreDisabled = errors.New("webhook notifications are disabled") +) + +// Config configures Configs API +type Config struct { + Notifications NotificationsConfig `yaml:"notifications"` +} + +// NotificationsConfig configures Alertmanager notifications method. +type NotificationsConfig struct { + DisableEmail bool `yaml:"disable_email"` + DisableWebHook bool `yaml:"disable_webhook"` +} + +// RegisterFlags adds the flags required to configure this to the given FlagSet. +func (cfg *Config) RegisterFlags(f *flag.FlagSet) { + f.BoolVar(&cfg.Notifications.DisableEmail, "configs.notifications.disable-email", false, "Disable Email notifications for Alertmanager.") + f.BoolVar(&cfg.Notifications.DisableWebHook, "configs.notifications.disable-webhook", false, "Disable WebHook notifications for Alertmanager.") +} + // API implements the configs api. type API struct { - db db.DB http.Handler + db db.DB + cfg Config } // New creates a new API -func New(database db.DB) *API { - a := &API{db: database} +func New(database db.DB, cfg Config) *API { + a := &API{ + db: database, + cfg: cfg, + } r := mux.NewRouter() a.RegisterRoutes(r) a.Handler = r @@ -124,7 +152,7 @@ func (a *API) setConfig(w http.ResponseWriter, r *http.Request) { } logger := util.WithContext(r.Context(), util.Logger) - var cfg configs.Config + var cfg userconfig.Config switch parseConfigFormat(r.Header.Get("Content-Type"), FormatJSON) { case FormatJSON: if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil { @@ -147,7 +175,7 @@ func (a *API) setConfig(w http.ResponseWriter, r *http.Request) { return } - if err := validateAlertmanagerConfig(cfg.AlertmanagerConfig); err != nil && cfg.AlertmanagerConfig != "" { + if err := validateAlertmanagerConfig(cfg.AlertmanagerConfig, a.cfg.Notifications); err != nil && cfg.AlertmanagerConfig != "" { level.Error(logger).Log("msg", "invalid Alertmanager config", "err", err) http.Error(w, fmt.Sprintf("Invalid Alertmanager config: %v", err), http.StatusBadRequest) return @@ -180,7 +208,7 @@ func (a *API) validateAlertmanagerConfig(w http.ResponseWriter, r *http.Request) return } - if err = validateAlertmanagerConfig(string(cfg)); err != nil { + if err = validateAlertmanagerConfig(string(cfg), a.cfg.Notifications); err != nil { w.WriteHeader(http.StatusBadRequest) util.WriteJSONResponse(w, map[string]string{ "status": "error", @@ -194,27 +222,30 @@ func (a *API) validateAlertmanagerConfig(w http.ResponseWriter, r *http.Request) }) } -func validateAlertmanagerConfig(cfg string) error { +func validateAlertmanagerConfig(cfg string, noCfg NotificationsConfig) error { amCfg, err := amconfig.Load(cfg) if err != nil { return err } for _, recv := range amCfg.Receivers { - if len(recv.EmailConfigs) != 0 { - return fmt.Errorf("email notifications are not supported in Cortex yet") + if noCfg.DisableEmail && len(recv.EmailConfigs) > 0 { + return ErrEmailNotificationsAreDisabled + } + if noCfg.DisableWebHook && len(recv.WebhookConfigs) > 0 { + return ErrWebhookNotificationsAreDisabled } } return nil } -func validateRulesFiles(c configs.Config) error { +func validateRulesFiles(c userconfig.Config) error { _, err := c.RulesConfig.Parse() return err } -func validateTemplateFiles(c configs.Config) error { +func validateTemplateFiles(c userconfig.Config) error { for fn, content := range c.TemplateFiles { if _, err := template.New(fn).Parse(content); err != nil { return err @@ -224,14 +255,14 @@ func validateTemplateFiles(c configs.Config) error { return nil } -// ConfigsView renders multiple configurations, mapping userID to configs.View. +// ConfigsView renders multiple configurations, mapping userID to userconfig.View. // Exposed only for tests. type ConfigsView struct { - Configs map[string]configs.View `json:"configs"` + Configs map[string]userconfig.View `json:"configs"` } func (a *API) getConfigs(w http.ResponseWriter, r *http.Request) { - var cfgs map[string]configs.View + var cfgs map[string]userconfig.View var cfgErr error logger := util.WithContext(r.Context(), util.Logger) rawSince := r.FormValue("since") @@ -244,7 +275,7 @@ func (a *API) getConfigs(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusBadRequest) return } - cfgs, cfgErr = a.db.GetConfigs(r.Context(), configs.ID(since)) + cfgs, cfgErr = a.db.GetConfigs(r.Context(), userconfig.ID(since)) } if cfgErr != nil { diff --git a/pkg/configs/api/api_test.go b/pkg/configs/api/api_test.go index 8a8a9eda3ab..7902aca2dc1 100644 --- a/pkg/configs/api/api_test.go +++ b/pkg/configs/api/api_test.go @@ -9,10 +9,10 @@ import ( "strings" "testing" + "github.com/cortexproject/cortex/pkg/configs/userconfig" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - - "github.com/cortexproject/cortex/pkg/configs" ) const ( @@ -45,14 +45,14 @@ type configurable struct { } // post a config -func (c configurable) post(t *testing.T, userID string, config configs.Config) configs.View { +func (c configurable) post(t *testing.T, userID string, config userconfig.Config) userconfig.View { w := requestAsUser(t, userID, "POST", c.Endpoint, "", readerFromConfig(t, config)) require.Equal(t, http.StatusNoContent, w.Code) return c.get(t, userID) } // get a config -func (c configurable) get(t *testing.T, userID string) configs.View { +func (c configurable) get(t *testing.T, userID string) userconfig.View { w := requestAsUser(t, userID, "GET", c.Endpoint, "", nil) return parseView(t, w.Body.Bytes()) } @@ -154,11 +154,11 @@ func Test_GetAllConfigs_Empty(t *testing.T) { var found ConfigsView err := json.Unmarshal(w.Body.Bytes(), &found) assert.NoError(t, err, "Could not unmarshal JSON") - assert.Equal(t, ConfigsView{Configs: map[string]configs.View{}}, found) + assert.Equal(t, ConfigsView{Configs: map[string]userconfig.View{}}, found) } } -// GetAllConfigs returns all created configs. +// GetAllConfigs returns all created userconfig. func Test_GetAllConfigs(t *testing.T) { setup(t) defer cleanup(t) @@ -173,13 +173,13 @@ func Test_GetAllConfigs(t *testing.T) { var found ConfigsView err := json.Unmarshal(w.Body.Bytes(), &found) assert.NoError(t, err, "Could not unmarshal JSON") - assert.Equal(t, ConfigsView{Configs: map[string]configs.View{ + assert.Equal(t, ConfigsView{Configs: map[string]userconfig.View{ userID: view, }}, found) } } -// GetAllConfigs returns the *newest* versions of all created configs. +// GetAllConfigs returns the *newest* versions of all created userconfig. func Test_GetAllConfigs_Newest(t *testing.T) { setup(t) defer cleanup(t) @@ -196,7 +196,7 @@ func Test_GetAllConfigs_Newest(t *testing.T) { var found ConfigsView err := json.Unmarshal(w.Body.Bytes(), &found) assert.NoError(t, err, "Could not unmarshal JSON") - assert.Equal(t, ConfigsView{Configs: map[string]configs.View{ + assert.Equal(t, ConfigsView{Configs: map[string]userconfig.View{ userID: lastCreated, }}, found) } @@ -217,7 +217,7 @@ func Test_GetConfigs_IncludesNewerConfigsAndExcludesOlder(t *testing.T) { var found ConfigsView err := json.Unmarshal(w.Body.Bytes(), &found) assert.NoError(t, err, "Could not unmarshal JSON") - assert.Equal(t, ConfigsView{Configs: map[string]configs.View{ + assert.Equal(t, ConfigsView{Configs: map[string]userconfig.View{ userID3: config3, }}, found) } @@ -245,13 +245,27 @@ var amCfgValidationTests = []struct { email_configs: - to: myteam@foobar.org`, shouldFail: true, - errContains: "email notifications are not supported in Cortex yet", + errContains: ErrEmailNotificationsAreDisabled.Error(), + }, { + config: ` + global: + smtp_smarthost: localhost:25 + smtp_from: alertmanager@example.org + route: + receiver: noop + + receivers: + - name: noop + slack_configs: + - api_url: http://slack`, + shouldFail: false, }, } func Test_ValidateAlertmanagerConfig(t *testing.T) { setup(t) defer cleanup(t) + userID := makeUserID() for i, test := range amCfgValidationTests { resp := requestAsUser(t, userID, "POST", "/api/prom/configs/alertmanager/validate", "", strings.NewReader(test.config)) @@ -276,9 +290,10 @@ func Test_ValidateAlertmanagerConfig(t *testing.T) { func Test_SetConfig_ValidatesAlertmanagerConfig(t *testing.T) { setup(t) defer cleanup(t) + userID := makeUserID() for i, test := range amCfgValidationTests { - cfg := configs.Config{AlertmanagerConfig: test.config} + cfg := userconfig.Config{AlertmanagerConfig: test.config} resp := requestAsUser(t, userID, "POST", "/api/prom/configs/alertmanager", "", readerFromConfig(t, cfg)) if !test.shouldFail { @@ -291,6 +306,28 @@ func Test_SetConfig_ValidatesAlertmanagerConfig(t *testing.T) { } } +func Test_SetConfig_ValidatesAlertmanagerConfig_WithEmailEnabled(t *testing.T) { + config := ` + global: + smtp_smarthost: localhost:25 + smtp_from: alertmanager@example.org + route: + receiver: noop + + receivers: + - name: noop + email_configs: + - to: myteam@foobar.org` + setupWithEmailEnabled(t) + defer cleanup(t) + + userID := makeUserID() + cfg := userconfig.Config{AlertmanagerConfig: config} + resp := requestAsUser(t, userID, "POST", "/api/prom/configs/alertmanager", "", readerFromConfig(t, cfg)) + + assert.Equal(t, http.StatusNoContent, resp.Code) +} + func Test_SetConfig_BodyFormat(t *testing.T) { setup(t) defer cleanup(t) diff --git a/pkg/configs/api/helpers_test.go b/pkg/configs/api/helpers_test.go index 1031a02e348..49e5cbfb51a 100644 --- a/pkg/configs/api/helpers_test.go +++ b/pkg/configs/api/helpers_test.go @@ -9,10 +9,11 @@ import ( "net/http/httptest" "testing" + "github.com/cortexproject/cortex/pkg/configs/userconfig" + "github.com/stretchr/testify/require" "github.com/weaveworks/common/user" - "github.com/cortexproject/cortex/pkg/configs" "github.com/cortexproject/cortex/pkg/configs/db" "github.com/cortexproject/cortex/pkg/configs/db/dbtest" ) @@ -26,7 +27,22 @@ var ( // setup sets up the environment for the tests. func setup(t *testing.T) { database = dbtest.Setup(t) - app = New(database) + app = New(database, Config{ + Notifications: NotificationsConfig{ + DisableEmail: true, + }, + }) + counter = 0 +} + +// setup sets up the environment for the tests with email enabled. +func setupWithEmailEnabled(t *testing.T) { + database = dbtest.Setup(t) + app = New(database, Config{ + Notifications: NotificationsConfig{ + DisableEmail: false, + }, + }) counter = 0 } @@ -71,8 +87,8 @@ func makeUserID() string { } // makeConfig makes some arbitrary configuration. -func makeConfig() configs.Config { - return configs.Config{ +func makeConfig() userconfig.Config { + return userconfig.Config{ AlertmanagerConfig: makeString(` # Config no. %d. route: @@ -80,19 +96,19 @@ func makeConfig() configs.Config { receivers: - name: noop`), - RulesConfig: configs.RulesConfig{}, + RulesConfig: userconfig.RulesConfig{}, } } -func readerFromConfig(t *testing.T, config configs.Config) io.Reader { +func readerFromConfig(t *testing.T, config userconfig.Config) io.Reader { b, err := json.Marshal(config) require.NoError(t, err) return bytes.NewReader(b) } -// parseView parses a configs.View from JSON. -func parseView(t *testing.T, b []byte) configs.View { - var x configs.View +// parseView parses a userconfig.View from JSON. +func parseView(t *testing.T, b []byte) userconfig.View { + var x userconfig.View err := json.Unmarshal(b, &x) require.NoError(t, err, "Could not unmarshal JSON: %v", string(b)) return x diff --git a/pkg/configs/client/client.go b/pkg/configs/client/client.go index 5250d40ee6c..6397c67c30d 100644 --- a/pkg/configs/client/client.go +++ b/pkg/configs/client/client.go @@ -9,17 +9,18 @@ import ( "net/url" "time" + "github.com/cortexproject/cortex/pkg/configs/userconfig" + "github.com/go-kit/kit/log/level" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/weaveworks/common/instrument" - "github.com/cortexproject/cortex/pkg/configs" "github.com/cortexproject/cortex/pkg/util" "github.com/cortexproject/cortex/pkg/util/flagext" ) -// Config says where we can find the ruler configs. +// Config says where we can find the ruler userconfig. type Config struct { ConfigsAPIURL flagext.URLValue ClientTimeout time.Duration // HTTP timeout duration for requests made to the Weave Cloud configs service. @@ -34,18 +35,18 @@ func (cfg *Config) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) { var configsRequestDuration = instrument.NewHistogramCollector(promauto.NewHistogramVec(prometheus.HistogramOpts{ Namespace: "cortex", Name: "configs_request_duration_seconds", - Help: "Time spent requesting configs.", + Help: "Time spent requesting userconfig.", Buckets: prometheus.DefBuckets, }, []string{"operation", "status_code"})) // Client is what the ruler and altermanger needs from a config store to process rules. type Client interface { // GetRules returns all Cortex configurations from a configs API server - // that have been updated after the given configs.ID was last updated. - GetRules(ctx context.Context, since configs.ID) (map[string]configs.VersionedRulesConfig, error) + // that have been updated after the given userconfig.ID was last updated. + GetRules(ctx context.Context, since userconfig.ID) (map[string]userconfig.VersionedRulesConfig, error) // GetAlerts fetches all the alerts that have changes since since. - GetAlerts(ctx context.Context, since configs.ID) (*ConfigsResponse, error) + GetAlerts(ctx context.Context, since userconfig.ID) (*ConfigsResponse, error) } // New creates a new ConfigClient. @@ -63,7 +64,7 @@ type ConfigDBClient struct { } // GetRules implements Client -func (c ConfigDBClient) GetRules(ctx context.Context, since configs.ID) (map[string]configs.VersionedRulesConfig, error) { +func (c ConfigDBClient) GetRules(ctx context.Context, since userconfig.ID) (map[string]userconfig.VersionedRulesConfig, error) { suffix := "" if since != 0 { suffix = fmt.Sprintf("?since=%d", since) @@ -78,7 +79,7 @@ func (c ConfigDBClient) GetRules(ctx context.Context, since configs.ID) (map[str if err != nil { return nil, err } - configs := map[string]configs.VersionedRulesConfig{} + configs := map[string]userconfig.VersionedRulesConfig{} for id, view := range response.Configs { cfg := view.GetVersionedRulesConfig() if cfg != nil { @@ -89,7 +90,7 @@ func (c ConfigDBClient) GetRules(ctx context.Context, since configs.ID) (map[str } // GetAlerts implements Client. -func (c ConfigDBClient) GetAlerts(ctx context.Context, since configs.ID) (*ConfigsResponse, error) { +func (c ConfigDBClient) GetAlerts(ctx context.Context, since userconfig.ID) (*ConfigsResponse, error) { suffix := "" if since != 0 { suffix = fmt.Sprintf("?since=%d", since) @@ -104,7 +105,7 @@ func (c ConfigDBClient) GetAlerts(ctx context.Context, since configs.ID) (*Confi return response, err } -func doRequest(endpoint string, timeout time.Duration, since configs.ID) (*ConfigsResponse, error) { +func doRequest(endpoint string, timeout time.Duration, since userconfig.ID) (*ConfigsResponse, error) { req, err := http.NewRequest("GET", endpoint, nil) if err != nil { return nil, err @@ -132,17 +133,17 @@ func doRequest(endpoint string, timeout time.Duration, since configs.ID) (*Confi return &config, nil } -// ConfigsResponse is a response from server for GetConfigs. +// ConfigsResponse is a response from server for Getuserconfig. type ConfigsResponse struct { // The version since which these configs were changed - since configs.ID + since userconfig.ID - // Configs maps user ID to their latest configs.View. - Configs map[string]configs.View `json:"configs"` + // Configs maps user ID to their latest userconfig.View. + Configs map[string]userconfig.View `json:"configs"` } -// GetLatestConfigID returns the last config ID from a set of configs. -func (c ConfigsResponse) GetLatestConfigID() configs.ID { +// GetLatestConfigID returns the last config ID from a set of userconfig. +func (c ConfigsResponse) GetLatestConfigID() userconfig.ID { latest := c.since for _, config := range c.Configs { if config.ID > latest { diff --git a/pkg/configs/client/configs_test.go b/pkg/configs/client/configs_test.go index b4ed4b275b5..86b0427c7ee 100644 --- a/pkg/configs/client/configs_test.go +++ b/pkg/configs/client/configs_test.go @@ -6,11 +6,11 @@ import ( "testing" "time" + "github.com/cortexproject/cortex/pkg/configs/userconfig" + "github.com/stretchr/testify/require" "github.com/stretchr/testify/assert" - - "github.com/cortexproject/cortex/pkg/configs" ) var response = `{ @@ -38,15 +38,15 @@ func TestDoRequest(t *testing.T) { resp, err := doRequest(server.URL, 1*time.Second, 0) assert.Nil(t, err) - expected := ConfigsResponse{Configs: map[string]configs.View{ + expected := ConfigsResponse{Configs: map[string]userconfig.View{ "2": { ID: 1, - Config: configs.Config{ - RulesConfig: configs.RulesConfig{ + Config: userconfig.Config{ + RulesConfig: userconfig.RulesConfig{ Files: map[string]string{ "recording.rules": "groups:\n- name: demo-service-alerts\n interval: 15s\n rules:\n - alert: SomethingIsUp\n expr: up == 1\n", }, - FormatVersion: configs.RuleFormatV2, + FormatVersion: userconfig.RuleFormatV2, }, }, }, diff --git a/pkg/configs/config.go b/pkg/configs/config.go new file mode 100644 index 00000000000..9ec1d68b648 --- /dev/null +++ b/pkg/configs/config.go @@ -0,0 +1,19 @@ +package configs + +import ( + "flag" + + "github.com/cortexproject/cortex/pkg/configs/api" + "github.com/cortexproject/cortex/pkg/configs/db" +) + +type Config struct { + DB db.Config `yaml:"database"` + API api.Config `yaml:"api"` +} + +// RegisterFlags adds the flags required to configure this to the given FlagSet. +func (cfg *Config) RegisterFlags(f *flag.FlagSet) { + cfg.DB.RegisterFlags(f) + cfg.API.RegisterFlags(f) +} diff --git a/pkg/configs/db/db.go b/pkg/configs/db/db.go index fd2f2b9dc37..0ec290494c7 100644 --- a/pkg/configs/db/db.go +++ b/pkg/configs/db/db.go @@ -7,16 +7,16 @@ import ( "io/ioutil" "net/url" - "github.com/cortexproject/cortex/pkg/configs" "github.com/cortexproject/cortex/pkg/configs/db/memory" "github.com/cortexproject/cortex/pkg/configs/db/postgres" + "github.com/cortexproject/cortex/pkg/configs/userconfig" ) // Config configures the database. type Config struct { - URI string - MigrationsDir string - PasswordFile string + URI string `yaml:"uri"` + MigrationsDir string `yaml:"migrations_dir"` + PasswordFile string `yaml:"password_file"` // Allow injection of mock DBs for unit testing. Mock DB `yaml:"-"` @@ -24,33 +24,33 @@ type Config struct { // RegisterFlags adds the flags required to configure this to the given FlagSet. func (cfg *Config) RegisterFlags(f *flag.FlagSet) { - f.StringVar(&cfg.URI, "database.uri", "postgres://postgres@configs-db.weave.local/configs?sslmode=disable", "URI where the database can be found (for dev you can use memory://)") - f.StringVar(&cfg.MigrationsDir, "database.migrations", "", "Path where the database migration files can be found") - f.StringVar(&cfg.PasswordFile, "database.password-file", "", "File containing password (username goes in URI)") + f.StringVar(&cfg.URI, "configs.database.uri", "postgres://postgres@configs-db.weave.local/configs?sslmode=disable", "URI where the database can be found (for dev you can use memory://)") + f.StringVar(&cfg.MigrationsDir, "configs.database.migrations-dir", "", "Path where the database migration files can be found") + f.StringVar(&cfg.PasswordFile, "configs.database.password-file", "", "File containing password (username goes in URI)") } // DB is the interface for the database. type DB interface { // GetRulesConfig gets the user's ruler config - GetRulesConfig(ctx context.Context, userID string) (configs.VersionedRulesConfig, error) + GetRulesConfig(ctx context.Context, userID string) (userconfig.VersionedRulesConfig, error) // SetRulesConfig does a compare-and-swap (CAS) on the user's rules config. // `oldConfig` must precisely match the current config in order to change the config to `newConfig`. // Will return `true` if the config was updated, `false` otherwise. - SetRulesConfig(ctx context.Context, userID string, oldConfig, newConfig configs.RulesConfig) (bool, error) + SetRulesConfig(ctx context.Context, userID string, oldConfig, newConfig userconfig.RulesConfig) (bool, error) // GetAllRulesConfigs gets all of the ruler configs - GetAllRulesConfigs(ctx context.Context) (map[string]configs.VersionedRulesConfig, error) + GetAllRulesConfigs(ctx context.Context) (map[string]userconfig.VersionedRulesConfig, error) // GetRulesConfigs gets all of the configs that have been added or have // changed since the provided config. - GetRulesConfigs(ctx context.Context, since configs.ID) (map[string]configs.VersionedRulesConfig, error) + GetRulesConfigs(ctx context.Context, since userconfig.ID) (map[string]userconfig.VersionedRulesConfig, error) - GetConfig(ctx context.Context, userID string) (configs.View, error) - SetConfig(ctx context.Context, userID string, cfg configs.Config) error + GetConfig(ctx context.Context, userID string) (userconfig.View, error) + SetConfig(ctx context.Context, userID string, cfg userconfig.Config) error - GetAllConfigs(ctx context.Context) (map[string]configs.View, error) - GetConfigs(ctx context.Context, since configs.ID) (map[string]configs.View, error) + GetAllConfigs(ctx context.Context) (map[string]userconfig.View, error) + GetConfigs(ctx context.Context, since userconfig.ID) (map[string]userconfig.View, error) DeactivateConfig(ctx context.Context, userID string) error RestoreConfig(ctx context.Context, userID string) error diff --git a/pkg/configs/db/memory/memory.go b/pkg/configs/db/memory/memory.go index c2f8bbe2c0c..a759c425bd0 100644 --- a/pkg/configs/db/memory/memory.go +++ b/pkg/configs/db/memory/memory.go @@ -6,50 +6,50 @@ import ( "fmt" "time" - "github.com/cortexproject/cortex/pkg/configs" + "github.com/cortexproject/cortex/pkg/configs/userconfig" ) // DB is an in-memory database for testing, and local development type DB struct { - cfgs map[string]configs.View + cfgs map[string]userconfig.View id uint } // New creates a new in-memory database func New(_, _ string) (*DB, error) { return &DB{ - cfgs: map[string]configs.View{}, + cfgs: map[string]userconfig.View{}, id: 0, }, nil } // GetConfig gets the user's configuration. -func (d *DB) GetConfig(ctx context.Context, userID string) (configs.View, error) { +func (d *DB) GetConfig(ctx context.Context, userID string) (userconfig.View, error) { c, ok := d.cfgs[userID] if !ok { - return configs.View{}, sql.ErrNoRows + return userconfig.View{}, sql.ErrNoRows } return c, nil } // SetConfig sets configuration for a user. -func (d *DB) SetConfig(ctx context.Context, userID string, cfg configs.Config) error { +func (d *DB) SetConfig(ctx context.Context, userID string, cfg userconfig.Config) error { if !cfg.RulesConfig.FormatVersion.IsValid() { return fmt.Errorf("invalid rule format version %v", cfg.RulesConfig.FormatVersion) } - d.cfgs[userID] = configs.View{Config: cfg, ID: configs.ID(d.id)} + d.cfgs[userID] = userconfig.View{Config: cfg, ID: userconfig.ID(d.id)} d.id++ return nil } -// GetAllConfigs gets all of the configs. -func (d *DB) GetAllConfigs(ctx context.Context) (map[string]configs.View, error) { +// GetAllConfigs gets all of the userconfig. +func (d *DB) GetAllConfigs(ctx context.Context) (map[string]userconfig.View, error) { return d.cfgs, nil } // GetConfigs gets all of the configs that have changed recently. -func (d *DB) GetConfigs(ctx context.Context, since configs.ID) (map[string]configs.View, error) { - cfgs := map[string]configs.View{} +func (d *DB) GetConfigs(ctx context.Context, since userconfig.ID) (map[string]userconfig.View, error) { + cfgs := map[string]userconfig.View{} for user, c := range d.cfgs { if c.ID > since { cfgs[user] = c @@ -67,7 +67,7 @@ func (d *DB) SetDeletedAtConfig(ctx context.Context, userID string, deletedAt ti return err } cv.DeletedAt = deletedAt - cv.ID = configs.ID(d.id) + cv.ID = userconfig.ID(d.id) d.cfgs[userID] = cv d.id++ return nil @@ -89,36 +89,36 @@ func (d *DB) Close() error { } // GetRulesConfig gets the rules config for a user. -func (d *DB) GetRulesConfig(ctx context.Context, userID string) (configs.VersionedRulesConfig, error) { +func (d *DB) GetRulesConfig(ctx context.Context, userID string) (userconfig.VersionedRulesConfig, error) { c, ok := d.cfgs[userID] if !ok { - return configs.VersionedRulesConfig{}, sql.ErrNoRows + return userconfig.VersionedRulesConfig{}, sql.ErrNoRows } cfg := c.GetVersionedRulesConfig() if cfg == nil { - return configs.VersionedRulesConfig{}, sql.ErrNoRows + return userconfig.VersionedRulesConfig{}, sql.ErrNoRows } return *cfg, nil } // SetRulesConfig sets the rules config for a user. -func (d *DB) SetRulesConfig(ctx context.Context, userID string, oldConfig, newConfig configs.RulesConfig) (bool, error) { +func (d *DB) SetRulesConfig(ctx context.Context, userID string, oldConfig, newConfig userconfig.RulesConfig) (bool, error) { c, ok := d.cfgs[userID] if !ok { - return true, d.SetConfig(ctx, userID, configs.Config{RulesConfig: newConfig}) + return true, d.SetConfig(ctx, userID, userconfig.Config{RulesConfig: newConfig}) } if !oldConfig.Equal(c.Config.RulesConfig) { return false, nil } - return true, d.SetConfig(ctx, userID, configs.Config{ + return true, d.SetConfig(ctx, userID, userconfig.Config{ AlertmanagerConfig: c.Config.AlertmanagerConfig, RulesConfig: newConfig, }) } // GetAllRulesConfigs gets the rules configs for all users that have them. -func (d *DB) GetAllRulesConfigs(ctx context.Context) (map[string]configs.VersionedRulesConfig, error) { - cfgs := map[string]configs.VersionedRulesConfig{} +func (d *DB) GetAllRulesConfigs(ctx context.Context) (map[string]userconfig.VersionedRulesConfig, error) { + cfgs := map[string]userconfig.VersionedRulesConfig{} for user, c := range d.cfgs { cfg := c.GetVersionedRulesConfig() if cfg != nil { @@ -130,8 +130,8 @@ func (d *DB) GetAllRulesConfigs(ctx context.Context) (map[string]configs.Version // GetRulesConfigs gets the rules configs that have changed // since the given config version. -func (d *DB) GetRulesConfigs(ctx context.Context, since configs.ID) (map[string]configs.VersionedRulesConfig, error) { - cfgs := map[string]configs.VersionedRulesConfig{} +func (d *DB) GetRulesConfigs(ctx context.Context, since userconfig.ID) (map[string]userconfig.VersionedRulesConfig, error) { + cfgs := map[string]userconfig.VersionedRulesConfig{} for user, c := range d.cfgs { if c.ID <= since { continue diff --git a/pkg/configs/db/postgres/postgres.go b/pkg/configs/db/postgres/postgres.go index 9247addd1b9..6476891f625 100644 --- a/pkg/configs/db/postgres/postgres.go +++ b/pkg/configs/db/postgres/postgres.go @@ -8,6 +8,8 @@ import ( "strings" "time" + "github.com/cortexproject/cortex/pkg/configs/userconfig" + "github.com/Masterminds/squirrel" "github.com/go-kit/kit/log/level" "github.com/golang-migrate/migrate/v4" @@ -17,7 +19,6 @@ import ( _ "github.com/lib/pq" // Import the postgres sql driver "github.com/pkg/errors" - "github.com/cortexproject/cortex/pkg/configs" "github.com/cortexproject/cortex/pkg/util" ) @@ -105,7 +106,7 @@ func New(uri, migrationsDir string) (DB, error) { var statementBuilder = squirrel.StatementBuilder.PlaceholderFormat(squirrel.Dollar).RunWith -func (d DB) findConfigs(filter squirrel.Sqlizer) (map[string]configs.View, error) { +func (d DB) findConfigs(filter squirrel.Sqlizer) (map[string]userconfig.View, error) { rows, err := d.Select("id", "owner_id", "config", "deleted_at"). Options("DISTINCT ON (owner_id)"). From("configs"). @@ -116,9 +117,9 @@ func (d DB) findConfigs(filter squirrel.Sqlizer) (map[string]configs.View, error return nil, err } defer rows.Close() - cfgs := map[string]configs.View{} + cfgs := map[string]userconfig.View{} for rows.Next() { - var cfg configs.View + var cfg userconfig.View var cfgBytes []byte var userID string var deletedAt pq.NullTime @@ -137,8 +138,8 @@ func (d DB) findConfigs(filter squirrel.Sqlizer) (map[string]configs.View, error } // GetConfig gets a configuration. -func (d DB) GetConfig(ctx context.Context, userID string) (configs.View, error) { - var cfgView configs.View +func (d DB) GetConfig(ctx context.Context, userID string) (userconfig.View, error) { + var cfgView userconfig.View var cfgBytes []byte var deletedAt pq.NullTime err := d.Select("id", "config", "deleted_at"). @@ -156,7 +157,7 @@ func (d DB) GetConfig(ctx context.Context, userID string) (configs.View, error) } // SetConfig sets a configuration. -func (d DB) SetConfig(ctx context.Context, userID string, cfg configs.Config) error { +func (d DB) SetConfig(ctx context.Context, userID string, cfg userconfig.Config) error { if !cfg.RulesConfig.FormatVersion.IsValid() { return fmt.Errorf("invalid rule format version %v", cfg.RulesConfig.FormatVersion) } @@ -172,13 +173,13 @@ func (d DB) SetConfig(ctx context.Context, userID string, cfg configs.Config) er return err } -// GetAllConfigs gets all of the configs. -func (d DB) GetAllConfigs(ctx context.Context) (map[string]configs.View, error) { +// GetAllConfigs gets all of the userconfig. +func (d DB) GetAllConfigs(ctx context.Context) (map[string]userconfig.View, error) { return d.findConfigs(allConfigs) } // GetConfigs gets all of the configs that have changed recently. -func (d DB) GetConfigs(ctx context.Context, since configs.ID) (map[string]configs.View, error) { +func (d DB) GetConfigs(ctx context.Context, since userconfig.ID) (map[string]userconfig.View, error) { return d.findConfigs(squirrel.And{ allConfigs, squirrel.Gt{"id": since}, @@ -186,20 +187,20 @@ func (d DB) GetConfigs(ctx context.Context, since configs.ID) (map[string]config } // GetRulesConfig gets the latest alertmanager config for a user. -func (d DB) GetRulesConfig(ctx context.Context, userID string) (configs.VersionedRulesConfig, error) { +func (d DB) GetRulesConfig(ctx context.Context, userID string) (userconfig.VersionedRulesConfig, error) { current, err := d.GetConfig(ctx, userID) if err != nil { - return configs.VersionedRulesConfig{}, err + return userconfig.VersionedRulesConfig{}, err } cfg := current.GetVersionedRulesConfig() if cfg == nil { - return configs.VersionedRulesConfig{}, sql.ErrNoRows + return userconfig.VersionedRulesConfig{}, sql.ErrNoRows } return *cfg, nil } // SetRulesConfig sets the current alertmanager config for a user. -func (d DB) SetRulesConfig(ctx context.Context, userID string, oldConfig, newConfig configs.RulesConfig) (bool, error) { +func (d DB) SetRulesConfig(ctx context.Context, userID string, oldConfig, newConfig userconfig.RulesConfig) (bool, error) { updated := false err := d.Transaction(func(tx DB) error { current, err := d.GetConfig(ctx, userID) @@ -212,7 +213,7 @@ func (d DB) SetRulesConfig(ctx context.Context, userID string, oldConfig, newCon if !((err == sql.ErrNoRows && oldConfig.Files == nil) || oldConfig.Equal(current.Config.RulesConfig)) { return nil } - new := configs.Config{ + new := userconfig.Config{ AlertmanagerConfig: current.Config.AlertmanagerConfig, RulesConfig: newConfig, } @@ -224,7 +225,7 @@ func (d DB) SetRulesConfig(ctx context.Context, userID string, oldConfig, newCon // findRulesConfigs helps GetAllRulesConfigs and GetRulesConfigs retrieve the // set of all active rules configurations across all our users. -func (d DB) findRulesConfigs(filter squirrel.Sqlizer) (map[string]configs.VersionedRulesConfig, error) { +func (d DB) findRulesConfigs(filter squirrel.Sqlizer) (map[string]userconfig.VersionedRulesConfig, error) { rows, err := d.Select("id", "owner_id", "config ->> 'rules_files'", "config ->> 'rule_format_version'", "deleted_at"). Options("DISTINCT ON (owner_id)"). From("configs"). @@ -245,9 +246,9 @@ func (d DB) findRulesConfigs(filter squirrel.Sqlizer) (map[string]configs.Versio return nil, err } defer rows.Close() - cfgs := map[string]configs.VersionedRulesConfig{} + cfgs := map[string]userconfig.VersionedRulesConfig{} for rows.Next() { - var cfg configs.VersionedRulesConfig + var cfg userconfig.VersionedRulesConfig var userID string var cfgBytes []byte var rfvBytes []byte @@ -275,12 +276,12 @@ func (d DB) findRulesConfigs(filter squirrel.Sqlizer) (map[string]configs.Versio } // GetAllRulesConfigs gets all alertmanager configs for all users. -func (d DB) GetAllRulesConfigs(ctx context.Context) (map[string]configs.VersionedRulesConfig, error) { +func (d DB) GetAllRulesConfigs(ctx context.Context) (map[string]userconfig.VersionedRulesConfig, error) { return d.findRulesConfigs(allConfigs) } // GetRulesConfigs gets all the alertmanager configs that have changed since a given config. -func (d DB) GetRulesConfigs(ctx context.Context, since configs.ID) (map[string]configs.VersionedRulesConfig, error) { +func (d DB) GetRulesConfigs(ctx context.Context, since userconfig.ID) (map[string]userconfig.VersionedRulesConfig, error) { return d.findRulesConfigs(squirrel.And{ allConfigs, squirrel.Gt{"id": since}, @@ -290,7 +291,7 @@ func (d DB) GetRulesConfigs(ctx context.Context, since configs.ID) (map[string]c // SetDeletedAtConfig sets a deletedAt for configuration // by adding a single new row with deleted_at set // the same as SetConfig is actually insert -func (d DB) SetDeletedAtConfig(ctx context.Context, userID string, deletedAt pq.NullTime, cfg configs.Config) error { +func (d DB) SetDeletedAtConfig(ctx context.Context, userID string, deletedAt pq.NullTime, cfg userconfig.Config) error { cfgBytes, err := json.Marshal(cfg) if err != nil { return err diff --git a/pkg/configs/db/timed.go b/pkg/configs/db/timed.go index f7bbd6d6cd4..58cbfdc9e19 100644 --- a/pkg/configs/db/timed.go +++ b/pkg/configs/db/timed.go @@ -6,7 +6,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/weaveworks/common/instrument" - "github.com/cortexproject/cortex/pkg/configs" + "github.com/cortexproject/cortex/pkg/configs/userconfig" ) var ( @@ -27,8 +27,8 @@ type timed struct { d DB } -func (t timed) GetConfig(ctx context.Context, userID string) (configs.View, error) { - var cfg configs.View +func (t timed) GetConfig(ctx context.Context, userID string) (userconfig.View, error) { + var cfg userconfig.View err := instrument.CollectedRequest(ctx, "DB.GetConfigs", databaseRequestDuration, instrument.ErrorCode, func(ctx context.Context) error { var err error cfg, err = t.d.GetConfig(ctx, userID) // Warning: this will produce an incorrect result if the configID ever overflows @@ -37,14 +37,14 @@ func (t timed) GetConfig(ctx context.Context, userID string) (configs.View, erro return cfg, err } -func (t timed) SetConfig(ctx context.Context, userID string, cfg configs.Config) error { +func (t timed) SetConfig(ctx context.Context, userID string, cfg userconfig.Config) error { return instrument.CollectedRequest(ctx, "DB.SetConfig", databaseRequestDuration, instrument.ErrorCode, func(ctx context.Context) error { return t.d.SetConfig(ctx, userID, cfg) // Warning: this will produce an incorrect result if the configID ever overflows }) } -func (t timed) GetAllConfigs(ctx context.Context) (map[string]configs.View, error) { - var cfgs map[string]configs.View +func (t timed) GetAllConfigs(ctx context.Context) (map[string]userconfig.View, error) { + var cfgs map[string]userconfig.View err := instrument.CollectedRequest(ctx, "DB.GetAllConfigs", databaseRequestDuration, instrument.ErrorCode, func(ctx context.Context) error { var err error cfgs, err = t.d.GetAllConfigs(ctx) @@ -54,8 +54,8 @@ func (t timed) GetAllConfigs(ctx context.Context) (map[string]configs.View, erro return cfgs, err } -func (t timed) GetConfigs(ctx context.Context, since configs.ID) (map[string]configs.View, error) { - var cfgs map[string]configs.View +func (t timed) GetConfigs(ctx context.Context, since userconfig.ID) (map[string]userconfig.View, error) { + var cfgs map[string]userconfig.View err := instrument.CollectedRequest(ctx, "DB.GetConfigs", databaseRequestDuration, instrument.ErrorCode, func(ctx context.Context) error { var err error cfgs, err = t.d.GetConfigs(ctx, since) @@ -83,8 +83,8 @@ func (t timed) Close() error { }) } -func (t timed) GetRulesConfig(ctx context.Context, userID string) (configs.VersionedRulesConfig, error) { - var cfg configs.VersionedRulesConfig +func (t timed) GetRulesConfig(ctx context.Context, userID string) (userconfig.VersionedRulesConfig, error) { + var cfg userconfig.VersionedRulesConfig err := instrument.CollectedRequest(ctx, "DB.GetRulesConfig", databaseRequestDuration, instrument.ErrorCode, func(ctx context.Context) error { var err error cfg, err = t.d.GetRulesConfig(ctx, userID) @@ -94,7 +94,7 @@ func (t timed) GetRulesConfig(ctx context.Context, userID string) (configs.Versi return cfg, err } -func (t timed) SetRulesConfig(ctx context.Context, userID string, oldCfg, newCfg configs.RulesConfig) (bool, error) { +func (t timed) SetRulesConfig(ctx context.Context, userID string, oldCfg, newCfg userconfig.RulesConfig) (bool, error) { var updated bool err := instrument.CollectedRequest(ctx, "DB.SetRulesConfig", databaseRequestDuration, instrument.ErrorCode, func(ctx context.Context) error { var err error @@ -105,8 +105,8 @@ func (t timed) SetRulesConfig(ctx context.Context, userID string, oldCfg, newCfg return updated, err } -func (t timed) GetAllRulesConfigs(ctx context.Context) (map[string]configs.VersionedRulesConfig, error) { - var cfgs map[string]configs.VersionedRulesConfig +func (t timed) GetAllRulesConfigs(ctx context.Context) (map[string]userconfig.VersionedRulesConfig, error) { + var cfgs map[string]userconfig.VersionedRulesConfig err := instrument.CollectedRequest(ctx, "DB.GetAllRulesConfigs", databaseRequestDuration, instrument.ErrorCode, func(ctx context.Context) error { var err error cfgs, err = t.d.GetAllRulesConfigs(ctx) @@ -116,8 +116,8 @@ func (t timed) GetAllRulesConfigs(ctx context.Context) (map[string]configs.Versi return cfgs, err } -func (t timed) GetRulesConfigs(ctx context.Context, since configs.ID) (map[string]configs.VersionedRulesConfig, error) { - var cfgs map[string]configs.VersionedRulesConfig +func (t timed) GetRulesConfigs(ctx context.Context, since userconfig.ID) (map[string]userconfig.VersionedRulesConfig, error) { + var cfgs map[string]userconfig.VersionedRulesConfig err := instrument.CollectedRequest(ctx, "DB.GetRulesConfigs", databaseRequestDuration, instrument.ErrorCode, func(ctx context.Context) error { var err error cfgs, err = t.d.GetRulesConfigs(ctx, since) diff --git a/pkg/configs/db/traced.go b/pkg/configs/db/traced.go index 2549b86be0d..7a2cc3aac61 100644 --- a/pkg/configs/db/traced.go +++ b/pkg/configs/db/traced.go @@ -4,9 +4,10 @@ import ( "context" "fmt" + "github.com/cortexproject/cortex/pkg/configs/userconfig" + "github.com/go-kit/kit/log/level" - "github.com/cortexproject/cortex/pkg/configs" "github.com/cortexproject/cortex/pkg/util" ) @@ -19,22 +20,22 @@ func (t traced) trace(name string, args ...interface{}) { level.Debug(util.Logger).Log("msg", fmt.Sprintf("%s: %#v", name, args)) } -func (t traced) GetConfig(ctx context.Context, userID string) (cfg configs.View, err error) { +func (t traced) GetConfig(ctx context.Context, userID string) (cfg userconfig.View, err error) { defer func() { t.trace("GetConfig", userID, cfg, err) }() return t.d.GetConfig(ctx, userID) } -func (t traced) SetConfig(ctx context.Context, userID string, cfg configs.Config) (err error) { +func (t traced) SetConfig(ctx context.Context, userID string, cfg userconfig.Config) (err error) { defer func() { t.trace("SetConfig", userID, cfg, err) }() return t.d.SetConfig(ctx, userID, cfg) } -func (t traced) GetAllConfigs(ctx context.Context) (cfgs map[string]configs.View, err error) { +func (t traced) GetAllConfigs(ctx context.Context) (cfgs map[string]userconfig.View, err error) { defer func() { t.trace("GetAllConfigs", cfgs, err) }() return t.d.GetAllConfigs(ctx) } -func (t traced) GetConfigs(ctx context.Context, since configs.ID) (cfgs map[string]configs.View, err error) { +func (t traced) GetConfigs(ctx context.Context, since userconfig.ID) (cfgs map[string]userconfig.View, err error) { defer func() { t.trace("GetConfigs", since, cfgs, err) }() return t.d.GetConfigs(ctx, since) } @@ -54,22 +55,22 @@ func (t traced) Close() (err error) { return t.d.Close() } -func (t traced) GetRulesConfig(ctx context.Context, userID string) (cfg configs.VersionedRulesConfig, err error) { +func (t traced) GetRulesConfig(ctx context.Context, userID string) (cfg userconfig.VersionedRulesConfig, err error) { defer func() { t.trace("GetRulesConfig", userID, cfg, err) }() return t.d.GetRulesConfig(ctx, userID) } -func (t traced) SetRulesConfig(ctx context.Context, userID string, oldCfg, newCfg configs.RulesConfig) (updated bool, err error) { +func (t traced) SetRulesConfig(ctx context.Context, userID string, oldCfg, newCfg userconfig.RulesConfig) (updated bool, err error) { defer func() { t.trace("SetRulesConfig", userID, oldCfg, newCfg, updated, err) }() return t.d.SetRulesConfig(ctx, userID, oldCfg, newCfg) } -func (t traced) GetAllRulesConfigs(ctx context.Context) (cfgs map[string]configs.VersionedRulesConfig, err error) { +func (t traced) GetAllRulesConfigs(ctx context.Context) (cfgs map[string]userconfig.VersionedRulesConfig, err error) { defer func() { t.trace("GetAllRulesConfigs", cfgs, err) }() return t.d.GetAllRulesConfigs(ctx) } -func (t traced) GetRulesConfigs(ctx context.Context, since configs.ID) (cfgs map[string]configs.VersionedRulesConfig, err error) { +func (t traced) GetRulesConfigs(ctx context.Context, since userconfig.ID) (cfgs map[string]userconfig.VersionedRulesConfig, err error) { defer func() { t.trace("GetConfigs", since, cfgs, err) }() return t.d.GetRulesConfigs(ctx, since) } diff --git a/pkg/configs/configs.go b/pkg/configs/userconfig/config.go similarity index 99% rename from pkg/configs/configs.go rename to pkg/configs/userconfig/config.go index c3896ce13bf..178ed5e4742 100644 --- a/pkg/configs/configs.go +++ b/pkg/configs/userconfig/config.go @@ -1,4 +1,4 @@ -package configs +package userconfig import ( "encoding/json" diff --git a/pkg/configs/configs_test.go b/pkg/configs/userconfig/config_test.go similarity index 99% rename from pkg/configs/configs_test.go rename to pkg/configs/userconfig/config_test.go index 8c26a7961c6..6fd9c0894f4 100644 --- a/pkg/configs/configs_test.go +++ b/pkg/configs/userconfig/config_test.go @@ -1,4 +1,4 @@ -package configs +package userconfig import ( "encoding/json" diff --git a/pkg/cortex/cortex.go b/pkg/cortex/cortex.go index 277e8af744c..a6e49053fe5 100644 --- a/pkg/cortex/cortex.go +++ b/pkg/cortex/cortex.go @@ -8,6 +8,8 @@ import ( "net/http" "os" + "github.com/cortexproject/cortex/pkg/configs" + "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/pkg/errors" @@ -87,7 +89,7 @@ type Config struct { DataPurgerConfig purger.Config `yaml:"purger,omitempty"` Ruler ruler.Config `yaml:"ruler,omitempty"` - ConfigDB db.Config `yaml:"configdb,omitempty"` + Configs configs.Config `yaml:"configs,omitempty"` Alertmanager alertmanager.MultitenantAlertmanagerConfig `yaml:"alertmanager,omitempty"` RuntimeConfig runtimeconfig.ManagerConfig `yaml:"runtime_config,omitempty"` MemberlistKV memberlist.KVConfig `yaml:"memberlist"` @@ -123,7 +125,7 @@ func (c *Config) RegisterFlags(f *flag.FlagSet) { c.DataPurgerConfig.RegisterFlags(f) c.Ruler.RegisterFlags(f) - c.ConfigDB.RegisterFlags(f) + c.Configs.RegisterFlags(f) c.Alertmanager.RegisterFlags(f) c.RuntimeConfig.RegisterFlags(f) c.MemberlistKV.RegisterFlags(f, "") diff --git a/pkg/cortex/modules.go b/pkg/cortex/modules.go index 578a51b83cc..c4aea29099d 100644 --- a/pkg/cortex/modules.go +++ b/pkg/cortex/modules.go @@ -493,12 +493,12 @@ func (t *Cortex) initRuler(cfg *Config) (serv services.Service, err error) { } func (t *Cortex) initConfig(cfg *Config) (serv services.Service, err error) { - t.configDB, err = db.New(cfg.ConfigDB) + t.configDB, err = db.New(cfg.Configs.DB) if err != nil { return } - t.configAPI = api.New(t.configDB) + t.configAPI = api.New(t.configDB, cfg.Configs.API) t.configAPI.RegisterRoutes(t.server.HTTP) return services.NewIdleService(nil, func() error { t.configDB.Close() diff --git a/pkg/ruler/rules/store.go b/pkg/ruler/rules/store.go index 11584ea5d88..6cca7de3768 100644 --- a/pkg/ruler/rules/store.go +++ b/pkg/ruler/rules/store.go @@ -4,7 +4,8 @@ import ( "context" "errors" - "github.com/cortexproject/cortex/pkg/configs" + "github.com/cortexproject/cortex/pkg/configs/userconfig" + "github.com/cortexproject/cortex/pkg/configs/client" legacy_rulefmt "github.com/cortexproject/cortex/pkg/ruler/legacy_rulefmt" @@ -45,7 +46,7 @@ func (l RuleGroupList) Formatted() map[string][]legacy_rulefmt.RuleGroup { // ConfigRuleStore is a concrete implementation of RuleStore that sources rules from the config service type ConfigRuleStore struct { configClient client.Client - since configs.ID + since userconfig.ID ruleGroupList map[string]RuleGroupList } @@ -96,7 +97,7 @@ func (c *ConfigRuleStore) ListAllRuleGroups(ctx context.Context) (map[string]Rul // getLatestConfigID gets the latest configs ID. // max [latest, max (map getID cfgs)] -func getLatestConfigID(cfgs map[string]configs.VersionedRulesConfig, latest configs.ID) configs.ID { +func getLatestConfigID(cfgs map[string]userconfig.VersionedRulesConfig, latest userconfig.ID) userconfig.ID { ret := latest for _, config := range cfgs { if config.ID > ret { diff --git a/pkg/ruler/rules/store_test.go b/pkg/ruler/rules/store_test.go index 445e2726868..775cdab212a 100644 --- a/pkg/ruler/rules/store_test.go +++ b/pkg/ruler/rules/store_test.go @@ -6,24 +6,25 @@ import ( "testing" time "time" + "github.com/cortexproject/cortex/pkg/configs/userconfig" + "github.com/stretchr/testify/assert" - "github.com/cortexproject/cortex/pkg/configs" "github.com/cortexproject/cortex/pkg/configs/client" ) var zeroTime time.Time type MockClient struct { - cfgs map[string]configs.VersionedRulesConfig + cfgs map[string]userconfig.VersionedRulesConfig err error } -func (c *MockClient) GetRules(ctx context.Context, since configs.ID) (map[string]configs.VersionedRulesConfig, error) { +func (c *MockClient) GetRules(ctx context.Context, since userconfig.ID) (map[string]userconfig.VersionedRulesConfig, error) { return c.cfgs, c.err } -func (c *MockClient) GetAlerts(ctx context.Context, since configs.ID) (*client.ConfigsResponse, error) { +func (c *MockClient) GetAlerts(ctx context.Context, since userconfig.ID) (*client.ConfigsResponse, error) { return nil, nil } @@ -40,9 +41,9 @@ func Test_ConfigRuleStoreError(t *testing.T) { } func Test_ConfigRuleStoreReturn(t *testing.T) { - id := configs.ID(10) + id := userconfig.ID(10) mock := &MockClient{ - cfgs: map[string]configs.VersionedRulesConfig{ + cfgs: map[string]userconfig.VersionedRulesConfig{ "user": { ID: id, Config: fakeRuleConfig(), @@ -61,7 +62,7 @@ func Test_ConfigRuleStoreReturn(t *testing.T) { func Test_ConfigRuleStoreDelete(t *testing.T) { mock := &MockClient{ - cfgs: map[string]configs.VersionedRulesConfig{ + cfgs: map[string]userconfig.VersionedRulesConfig{ "user": { ID: 1, Config: fakeRuleConfig(), @@ -74,9 +75,9 @@ func Test_ConfigRuleStoreDelete(t *testing.T) { store := NewConfigRuleStore(mock) _, _ = store.ListAllRuleGroups(context.Background()) - mock.cfgs["user"] = configs.VersionedRulesConfig{ + mock.cfgs["user"] = userconfig.VersionedRulesConfig{ ID: 1, - Config: configs.RulesConfig{}, + Config: userconfig.RulesConfig{}, DeletedAt: time.Unix(0, 1), } @@ -87,7 +88,7 @@ func Test_ConfigRuleStoreDelete(t *testing.T) { func Test_ConfigRuleStoreAppend(t *testing.T) { mock := &MockClient{ - cfgs: map[string]configs.VersionedRulesConfig{ + cfgs: map[string]userconfig.VersionedRulesConfig{ "user": { ID: 1, Config: fakeRuleConfig(), @@ -101,7 +102,7 @@ func Test_ConfigRuleStoreAppend(t *testing.T) { _, _ = store.ListAllRuleGroups(context.Background()) delete(mock.cfgs, "user") - mock.cfgs["user2"] = configs.VersionedRulesConfig{ + mock.cfgs["user2"] = userconfig.VersionedRulesConfig{ ID: 1, Config: fakeRuleConfig(), DeletedAt: zeroTime, @@ -114,7 +115,7 @@ func Test_ConfigRuleStoreAppend(t *testing.T) { func Test_ConfigRuleStoreSinceSet(t *testing.T) { mock := &MockClient{ - cfgs: map[string]configs.VersionedRulesConfig{ + cfgs: map[string]userconfig.VersionedRulesConfig{ "user": { ID: 1, Config: fakeRuleConfig(), @@ -136,32 +137,32 @@ func Test_ConfigRuleStoreSinceSet(t *testing.T) { store := NewConfigRuleStore(mock) _, _ = store.ListAllRuleGroups(context.Background()) - assert.Equal(t, configs.ID(100), store.since) + assert.Equal(t, userconfig.ID(100), store.since) delete(mock.cfgs, "user") delete(mock.cfgs, "user1") - mock.cfgs["user2"] = configs.VersionedRulesConfig{ + mock.cfgs["user2"] = userconfig.VersionedRulesConfig{ ID: 50, Config: fakeRuleConfig(), DeletedAt: zeroTime, } _, _ = store.ListAllRuleGroups(context.Background()) - assert.Equal(t, configs.ID(100), store.since) + assert.Equal(t, userconfig.ID(100), store.since) - mock.cfgs["user2"] = configs.VersionedRulesConfig{ + mock.cfgs["user2"] = userconfig.VersionedRulesConfig{ ID: 101, Config: fakeRuleConfig(), DeletedAt: zeroTime, } _, _ = store.ListAllRuleGroups(context.Background()) - assert.Equal(t, configs.ID(101), store.since) + assert.Equal(t, userconfig.ID(101), store.since) } -func fakeRuleConfig() configs.RulesConfig { - return configs.RulesConfig{ - FormatVersion: configs.RuleFormatV2, +func fakeRuleConfig() userconfig.RulesConfig { + return userconfig.RulesConfig{ + FormatVersion: userconfig.RuleFormatV2, Files: map[string]string{ "test": ` # Config no. 1. diff --git a/tools/doc-generator/main.go b/tools/doc-generator/main.go index 5bccfea6ad8..52b94074b46 100644 --- a/tools/doc-generator/main.go +++ b/tools/doc-generator/main.go @@ -17,8 +17,8 @@ import ( "github.com/cortexproject/cortex/pkg/chunk/purger" "github.com/cortexproject/cortex/pkg/chunk/storage" "github.com/cortexproject/cortex/pkg/compactor" + "github.com/cortexproject/cortex/pkg/configs" config_client "github.com/cortexproject/cortex/pkg/configs/client" - "github.com/cortexproject/cortex/pkg/configs/db" "github.com/cortexproject/cortex/pkg/cortex" "github.com/cortexproject/cortex/pkg/distributor" "github.com/cortexproject/cortex/pkg/ingester" @@ -149,9 +149,9 @@ var ( desc: "The fifo_cache_config configures the local in-memory cache.", }, { - name: "configdb_config", - structType: reflect.TypeOf(db.Config{}), - desc: "The configdb_config configures the config database storing rules and alerts, and used by the 'configs' service to expose APIs to manage them.", + name: "configs_config", + structType: reflect.TypeOf(configs.Config{}), + desc: "The configs_config configures the Cortex Configs DB and API.", }, { name: "configstore_config",