Documentation ¶
Overview ¶
Package client provides bindings for the etcd APIs.
Create a Config and exchange it for a Client:
import ( "net/http" "context" "github.com/meycoin/goetcd/client" ) cfg := client.Config{ Endpoints: []string{"http://127.0.0.1:2379"}, Transport: DefaultTransport, } c, err := client.New(cfg) if err != nil { // handle error }
Clients are safe for concurrent use by multiple goroutines.
Create a KeysAPI using the Client, then use it to interact with etcd:
kAPI := client.NewKeysAPI(c) // create a new key /foo with the value "bar" _, err = kAPI.Create(context.Background(), "/foo", "bar") if err != nil { // handle error } // delete the newly created key only if the value is still "bar" _, err = kAPI.Delete(context.Background(), "/foo", &DeleteOptions{PrevValue: "bar"}) if err != nil { // handle error }
Use a custom context to set timeouts on your operations:
import "time" ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() // set a new key, ignoring its previous state _, err := kAPI.Set(ctx, "/ping", "pong", nil) if err != nil { if err == context.DeadlineExceeded { // request took longer than 5s } else { // handle error } }
Index ¶
- Constants
- Variables
- func DisablecURLDebug()
- func EnablecURLDebug()
- func IsKeyNotFound(err error) bool
- func IsRoleNotFound(err error) bool
- func IsUserNotFound(err error) bool
- type AuthAPI
- type AuthRoleAPI
- type AuthUserAPI
- type CancelableTransport
- type CheckRedirectFunc
- type Client
- type ClusterError
- type Config
- type CreateInOrderOptions
- type DeleteOptions
- type Discoverer
- type EndpointSelectionMode
- type Error
- type GetOptions
- type KeysAPI
- type Member
- type MembersAPI
- type Node
- type Nodes
- type PermissionType
- type Permissions
- type PrevExistType
- type Response
- type Role
- type SetOptions
- type User
- type UserRoles
- type Watcher
- type WatcherOptions
Examples ¶
Constants ¶
const ( ErrorCodeKeyNotFound = 100 ErrorCodeTestFailed = 101 ErrorCodeNotFile = 102 ErrorCodeNotDir = 104 ErrorCodeNodeExist = 105 ErrorCodeRootROnly = 107 ErrorCodeDirNotEmpty = 108 ErrorCodePrevValueRequired = 201 ErrorCodeTTLNaN = 202 ErrorCodeIndexNaN = 203 ErrorCodeInvalidField = 209 ErrorCodeInvalidForm = 210 ErrorCodeRaftInternal = 300 ErrorCodeLeaderElect = 301 ErrorCodeWatcherCleared = 400 ErrorCodeEventIndexCleared = 401 )
const ( PrevIgnore = PrevExistType("") PrevExist = PrevExistType("true") PrevNoExist = PrevExistType("false") )
Variables ¶
var ( ErrNoEndpoints = errors.New("client: no endpoints available") ErrTooManyRedirects = errors.New("client: too many redirects") ErrNoLeaderEndpoint = errors.New("client: no leader endpoint available") )
var ( ErrInvalidJSON = errors.New("client: response is invalid json. The endpoint is probably not valid etcd cluster endpoint.") ErrEmptyBody = errors.New("client: response body is empty") )
var DefaultRequestTimeout = 5 * time.Second
Functions ¶
func DisablecURLDebug ¶
func DisablecURLDebug()
func EnablecURLDebug ¶
func EnablecURLDebug()
func IsKeyNotFound ¶
IsKeyNotFound returns true if the error code is ErrorCodeKeyNotFound.
func IsRoleNotFound ¶
IsRoleNotFound returns true if the error means role not found of v2 API.
func IsUserNotFound ¶
IsUserNotFound returns true if the error means user not found of v2 API.
Types ¶
type AuthAPI ¶
type AuthAPI interface { // Enable auth. Enable(ctx context.Context) error // Disable auth. Disable(ctx context.Context) error }
func NewAuthAPI ¶
NewAuthAPI constructs a new AuthAPI that uses HTTP to interact with etcd's general auth features.
type AuthRoleAPI ¶
type AuthRoleAPI interface { // AddRole adds a role. AddRole(ctx context.Context, role string) error // RemoveRole removes a role. RemoveRole(ctx context.Context, role string) error // GetRole retrieves role details. GetRole(ctx context.Context, role string) (*Role, error) // GrantRoleKV grants a role some permission prefixes for the KV store. GrantRoleKV(ctx context.Context, role string, prefixes []string, permType PermissionType) (*Role, error) // RevokeRoleKV revokes some permission prefixes for a role on the KV store. RevokeRoleKV(ctx context.Context, role string, prefixes []string, permType PermissionType) (*Role, error) // ListRoles lists roles. ListRoles(ctx context.Context) ([]string, error) }
func NewAuthRoleAPI ¶
func NewAuthRoleAPI(c Client) AuthRoleAPI
NewAuthRoleAPI constructs a new AuthRoleAPI that uses HTTP to interact with etcd's role creation and modification features.
type AuthUserAPI ¶
type AuthUserAPI interface { // AddUser adds a user. AddUser(ctx context.Context, username string, password string) error // RemoveUser removes a user. RemoveUser(ctx context.Context, username string) error // GetUser retrieves user details. GetUser(ctx context.Context, username string) (*User, error) // GrantUser grants a user some permission roles. GrantUser(ctx context.Context, username string, roles []string) (*User, error) // RevokeUser revokes some permission roles from a user. RevokeUser(ctx context.Context, username string, roles []string) (*User, error) // ChangePassword changes the user's password. ChangePassword(ctx context.Context, username string, password string) (*User, error) // ListUsers lists the users. ListUsers(ctx context.Context) ([]string, error) }
func NewAuthUserAPI ¶
func NewAuthUserAPI(c Client) AuthUserAPI
NewAuthUserAPI constructs a new AuthUserAPI that uses HTTP to interact with etcd's user creation and modification features.
type CancelableTransport ¶
type CancelableTransport interface { http.RoundTripper CancelRequest(req *http.Request) }
CancelableTransport mimics net/http.Transport, but requires that the object also support request cancellation.
type CheckRedirectFunc ¶
var DefaultCheckRedirect CheckRedirectFunc = func(via int) error { if via > 10 { return ErrTooManyRedirects } return nil }
DefaultCheckRedirect follows up to 10 redirects, but no more.
type Client ¶
type Client interface { // Sync updates the internal cache of the etcd cluster's membership. Sync(context.Context) error // AutoSync periodically calls Sync() every given interval. // The recommended sync interval is 10 seconds to 1 minute, which does // not bring too much overhead to server and makes client catch up the // cluster change in time. // // The example to use it: // // for { // err := client.AutoSync(ctx, 10*time.Second) // if err == context.DeadlineExceeded || err == context.Canceled { // break // } // log.Print(err) // } AutoSync(context.Context, time.Duration) error // Endpoints returns a copy of the current set of API endpoints used // by Client to resolve HTTP requests. If Sync has ever been called, // this may differ from the initial Endpoints provided in the Config. Endpoints() []string // SetEndpoints sets the set of API endpoints used by Client to resolve // HTTP requests. If the given endpoints are not valid, an error will be // returned SetEndpoints(eps []string) error // GetVersion retrieves the current etcd server and cluster version GetVersion(ctx context.Context) (*version.Versions, error) // contains filtered or unexported methods }
type ClusterError ¶
type ClusterError struct {
Errors []error
}
func (*ClusterError) Detail ¶
func (ce *ClusterError) Detail() string
func (*ClusterError) Error ¶
func (ce *ClusterError) Error() string
type Config ¶
type Config struct { // Endpoints defines a set of URLs (schemes, hosts and ports only) // that can be used to communicate with a logical etcd cluster. For // example, a three-node cluster could be provided like so: // // Endpoints: []string{ // "http://node1.example.com:2379", // "http://node2.example.com:2379", // "http://node3.example.com:2379", // } // // If multiple endpoints are provided, the Client will attempt to // use them all in the event that one or more of them are unusable. // // If Client.Sync is ever called, the Client may cache an alternate // set of endpoints to continue operation. Endpoints []string // Transport is used by the Client to drive HTTP requests. If not // provided, DefaultTransport will be used. Transport CancelableTransport // CheckRedirect specifies the policy for handling HTTP redirects. // If CheckRedirect is not nil, the Client calls it before // following an HTTP redirect. The sole argument is the number of // requests that have already been made. If CheckRedirect returns // an error, Client.Do will not make any further requests and return // the error back it to the caller. // // If CheckRedirect is nil, the Client uses its default policy, // which is to stop after 10 consecutive requests. CheckRedirect CheckRedirectFunc // Username specifies the user credential to add as an authorization header Username string // Password is the password for the specified user to add as an authorization header // to the request. Password string // HeaderTimeoutPerRequest specifies the time limit to wait for response // header in a single request made by the Client. The timeout includes // connection time, any redirects, and header wait time. // // For non-watch GET request, server returns the response body immediately. // For PUT/POST/DELETE request, server will attempt to commit request // before responding, which is expected to take `100ms + 2 * RTT`. // For watch request, server returns the header immediately to notify Client // watch start. But if server is behind some kind of proxy, the response // header may be cached at proxy, and Client cannot rely on this behavior. // // Especially, wait request will ignore this timeout. // // One API call may send multiple requests to different etcd servers until it // succeeds. Use context of the API to specify the overall timeout. // // A HeaderTimeoutPerRequest of zero means no timeout. HeaderTimeoutPerRequest time.Duration // SelectionMode is an EndpointSelectionMode enum that specifies the // policy for choosing the etcd cluster node to which requests are sent. SelectionMode EndpointSelectionMode }
type CreateInOrderOptions ¶
type CreateInOrderOptions struct { // TTL defines a period of time after-which the Node should // expire and no longer exist. Values <= 0 are ignored. Given // that the zero-value is ignored, TTL cannot be used to set // a TTL of 0. TTL time.Duration }
func (*CreateInOrderOptions) CodecDecodeSelf ¶
func (x *CreateInOrderOptions) CodecDecodeSelf(d *codec1978.Decoder)
func (*CreateInOrderOptions) CodecEncodeSelf ¶
func (x *CreateInOrderOptions) CodecEncodeSelf(e *codec1978.Encoder)
type DeleteOptions ¶
type DeleteOptions struct { // PrevValue specifies what the current value of the Node must // be in order for the Delete operation to succeed. // // Leaving this field empty means that the caller wishes to // ignore the current value of the Node. This cannot be used // to compare the Node's current value to an empty string. PrevValue string // PrevIndex indicates what the current ModifiedIndex of the // Node must be in order for the Delete operation to succeed. // // If PrevIndex is set to 0 (default), no comparison is made. PrevIndex uint64 // Recursive defines whether or not all children of the Node // should be deleted. If set to true, all children of the Node // identified by the given key will be deleted. If left unset // or explicitly set to false, only a single Node will be // deleted. Recursive bool // Dir specifies whether or not this Node should be removed as a directory. Dir bool }
func (*DeleteOptions) CodecDecodeSelf ¶
func (x *DeleteOptions) CodecDecodeSelf(d *codec1978.Decoder)
func (*DeleteOptions) CodecEncodeSelf ¶
func (x *DeleteOptions) CodecEncodeSelf(e *codec1978.Encoder)
type Discoverer ¶
type Discoverer interface { // Discover looks up the etcd servers for the domain. Discover(domain string) ([]string, error) }
Discoverer is an interface that wraps the Discover method.
func NewSRVDiscover ¶
func NewSRVDiscover() Discoverer
NewSRVDiscover constructs a new Discoverer that uses the stdlib to lookup SRV records.
type EndpointSelectionMode ¶
type EndpointSelectionMode int
const ( // EndpointSelectionRandom is the default value of the 'SelectionMode'. // As the name implies, the client object will pick a node from the members // of the cluster in a random fashion. If the cluster has three members, A, B, // and C, the client picks any node from its three members as its request // destination. EndpointSelectionRandom EndpointSelectionMode = iota // If 'SelectionMode' is set to 'EndpointSelectionPrioritizeLeader', // requests are sent directly to the cluster leader. This reduces // forwarding roundtrips compared to making requests to etcd followers // who then forward them to the cluster leader. In the event of a leader // failure, however, clients configured this way cannot prioritize among // the remaining etcd followers. Therefore, when a client sets 'SelectionMode' // to 'EndpointSelectionPrioritizeLeader', it must use 'client.AutoSync()' to // maintain its knowledge of current cluster state. // // This mode should be used with Client.AutoSync(). EndpointSelectionPrioritizeLeader )
type Error ¶
type Error struct { Code int `json:"errorCode"` Message string `json:"message"` Cause string `json:"cause"` Index uint64 `json:"index"` }
func (*Error) CodecDecodeSelf ¶
func (*Error) CodecEncodeSelf ¶
type GetOptions ¶
type GetOptions struct { // Recursive defines whether or not all children of the Node // should be returned. Recursive bool // Sort instructs the server whether or not to sort the Nodes. // If true, the Nodes are sorted alphabetically by key in // ascending order (A to z). If false (default), the Nodes will // not be sorted and the ordering used should not be considered // predictable. Sort bool // Quorum specifies whether it gets the latest committed value that // has been applied in quorum of members, which ensures external // consistency (or linearizability). Quorum bool }
func (*GetOptions) CodecDecodeSelf ¶
func (x *GetOptions) CodecDecodeSelf(d *codec1978.Decoder)
func (*GetOptions) CodecEncodeSelf ¶
func (x *GetOptions) CodecEncodeSelf(e *codec1978.Encoder)
type KeysAPI ¶
type KeysAPI interface { // Get retrieves a set of Nodes from etcd Get(ctx context.Context, key string, opts *GetOptions) (*Response, error) // Set assigns a new value to a Node identified by a given key. The caller // may define a set of conditions in the SetOptions. If SetOptions.Dir=true // then value is ignored. Set(ctx context.Context, key, value string, opts *SetOptions) (*Response, error) // Delete removes a Node identified by the given key, optionally destroying // all of its children as well. The caller may define a set of required // conditions in an DeleteOptions object. Delete(ctx context.Context, key string, opts *DeleteOptions) (*Response, error) // Create is an alias for Set w/ PrevExist=false Create(ctx context.Context, key, value string) (*Response, error) // CreateInOrder is used to atomically create in-order keys within the given directory. CreateInOrder(ctx context.Context, dir, value string, opts *CreateInOrderOptions) (*Response, error) // Update is an alias for Set w/ PrevExist=true Update(ctx context.Context, key, value string) (*Response, error) // Watcher builds a new Watcher targeted at a specific Node identified // by the given key. The Watcher may be configured at creation time // through a WatcherOptions object. The returned Watcher is designed // to emit events that happen to a Node, and optionally to its children. Watcher(key string, opts *WatcherOptions) Watcher }
Example (Directory) ¶
c, err := client.New(client.Config{ Endpoints: exampleEndpoints, Transport: exampleTransport, }) if err != nil { log.Fatal(err) } kapi := client.NewKeysAPI(c) // Setting '/myNodes' to create a directory that will hold some keys. o := client.SetOptions{Dir: true} resp, err := kapi.Set(context.Background(), "/myNodes", "", &o) if err != nil { log.Fatal(err) } // Add keys to /myNodes directory. resp, err = kapi.Set(context.Background(), "/myNodes/key1", "value1", nil) if err != nil { log.Fatal(err) } resp, err = kapi.Set(context.Background(), "/myNodes/key2", "value2", nil) if err != nil { log.Fatal(err) } // fetch directory resp, err = kapi.Get(context.Background(), "/myNodes", nil) if err != nil { log.Fatal(err) } // print directory keys sort.Sort(resp.Node.Nodes) for _, n := range resp.Node.Nodes { fmt.Printf("Key: %q, Value: %q\n", n.Key, n.Value) }
Output: Key: "/myNodes/key1", Value: "value1" Key: "/myNodes/key2", Value: "value2"
Example (Setget) ¶
c, err := client.New(client.Config{ Endpoints: exampleEndpoints, Transport: exampleTransport, }) if err != nil { log.Fatal(err) } kapi := client.NewKeysAPI(c) // Set key "/foo" to value "bar". resp, err := kapi.Set(context.Background(), "/foo", "bar", nil) if err != nil { log.Fatal(err) } // Get key "/foo" resp, err = kapi.Get(context.Background(), "/foo", nil) if err != nil { log.Fatal(err) } fmt.Printf("%q key has %q value\n", resp.Node.Key, resp.Node.Value)
Output: "/foo" key has "bar" value
func NewKeysAPI ¶
NewKeysAPI builds a KeysAPI that interacts with etcd's key-value API over HTTP.
func NewKeysAPIWithPrefix ¶
NewKeysAPIWithPrefix acts like NewKeysAPI, but allows the caller to provide a custom base URL path. This should only be used in very rare cases.
type Member ¶
type Member struct { // ID is the unique identifier of this Member. ID string `json:"id"` // Name is a human-readable, non-unique identifier of this Member. Name string `json:"name"` // PeerURLs represents the HTTP(S) endpoints this Member uses to // participate in etcd's consensus protocol. PeerURLs []string `json:"peerURLs"` // ClientURLs represents the HTTP(S) endpoints on which this Member // serves its client-facing APIs. ClientURLs []string `json:"clientURLs"` }
type MembersAPI ¶
type MembersAPI interface { // List enumerates the current cluster membership. List(ctx context.Context) ([]Member, error) // Add instructs etcd to accept a new Member into the cluster. Add(ctx context.Context, peerURL string) (*Member, error) // Remove demotes an existing Member out of the cluster. Remove(ctx context.Context, mID string) error // Update instructs etcd to update an existing Member in the cluster. Update(ctx context.Context, mID string, peerURLs []string) error // Leader gets current leader of the cluster Leader(ctx context.Context) (*Member, error) }
func NewMembersAPI ¶
func NewMembersAPI(c Client) MembersAPI
NewMembersAPI constructs a new MembersAPI that uses HTTP to interact with etcd's membership API.
type Node ¶
type Node struct { // Key represents the unique location of this Node (e.g. "/foo/bar"). Key string `json:"key"` // Dir reports whether node describes a directory. Dir bool `json:"dir,omitempty"` // Value is the current data stored on this Node. If this Node // is a directory, Value will be empty. Value string `json:"value"` // Nodes holds the children of this Node, only if this Node is a directory. // This slice of will be arbitrarily deep (children, grandchildren, great- // grandchildren, etc.) if a recursive Get or Watch request were made. Nodes Nodes `json:"nodes"` // CreatedIndex is the etcd index at-which this Node was created. CreatedIndex uint64 `json:"createdIndex"` // ModifiedIndex is the etcd index at-which this Node was last modified. ModifiedIndex uint64 `json:"modifiedIndex"` // Expiration is the server side expiration time of the key. Expiration *time.Time `json:"expiration,omitempty"` // TTL is the time to live of the key in second. TTL int64 `json:"ttl,omitempty"` }
func (*Node) CodecDecodeSelf ¶
func (*Node) CodecEncodeSelf ¶
func (*Node) TTLDuration ¶
TTLDuration returns the Node's TTL as a time.Duration object
type PermissionType ¶
type PermissionType int
const ( ReadPermission PermissionType = iota WritePermission ReadWritePermission )
type Permissions ¶
type Permissions struct {
KV rwPermission `json:"kv"`
}
type PrevExistType ¶
type PrevExistType string
PrevExistType is used to define an existence condition when setting or deleting Nodes.
func (*PrevExistType) CodecDecodeSelf ¶
func (x *PrevExistType) CodecDecodeSelf(d *codec1978.Decoder)
func (PrevExistType) CodecEncodeSelf ¶
func (x PrevExistType) CodecEncodeSelf(e *codec1978.Encoder)
type Response ¶
type Response struct { // Action is the name of the operation that occurred. Possible values // include get, set, delete, update, create, compareAndSwap, // compareAndDelete and expire. Action string `json:"action"` // Node represents the state of the relevant etcd Node. Node *Node `json:"node"` // PrevNode represents the previous state of the Node. PrevNode is non-nil // only if the Node existed before the action occurred and the action // caused a change to the Node. PrevNode *Node `json:"prevNode"` // Index holds the cluster-level index at the time the Response was generated. // This index is not tied to the Node(s) contained in this Response. Index uint64 `json:"-"` // ClusterID holds the cluster-level ID reported by the server. This // should be different for different etcd clusters. ClusterID string `json:"-"` }
func (*Response) CodecDecodeSelf ¶
func (*Response) CodecEncodeSelf ¶
type Role ¶
type Role struct { Role string `json:"role"` Permissions Permissions `json:"permissions"` Grant *Permissions `json:"grant,omitempty"` Revoke *Permissions `json:"revoke,omitempty"` }
type SetOptions ¶
type SetOptions struct { // PrevValue specifies what the current value of the Node must // be in order for the Set operation to succeed. // // Leaving this field empty means that the caller wishes to // ignore the current value of the Node. This cannot be used // to compare the Node's current value to an empty string. // // PrevValue is ignored if Dir=true PrevValue string // PrevIndex indicates what the current ModifiedIndex of the // Node must be in order for the Set operation to succeed. // // If PrevIndex is set to 0 (default), no comparison is made. PrevIndex uint64 // PrevExist specifies whether the Node must currently exist // (PrevExist) or not (PrevNoExist). If the caller does not // care about existence, set PrevExist to PrevIgnore, or simply // leave it unset. PrevExist PrevExistType // TTL defines a period of time after-which the Node should // expire and no longer exist. Values <= 0 are ignored. Given // that the zero-value is ignored, TTL cannot be used to set // a TTL of 0. TTL time.Duration // Refresh set to true means a TTL value can be updated // without firing a watch or changing the node value. A // value must not be provided when refreshing a key. Refresh bool // Dir specifies whether or not this Node should be created as a directory. Dir bool // NoValueOnSuccess specifies whether the response contains the current value of the Node. // If set, the response will only contain the current value when the request fails. NoValueOnSuccess bool }
func (*SetOptions) CodecDecodeSelf ¶
func (x *SetOptions) CodecDecodeSelf(d *codec1978.Decoder)
func (*SetOptions) CodecEncodeSelf ¶
func (x *SetOptions) CodecEncodeSelf(e *codec1978.Encoder)
type Watcher ¶
type Watcher interface { // Next blocks until an etcd event occurs, then returns a Response // representing that event. The behavior of Next depends on the // WatcherOptions used to construct the Watcher. Next is designed to // be called repeatedly, each time blocking until a subsequent event // is available. // // If the provided context is cancelled, Next will return a non-nil // error. Any other failures encountered while waiting for the next // event (connection issues, deserialization failures, etc) will // also result in a non-nil error. Next(context.Context) (*Response, error) }
type WatcherOptions ¶
type WatcherOptions struct { // AfterIndex defines the index after-which the Watcher should // start emitting events. For example, if a value of 5 is // provided, the first event will have an index >= 6. // // Setting AfterIndex to 0 (default) means that the Watcher // should start watching for events starting at the current // index, whatever that may be. AfterIndex uint64 // Recursive specifies whether or not the Watcher should emit // events that occur in children of the given keyspace. If set // to false (default), events will be limited to those that // occur for the exact key. Recursive bool }
func (*WatcherOptions) CodecDecodeSelf ¶
func (x *WatcherOptions) CodecDecodeSelf(d *codec1978.Decoder)
func (*WatcherOptions) CodecEncodeSelf ¶
func (x *WatcherOptions) CodecEncodeSelf(e *codec1978.Encoder)
Source Files ¶
Directories ¶
Path | Synopsis |
---|---|
Package integration implements tests built upon embedded etcd, focusing on the correctness of the etcd v2 client.
|
Package integration implements tests built upon embedded etcd, focusing on the correctness of the etcd v2 client. |