gopkg.in/hashicorp/nomad.v0@v0.11.8/nomad/autopilot.go (about) 1 package nomad 2 3 import ( 4 "context" 5 "fmt" 6 7 metrics "github.com/armon/go-metrics" 8 "github.com/hashicorp/consul/agent/consul/autopilot" 9 "github.com/hashicorp/raft" 10 "github.com/hashicorp/serf/serf" 11 ) 12 13 const ( 14 // AutopilotRZTag is the Serf tag to use for the redundancy zone value 15 // when passing the server metadata to Autopilot. 16 AutopilotRZTag = "ap_zone" 17 18 // AutopilotRZTag is the Serf tag to use for the custom version value 19 // when passing the server metadata to Autopilot. 20 AutopilotVersionTag = "ap_version" 21 ) 22 23 // AutopilotDelegate is a Nomad delegate for autopilot operations. 24 type AutopilotDelegate struct { 25 server *Server 26 } 27 28 func (d *AutopilotDelegate) AutopilotConfig() *autopilot.Config { 29 c := d.server.getOrCreateAutopilotConfig() 30 if c == nil { 31 return nil 32 } 33 34 conf := &autopilot.Config{ 35 CleanupDeadServers: c.CleanupDeadServers, 36 LastContactThreshold: c.LastContactThreshold, 37 MaxTrailingLogs: c.MaxTrailingLogs, 38 MinQuorum: c.MinQuorum, 39 ServerStabilizationTime: c.ServerStabilizationTime, 40 DisableUpgradeMigration: c.DisableUpgradeMigration, 41 ModifyIndex: c.ModifyIndex, 42 CreateIndex: c.CreateIndex, 43 } 44 45 if c.EnableRedundancyZones { 46 conf.RedundancyZoneTag = AutopilotRZTag 47 } 48 if c.EnableCustomUpgrades { 49 conf.UpgradeVersionTag = AutopilotVersionTag 50 } 51 52 return conf 53 } 54 55 func (d *AutopilotDelegate) FetchStats(ctx context.Context, servers []serf.Member) map[string]*autopilot.ServerStats { 56 return d.server.statsFetcher.Fetch(ctx, servers) 57 } 58 59 func (d *AutopilotDelegate) IsServer(m serf.Member) (*autopilot.ServerInfo, error) { 60 ok, parts := isNomadServer(m) 61 if !ok || parts.Region != d.server.Region() { 62 return nil, nil 63 } 64 65 server := &autopilot.ServerInfo{ 66 Name: m.Name, 67 ID: parts.ID, 68 Addr: parts.Addr, 69 Build: parts.Build, 70 Status: m.Status, 71 } 72 return server, nil 73 } 74 75 // NotifyHealth heartbeats a metric for monitoring if we're the leader. 76 func (d *AutopilotDelegate) NotifyHealth(health autopilot.OperatorHealthReply) { 77 if d.server.raft.State() == raft.Leader { 78 metrics.SetGauge([]string{"nomad", "autopilot", "failure_tolerance"}, float32(health.FailureTolerance)) 79 if health.Healthy { 80 metrics.SetGauge([]string{"nomad", "autopilot", "healthy"}, 1) 81 } else { 82 metrics.SetGauge([]string{"nomad", "autopilot", "healthy"}, 0) 83 } 84 } 85 } 86 87 func (d *AutopilotDelegate) PromoteNonVoters(conf *autopilot.Config, health autopilot.OperatorHealthReply) ([]raft.Server, error) { 88 future := d.server.raft.GetConfiguration() 89 if err := future.Error(); err != nil { 90 return nil, fmt.Errorf("failed to get raft configuration: %v", err) 91 } 92 93 return autopilot.PromoteStableServers(conf, health, future.Configuration().Servers), nil 94 } 95 96 func (d *AutopilotDelegate) Raft() *raft.Raft { 97 return d.server.raft 98 } 99 100 func (d *AutopilotDelegate) SerfLAN() *serf.Serf { 101 return d.server.serf 102 } 103 104 func (d *AutopilotDelegate) SerfWAN() *serf.Serf { 105 // serf WAN isn't supported in nomad yet 106 return nil 107 }