diff --git a/cmd/cli/cluster.go b/cmd/cli/cluster.go index 15f7a4bdb..7710d9093 100644 --- a/cmd/cli/cluster.go +++ b/cmd/cli/cluster.go @@ -32,6 +32,8 @@ func renameKey(database moira.Database, oldValue, newValue string) error { if err != nil { return err } + default: + return makeUnknownDBError(database) } return nil @@ -51,6 +53,8 @@ func changeKeysPrefix(database moira.Database, oldPrefix string, newPrefix strin if err != nil { return err } + default: + return makeUnknownDBError(database) } return nil diff --git a/cmd/cli/errors.go b/cmd/cli/errors.go new file mode 100644 index 000000000..8f89b9858 --- /dev/null +++ b/cmd/cli/errors.go @@ -0,0 +1,22 @@ +package main + +import ( + "fmt" + "reflect" + + "github.com/moira-alert/moira" +) + +type unknownDBError struct { + database reflect.Type +} + +func makeUnknownDBError(database moira.Database) unknownDBError { + return unknownDBError{ + database: reflect.TypeOf(database), + } +} + +func (err unknownDBError) Error() string { + return fmt.Sprintf("Unknown implementation of moira.Database: %s", err.database.Name()) +} diff --git a/cmd/cli/from_2.9_to_2.10.go b/cmd/cli/from_2.9_to_2.10.go new file mode 100644 index 000000000..ba005e62f --- /dev/null +++ b/cmd/cli/from_2.9_to_2.10.go @@ -0,0 +1,86 @@ +package main + +import ( + "context" + + "github.com/moira-alert/moira" + "github.com/moira-alert/moira/database/redis" +) + +func updateFrom29(logger moira.Logger, database moira.Database) error { + logger.Info().Msg("Update 2.9 -> 2.10 was started") + + ctx := context.Background() + err := createKeyForLocalTriggers(ctx, logger, database) + if err != nil { + return err + } + + logger.Info().Msg("Update 2.9 -> 2.10 was finished") + return nil +} + +func downgradeTo29(logger moira.Logger, database moira.Database) error { + logger.Info().Msg("Downgrade 2.10 -> 2.9 started") + + ctx := context.Background() + err := revertCreateKeyForLocalTriggers(ctx, logger, database) + if err != nil { + return err + } + + logger.Info().Msg("Downgrade 2.10 -> 2.9 was finished") + return nil +} + +var triggersListKey = "{moira-triggers-list}:moira-triggers-list" +var localTriggersListKey = "{moira-triggers-list}:moira-local-triggers-list" +var remoteTriggersListKey = "{moira-triggers-list}:moira-remote-triggers-list" +var prometheusTriggersListKey = "{moira-triggers-list}:moira-prometheus-triggers-list" + +func createKeyForLocalTriggers(ctx context.Context, logger moira.Logger, database moira.Database) error { + logger.Info().Msg("Start createKeyForLocalTriggers") + + switch d := database.(type) { + case *redis.DbConnector: + pipe := d.Client().TxPipeline() + + localTriggerIds, err := pipe.SDiff(ctx, triggersListKey, remoteTriggersListKey, prometheusTriggersListKey).Result() + if err != nil { + return err + } + + logger.Info().Msg("Finish getting local trigger IDs") + + _, err = pipe.SAdd(ctx, localTriggersListKey, localTriggerIds).Result() + if err != nil { + return err + } + default: + return makeUnknownDBError(database) + } + + logger.Info().Msg("Successfully finished createKeyForLocalTriggers") + + return nil +} + +func revertCreateKeyForLocalTriggers(ctx context.Context, logger moira.Logger, database moira.Database) error { + logger.Info().Msg("Start revertCreateKeyForLocalTriggers") + + switch d := database.(type) { + case *redis.DbConnector: + pipe := d.Client().TxPipeline() + + _, err := pipe.Del(ctx, localTriggersListKey).Result() + if err != nil { + return err + } + default: + return makeUnknownDBError(database) + } + + logger.Info().Msg("Successfully finished revertCreateKeyForLocalTriggers") + + return nil +} diff --git a/cmd/cli/main.go b/cmd/cli/main.go index 13c35b45d..d8d99ab1b 100644 --- a/cmd/cli/main.go +++ b/cmd/cli/main.go @@ -23,7 +23,7 @@ var ( GoVersion = "unknown" ) -var moiraValidVersions = []string{"2.3", "2.6", "2.7"} +var moiraValidVersions = []string{"2.3", "2.6", "2.7", "2.9"} var ( configFileName = flag.String("config", "/etc/moira/cli.yml", "Path to configuration file") @@ -72,32 +72,39 @@ var ( ) func main() { //nolint - confCleanup, logger, dataBase := initApp() + confCleanup, logger, database := initApp() if *update { fromVersion := checkValidVersion(logger, updateFromVersion, true) switch fromVersion { case "2.3": - err := updateFrom23(logger, dataBase) + err := updateFrom23(logger, database) if err != nil { logger.Fatal(). Error(err). Msg("Fail to update from version 2.3") } case "2.6": - err := updateFrom26(logger, dataBase) + err := updateFrom26(logger, database) if err != nil { logger.Fatal(). Error(err). Msg("Fail to update from version 2.6") } case "2.7": - err := updateFrom27(logger, dataBase) + err := updateFrom27(logger, database) if err != nil { logger.Fatal(). Error(err). Msg("Fail to update from version 2.7") } + case "2.9": + err := updateFrom29(logger, database) + if err != nil { + logger.Fatal(). + Error(err). + Msg("Fail to update from version 2.9") + } } } @@ -105,31 +112,38 @@ func main() { //nolint toVersion := checkValidVersion(logger, downgradeToVersion, false) switch toVersion { case "2.3": - err := downgradeTo23(logger, dataBase) + err := downgradeTo23(logger, database) if err != nil { logger.Fatal(). Error(err). Msg("Fail to update to version 2.3") } case "2.6": - err := downgradeTo26(logger, dataBase) + err := downgradeTo26(logger, database) if err != nil { logger.Fatal(). Error(err). Msg("Fail to update to version 2.6") } case "2.7": - err := downgradeTo27(logger, dataBase) + err := downgradeTo27(logger, database) if err != nil { logger.Fatal(). Error(err). Msg("Fail to update to version 2.7") } + case "2.9": + err := downgradeTo29(logger, database) + if err != nil { + logger.Fatal(). + Error(err). + Msg("Fail to update to version 2.9") + } } } if *plotting { - if err := enablePlottingInAllSubscriptions(logger, dataBase); err != nil { + if err := enablePlottingInAllSubscriptions(logger, database); err != nil { logger.Error(). Error(err). Msg("Failed to enable images in all notifications") @@ -137,7 +151,7 @@ func main() { //nolint } if *fromUser != "" || *toUser != "" { - if err := transferUserSubscriptionsAndContacts(dataBase, *fromUser, *toUser); err != nil { + if err := transferUserSubscriptionsAndContacts(database, *fromUser, *toUser); err != nil { logger.Error(). Error(err). Msg("Failed to transfer user subscriptions and contacts") @@ -145,7 +159,7 @@ func main() { //nolint } if *userDel != "" { - if err := deleteUser(dataBase, *userDel); err != nil { + if err := deleteUser(database, *userDel); err != nil { logger.Error(). Error(err). Msg("Failed to delete user") @@ -158,7 +172,7 @@ func main() { //nolint String("prefix", *removeMetricsByPrefix). Msg("Removing metrics by prefix started") - if err := handleRemoveMetricsByPrefix(dataBase, *removeMetricsByPrefix); err != nil { + if err := handleRemoveMetricsByPrefix(database, *removeMetricsByPrefix); err != nil { log.Error(). Error(err). Msg("Failed to remove metrics by prefix") @@ -171,7 +185,7 @@ func main() { //nolint if *removeAllMetrics { log := logger.String(moira.LogFieldNameContext, "cleanup") log.Info().Msg("Removing all metrics started") - if err := handleRemoveAllMetrics(dataBase); err != nil { + if err := handleRemoveAllMetrics(database); err != nil { log.Error(). Error(err). Msg("Failed to remove all metrics") @@ -181,7 +195,7 @@ func main() { //nolint if *removeTriggersStartWith != "" { log := logger.String(moira.LogFieldNameContext, "remove-triggers-start-with") - if err := handleRemoveTriggersStartWith(logger, dataBase, *removeTriggersStartWith); err != nil { + if err := handleRemoveTriggersStartWith(logger, database, *removeTriggersStartWith); err != nil { log.Error(). Error(err). Msg("Failed to remove triggers by prefix") @@ -190,7 +204,7 @@ func main() { //nolint if *removeUnusedTriggersStartWith != "" { log := logger.String(moira.LogFieldNameContext, "remove-unused-triggers-start-with") - if err := handleRemoveUnusedTriggersStartWith(logger, dataBase, *removeUnusedTriggersStartWith); err != nil { + if err := handleRemoveUnusedTriggersStartWith(logger, database, *removeUnusedTriggersStartWith); err != nil { log.Error(). Error(err). Msg("Failed to remove unused triggers by prefix") @@ -204,7 +218,7 @@ func main() { //nolint Interface("user_whitelist", confCleanup.Whitelist). Msg("Cleanup started") - if err := handleCleanup(logger, dataBase, confCleanup); err != nil { + if err := handleCleanup(logger, database, confCleanup); err != nil { log.Error(). Error(err). Msg("Failed to cleanup") @@ -216,7 +230,7 @@ func main() { //nolint log := logger.String(moira.LogFieldNameContext, "cleanup-metrics") log.Info().Msg("Cleanup of outdated metrics started") - err := handleCleanUpOutdatedMetrics(confCleanup, dataBase) + err := handleCleanUpOutdatedMetrics(confCleanup, database) if err != nil { log.Error(). Error(err). @@ -228,7 +242,7 @@ func main() { //nolint log := logger.String(moira.LogFieldNameContext, "cleanup-last-checks") log.Info().Msg("Cleanup abandoned triggers last checks started") - err := handleCleanUpAbandonedTriggerLastCheck(dataBase) + err := handleCleanUpAbandonedTriggerLastCheck(database) if err != nil { log.Error(). Error(err). @@ -240,7 +254,7 @@ func main() { //nolint if *cleanupTags { log := logger.String(moira.LogFieldNameContext, "cleanup-tags") log.Info().Msg("Cleanup abandoned tags started") - count, err := handleCleanUpAbandonedTags(dataBase) + count, err := handleCleanUpAbandonedTags(database) if err != nil { log.Error(). Error(err). @@ -255,7 +269,7 @@ func main() { //nolint log := logger.String(moira.LogFieldNameContext, "cleanup-retentions") log.Info().Msg("Cleanup of abandoned retentions started") - err := handleCleanUpAbandonedRetentions(dataBase) + err := handleCleanUpAbandonedRetentions(database) if err != nil { log.Error(). Error(err). @@ -283,19 +297,19 @@ func main() { //nolint } logger.Info().Msg(GetDumpBriefInfo(dump)) - if err := support.HandlePushTrigger(logger, dataBase, &dump.Trigger); err != nil { + if err := support.HandlePushTrigger(logger, database, &dump.Trigger); err != nil { logger.Fatal(). Error(err). Msg("Failed to handle push trigger") } - if err := support.HandlePushTriggerMetrics(logger, dataBase, dump.Trigger.ID, dump.Metrics); err != nil { + if err := support.HandlePushTriggerMetrics(logger, database, dump.Trigger.ID, dump.Metrics); err != nil { logger.Fatal(). Error(err). Msg("Failed to handle push trigger metrics") } if err := support.HandlePushTriggerLastCheck( logger, - dataBase, + database, dump.Trigger.ID, &dump.LastCheck, dump.Trigger.TriggerSource, @@ -359,6 +373,7 @@ func checkValidVersion(logger moira.Logger, updateFromVersion *string, isUpdate logger.Fatal(). String("valid_version", strings.Join(moiraValidVersions, ", ")). String("flag", validFlag). + String("your_version", *updateFromVersion). Msg("You must set valid flag") } return moira.UseString(updateFromVersion) diff --git a/database/redis/database_test.go b/database/redis/database_test.go index c5a98b7d1..065e704e1 100644 --- a/database/redis/database_test.go +++ b/database/redis/database_test.go @@ -17,7 +17,7 @@ func TestNewDatabase(t *testing.T) { So(database, ShouldNotBeEmpty) So(database.source, ShouldEqual, "test") So(database.logger, ShouldEqual, logger) - So(database.context, ShouldEqual, context.Background()) + So(database.context, ShouldResemble, context.Background()) database.Flush() defer database.Flush() diff --git a/database/redis/trigger.go b/database/redis/trigger.go index b8868dbdd..83055aa0c 100644 --- a/database/redis/trigger.go +++ b/database/redis/trigger.go @@ -26,9 +26,9 @@ func (connector *DbConnector) GetAllTriggerIDs() ([]string, error) { // GetLocalTriggerIDs gets moira local triggerIDs func (connector *DbConnector) GetLocalTriggerIDs() ([]string, error) { c := *connector.client - triggerIds, err := c.SDiff(connector.context, triggersListKey, remoteTriggersListKey, prometheusTriggersListKey).Result() + triggerIds, err := c.SMembers(connector.context, localTriggersListKey).Result() if err != nil { - return nil, fmt.Errorf("failed to get triggers-list: %s", err.Error()) + return nil, fmt.Errorf("failed to get local triggers-list: %s", err.Error()) } return triggerIds, nil } @@ -55,7 +55,7 @@ func (connector *DbConnector) GetPrometheusTriggerIDs() ([]string, error) { func (connector *DbConnector) GetTriggerCount() (map[moira.TriggerSource]int64, error) { pipe := (*connector.client).TxPipeline() - total := pipe.SCard(connector.context, triggersListKey) + local := pipe.SCard(connector.context, localTriggersListKey) remote := pipe.SCard(connector.context, remoteTriggersListKey) prometheus := pipe.SCard(connector.context, prometheusTriggersListKey) @@ -64,7 +64,7 @@ func (connector *DbConnector) GetTriggerCount() (map[moira.TriggerSource]int64, return nil, err } - totalCount, err := total.Result() + localCount, err := local.Result() if err != nil { return nil, err } @@ -78,7 +78,7 @@ func (connector *DbConnector) GetTriggerCount() (map[moira.TriggerSource]int64, } return map[moira.TriggerSource]int64{ - moira.GraphiteLocal: totalCount - remoteCount - prometheusCount, + moira.GraphiteLocal: localCount, moira.GraphiteRemote: remoteCount, moira.PrometheusRemote: prometheusCount, }, nil @@ -226,6 +226,9 @@ func (connector *DbConnector) updateTrigger(triggerID string, newTrigger *moira. if newTrigger.TriggerSource != oldTrigger.TriggerSource { switch oldTrigger.TriggerSource { + case moira.GraphiteLocal: + pipe.SRem(connector.context, localTriggersListKey, triggerID) + case moira.GraphiteRemote: pipe.SRem(connector.context, remoteTriggersListKey, triggerID) @@ -245,6 +248,7 @@ func (connector *DbConnector) updateTrigger(triggerID string, newTrigger *moira. pipe.SAdd(connector.context, prometheusTriggersListKey, triggerID) case moira.GraphiteLocal: + pipe.SAdd(connector.context, localTriggersListKey, triggerID) for _, pattern := range newTrigger.Patterns { pipe.SAdd(connector.context, patternsListKey, pattern) pipe.SAdd(connector.context, patternTriggersKey(pattern), triggerID) @@ -309,6 +313,9 @@ func (connector *DbConnector) removeTrigger(triggerID string, trigger *moira.Tri pipe.SRem(connector.context, triggersListKey, triggerID) switch trigger.TriggerSource { + case moira.GraphiteLocal: + pipe.SRem(connector.context, localTriggersListKey, triggerID) + case moira.GraphiteRemote: pipe.SRem(connector.context, remoteTriggersListKey, triggerID) @@ -443,6 +450,7 @@ func (connector *DbConnector) triggerHasSubscriptions(trigger *moira.Trigger) (b } var triggersListKey = "{moira-triggers-list}:moira-triggers-list" +var localTriggersListKey = "{moira-triggers-list}:moira-local-triggers-list" var remoteTriggersListKey = "{moira-triggers-list}:moira-remote-triggers-list" var prometheusTriggersListKey = "{moira-triggers-list}:moira-prometheus-triggers-list"