github.com/criteo-forks/consul@v1.4.5-criteonogrpc/api/operator_autopilot.go (about) 1 package api 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "strconv" 8 "strings" 9 "time" 10 ) 11 12 // AutopilotConfiguration is used for querying/setting the Autopilot configuration. 13 // Autopilot helps manage operator tasks related to Consul servers like removing 14 // failed servers from the Raft quorum. 15 type AutopilotConfiguration struct { 16 // CleanupDeadServers controls whether to remove dead servers from the Raft 17 // peer list when a new server joins 18 CleanupDeadServers bool 19 20 // LastContactThreshold is the limit on the amount of time a server can go 21 // without leader contact before being considered unhealthy. 22 LastContactThreshold *ReadableDuration 23 24 // MaxTrailingLogs is the amount of entries in the Raft Log that a server can 25 // be behind before being considered unhealthy. 26 MaxTrailingLogs uint64 27 28 // ServerStabilizationTime is the minimum amount of time a server must be 29 // in a stable, healthy state before it can be added to the cluster. Only 30 // applicable with Raft protocol version 3 or higher. 31 ServerStabilizationTime *ReadableDuration 32 33 // (Enterprise-only) RedundancyZoneTag is the node tag to use for separating 34 // servers into zones for redundancy. If left blank, this feature will be disabled. 35 RedundancyZoneTag string 36 37 // (Enterprise-only) DisableUpgradeMigration will disable Autopilot's upgrade migration 38 // strategy of waiting until enough newer-versioned servers have been added to the 39 // cluster before promoting them to voters. 40 DisableUpgradeMigration bool 41 42 // (Enterprise-only) UpgradeVersionTag is the node tag to use for version info when 43 // performing upgrade migrations. If left blank, the Consul version will be used. 44 UpgradeVersionTag string 45 46 // CreateIndex holds the index corresponding the creation of this configuration. 47 // This is a read-only field. 48 CreateIndex uint64 49 50 // ModifyIndex will be set to the index of the last update when retrieving the 51 // Autopilot configuration. Resubmitting a configuration with 52 // AutopilotCASConfiguration will perform a check-and-set operation which ensures 53 // there hasn't been a subsequent update since the configuration was retrieved. 54 ModifyIndex uint64 55 } 56 57 // ServerHealth is the health (from the leader's point of view) of a server. 58 type ServerHealth struct { 59 // ID is the raft ID of the server. 60 ID string 61 62 // Name is the node name of the server. 63 Name string 64 65 // Address is the address of the server. 66 Address string 67 68 // The status of the SerfHealth check for the server. 69 SerfStatus string 70 71 // Version is the Consul version of the server. 72 Version string 73 74 // Leader is whether this server is currently the leader. 75 Leader bool 76 77 // LastContact is the time since this node's last contact with the leader. 78 LastContact *ReadableDuration 79 80 // LastTerm is the highest leader term this server has a record of in its Raft log. 81 LastTerm uint64 82 83 // LastIndex is the last log index this server has a record of in its Raft log. 84 LastIndex uint64 85 86 // Healthy is whether or not the server is healthy according to the current 87 // Autopilot config. 88 Healthy bool 89 90 // Voter is whether this is a voting server. 91 Voter bool 92 93 // StableSince is the last time this server's Healthy value changed. 94 StableSince time.Time 95 } 96 97 // OperatorHealthReply is a representation of the overall health of the cluster 98 type OperatorHealthReply struct { 99 // Healthy is true if all the servers in the cluster are healthy. 100 Healthy bool 101 102 // FailureTolerance is the number of healthy servers that could be lost without 103 // an outage occurring. 104 FailureTolerance int 105 106 // Servers holds the health of each server. 107 Servers []ServerHealth 108 } 109 110 // ReadableDuration is a duration type that is serialized to JSON in human readable format. 111 type ReadableDuration time.Duration 112 113 func NewReadableDuration(dur time.Duration) *ReadableDuration { 114 d := ReadableDuration(dur) 115 return &d 116 } 117 118 func (d *ReadableDuration) String() string { 119 return d.Duration().String() 120 } 121 122 func (d *ReadableDuration) Duration() time.Duration { 123 if d == nil { 124 return time.Duration(0) 125 } 126 return time.Duration(*d) 127 } 128 129 func (d *ReadableDuration) MarshalJSON() ([]byte, error) { 130 return []byte(fmt.Sprintf(`"%s"`, d.Duration().String())), nil 131 } 132 133 func (d *ReadableDuration) UnmarshalJSON(raw []byte) error { 134 if d == nil { 135 return fmt.Errorf("cannot unmarshal to nil pointer") 136 } 137 138 str := string(raw) 139 if len(str) < 2 || str[0] != '"' || str[len(str)-1] != '"' { 140 return fmt.Errorf("must be enclosed with quotes: %s", str) 141 } 142 dur, err := time.ParseDuration(str[1 : len(str)-1]) 143 if err != nil { 144 return err 145 } 146 *d = ReadableDuration(dur) 147 return nil 148 } 149 150 // AutopilotGetConfiguration is used to query the current Autopilot configuration. 151 func (op *Operator) AutopilotGetConfiguration(q *QueryOptions) (*AutopilotConfiguration, error) { 152 r := op.c.newRequest("GET", "/v1/operator/autopilot/configuration") 153 r.setQueryOptions(q) 154 _, resp, err := requireOK(op.c.doRequest(r)) 155 if err != nil { 156 return nil, err 157 } 158 defer resp.Body.Close() 159 160 var out AutopilotConfiguration 161 if err := decodeBody(resp, &out); err != nil { 162 return nil, err 163 } 164 165 return &out, nil 166 } 167 168 // AutopilotSetConfiguration is used to set the current Autopilot configuration. 169 func (op *Operator) AutopilotSetConfiguration(conf *AutopilotConfiguration, q *WriteOptions) error { 170 r := op.c.newRequest("PUT", "/v1/operator/autopilot/configuration") 171 r.setWriteOptions(q) 172 r.obj = conf 173 _, resp, err := requireOK(op.c.doRequest(r)) 174 if err != nil { 175 return err 176 } 177 resp.Body.Close() 178 return nil 179 } 180 181 // AutopilotCASConfiguration is used to perform a Check-And-Set update on the 182 // Autopilot configuration. The ModifyIndex value will be respected. Returns 183 // true on success or false on failures. 184 func (op *Operator) AutopilotCASConfiguration(conf *AutopilotConfiguration, q *WriteOptions) (bool, error) { 185 r := op.c.newRequest("PUT", "/v1/operator/autopilot/configuration") 186 r.setWriteOptions(q) 187 r.params.Set("cas", strconv.FormatUint(conf.ModifyIndex, 10)) 188 r.obj = conf 189 _, resp, err := requireOK(op.c.doRequest(r)) 190 if err != nil { 191 return false, err 192 } 193 defer resp.Body.Close() 194 195 var buf bytes.Buffer 196 if _, err := io.Copy(&buf, resp.Body); err != nil { 197 return false, fmt.Errorf("Failed to read response: %v", err) 198 } 199 res := strings.Contains(buf.String(), "true") 200 201 return res, nil 202 } 203 204 // AutopilotServerHealth 205 func (op *Operator) AutopilotServerHealth(q *QueryOptions) (*OperatorHealthReply, error) { 206 r := op.c.newRequest("GET", "/v1/operator/autopilot/health") 207 r.setQueryOptions(q) 208 _, resp, err := requireOK(op.c.doRequest(r)) 209 if err != nil { 210 return nil, err 211 } 212 defer resp.Body.Close() 213 214 var out OperatorHealthReply 215 if err := decodeBody(resp, &out); err != nil { 216 return nil, err 217 } 218 return &out, nil 219 }