github.com/zoomfoo/nomad@v0.8.5-0.20180907175415-f28fd3a1a056/nomad/autopilot.go (about) 1 package nomad 2 3 import ( 4 "context" 5 "fmt" 6 7 "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 ServerStabilizationTime: c.ServerStabilizationTime, 39 DisableUpgradeMigration: c.DisableUpgradeMigration, 40 ModifyIndex: c.ModifyIndex, 41 CreateIndex: c.CreateIndex, 42 } 43 44 if c.EnableRedundancyZones { 45 conf.RedundancyZoneTag = AutopilotRZTag 46 } 47 if c.EnableCustomUpgrades { 48 conf.UpgradeVersionTag = AutopilotVersionTag 49 } 50 51 return conf 52 } 53 54 func (d *AutopilotDelegate) FetchStats(ctx context.Context, servers []serf.Member) map[string]*autopilot.ServerStats { 55 return d.server.statsFetcher.Fetch(ctx, servers) 56 } 57 58 func (d *AutopilotDelegate) IsServer(m serf.Member) (*autopilot.ServerInfo, error) { 59 ok, parts := isNomadServer(m) 60 if !ok || parts.Region != d.server.Region() { 61 return nil, nil 62 } 63 64 server := &autopilot.ServerInfo{ 65 Name: m.Name, 66 ID: parts.ID, 67 Addr: parts.Addr, 68 Build: parts.Build, 69 Status: m.Status, 70 } 71 return server, nil 72 } 73 74 // NotifyHealth heartbeats a metric for monitoring if we're the leader. 75 func (d *AutopilotDelegate) NotifyHealth(health autopilot.OperatorHealthReply) { 76 if d.server.raft.State() == raft.Leader { 77 metrics.SetGauge([]string{"nomad", "autopilot", "failure_tolerance"}, float32(health.FailureTolerance)) 78 if health.Healthy { 79 metrics.SetGauge([]string{"nomad", "autopilot", "healthy"}, 1) 80 } else { 81 metrics.SetGauge([]string{"nomad", "autopilot", "healthy"}, 0) 82 } 83 } 84 } 85 86 func (d *AutopilotDelegate) PromoteNonVoters(conf *autopilot.Config, health autopilot.OperatorHealthReply) ([]raft.Server, error) { 87 future := d.server.raft.GetConfiguration() 88 if err := future.Error(); err != nil { 89 return nil, fmt.Errorf("failed to get raft configuration: %v", err) 90 } 91 92 return autopilot.PromoteStableServers(conf, health, future.Configuration().Servers), nil 93 } 94 95 func (d *AutopilotDelegate) Raft() *raft.Raft { 96 return d.server.raft 97 } 98 99 func (d *AutopilotDelegate) Serf() *serf.Serf { 100 return d.server.serf 101 }