github.com/muhammadn/cortex@v1.9.1-0.20220510110439-46bb7000d03d/pkg/alertmanager/alertmanager_ring.go (about) 1 package alertmanager 2 3 import ( 4 "flag" 5 "fmt" 6 "os" 7 "time" 8 9 "github.com/go-kit/log" 10 "github.com/go-kit/log/level" 11 "github.com/grafana/dskit/flagext" 12 "github.com/grafana/dskit/kv" 13 "github.com/grafana/dskit/ring" 14 15 util_log "github.com/cortexproject/cortex/pkg/util/log" 16 ) 17 18 const ( 19 // RingKey is the key under which we store the alertmanager ring in the KVStore. 20 RingKey = "alertmanager" 21 22 // RingNameForServer is the name of the ring used by the alertmanager server. 23 RingNameForServer = "alertmanager" 24 25 // RingNumTokens is a safe default instead of exposing to config option to the user 26 // in order to simplify the config. 27 RingNumTokens = 128 28 ) 29 30 // RingOp is the operation used for reading/writing to the alertmanagers. 31 var RingOp = ring.NewOp([]ring.InstanceState{ring.ACTIVE}, func(s ring.InstanceState) bool { 32 // Only ACTIVE Alertmanager get requests. If instance is not ACTIVE, we need to find another Alertmanager. 33 return s != ring.ACTIVE 34 }) 35 36 // SyncRingOp is the operation used for checking if a user is owned by an alertmanager. 37 var SyncRingOp = ring.NewOp([]ring.InstanceState{ring.ACTIVE, ring.JOINING}, func(s ring.InstanceState) bool { 38 return s != ring.ACTIVE 39 }) 40 41 // RingConfig masks the ring lifecycler config which contains 42 // many options not really required by the alertmanager ring. This config 43 // is used to strip down the config to the minimum, and avoid confusion 44 // to the user. 45 type RingConfig struct { 46 KVStore kv.Config `yaml:"kvstore" doc:"description=The key-value store used to share the hash ring across multiple instances."` 47 HeartbeatPeriod time.Duration `yaml:"heartbeat_period"` 48 HeartbeatTimeout time.Duration `yaml:"heartbeat_timeout"` 49 ReplicationFactor int `yaml:"replication_factor"` 50 ZoneAwarenessEnabled bool `yaml:"zone_awareness_enabled"` 51 52 // Instance details 53 InstanceID string `yaml:"instance_id" doc:"hidden"` 54 InstanceInterfaceNames []string `yaml:"instance_interface_names"` 55 InstancePort int `yaml:"instance_port" doc:"hidden"` 56 InstanceAddr string `yaml:"instance_addr" doc:"hidden"` 57 InstanceZone string `yaml:"instance_availability_zone"` 58 59 // Injected internally 60 ListenPort int `yaml:"-"` 61 RingCheckPeriod time.Duration `yaml:"-"` 62 63 // Used for testing 64 SkipUnregister bool `yaml:"-"` 65 } 66 67 // RegisterFlags adds the flags required to config this to the given FlagSet 68 func (cfg *RingConfig) RegisterFlags(f *flag.FlagSet) { 69 hostname, err := os.Hostname() 70 if err != nil { 71 level.Error(util_log.Logger).Log("msg", "failed to get hostname", "err", err) 72 os.Exit(1) 73 } 74 75 // Prefix used by all the ring flags 76 rfprefix := "alertmanager.sharding-ring." 77 78 // Ring flags 79 cfg.KVStore.RegisterFlagsWithPrefix(rfprefix, "alertmanagers/", f) 80 f.DurationVar(&cfg.HeartbeatPeriod, rfprefix+"heartbeat-period", 15*time.Second, "Period at which to heartbeat to the ring. 0 = disabled.") 81 f.DurationVar(&cfg.HeartbeatTimeout, rfprefix+"heartbeat-timeout", time.Minute, "The heartbeat timeout after which alertmanagers are considered unhealthy within the ring. 0 = never (timeout disabled).") 82 f.IntVar(&cfg.ReplicationFactor, rfprefix+"replication-factor", 3, "The replication factor to use when sharding the alertmanager.") 83 f.BoolVar(&cfg.ZoneAwarenessEnabled, rfprefix+"zone-awareness-enabled", false, "True to enable zone-awareness and replicate alerts across different availability zones.") 84 85 // Instance flags 86 cfg.InstanceInterfaceNames = []string{"eth0", "en0"} 87 f.Var((*flagext.StringSlice)(&cfg.InstanceInterfaceNames), rfprefix+"instance-interface-names", "Name of network interface to read address from.") 88 f.StringVar(&cfg.InstanceAddr, rfprefix+"instance-addr", "", "IP address to advertise in the ring.") 89 f.IntVar(&cfg.InstancePort, rfprefix+"instance-port", 0, "Port to advertise in the ring (defaults to server.grpc-listen-port).") 90 f.StringVar(&cfg.InstanceID, rfprefix+"instance-id", hostname, "Instance ID to register in the ring.") 91 f.StringVar(&cfg.InstanceZone, rfprefix+"instance-availability-zone", "", "The availability zone where this instance is running. Required if zone-awareness is enabled.") 92 93 cfg.RingCheckPeriod = 5 * time.Second 94 } 95 96 // ToLifecyclerConfig returns a LifecyclerConfig based on the alertmanager 97 // ring config. 98 func (cfg *RingConfig) ToLifecyclerConfig(logger log.Logger) (ring.BasicLifecyclerConfig, error) { 99 instanceAddr, err := ring.GetInstanceAddr(cfg.InstanceAddr, cfg.InstanceInterfaceNames, logger) 100 if err != nil { 101 return ring.BasicLifecyclerConfig{}, err 102 } 103 104 instancePort := ring.GetInstancePort(cfg.InstancePort, cfg.ListenPort) 105 106 return ring.BasicLifecyclerConfig{ 107 ID: cfg.InstanceID, 108 Addr: fmt.Sprintf("%s:%d", instanceAddr, instancePort), 109 HeartbeatPeriod: cfg.HeartbeatPeriod, 110 TokensObservePeriod: 0, 111 Zone: cfg.InstanceZone, 112 NumTokens: RingNumTokens, 113 }, nil 114 } 115 116 func (cfg *RingConfig) ToRingConfig() ring.Config { 117 rc := ring.Config{} 118 flagext.DefaultValues(&rc) 119 120 rc.KVStore = cfg.KVStore 121 rc.HeartbeatTimeout = cfg.HeartbeatTimeout 122 rc.ReplicationFactor = cfg.ReplicationFactor 123 rc.ZoneAwarenessEnabled = cfg.ZoneAwarenessEnabled 124 125 return rc 126 }