github.imxd.top/hashicorp/consul@v1.4.5/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  }