Compare commits

...

1011 Commits

Author SHA1 Message Date
66722b1ada version: bump up to 3.2.0
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-06-09 10:59:09 -07:00
963339d265 rafthttp: permit very large v2 snapshots
v2 snapshots were hitting the 512MB message decode limit, causing
sending snapshots to new members to fail for being too big.
2017-06-09 10:49:51 -07:00
c87594f27c etcdserver: use same ReadView for read-only txns
A read-only txn isn't serialized by raft, but it uses a fresh
read txn for every mvcc access prior to executing its request ops.
If a write txn modifies the keys matching the read txn's comparisons,
the read txn may return inconsistent results.

To fix, use the same read-only mvcc txn for the duration of the etcd
txn. Probably gets a modest txn speedup as well since there are
fewer read txn allocations.
2017-06-09 09:50:43 -07:00
e72ad5dd2a mvcc: create TxnWrites from TxnRead with NewReadOnlyTxnWrite
Already used internally by mvcc, but needed by etcdserver txns.
2017-06-09 09:50:37 -07:00
3eb5d24cab integration: test txn comparison and concurrent put ordering 2017-06-09 09:50:30 -07:00
8b9041a938 Documentation/op-guide: do not use host network, fix indentation
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-06-09 09:14:21 -07:00
864ffec88c v2http: put back /v2/machines and mark as non-deprecated
This reverts commit 2bb33181b6. python-etcd
seems to depend on /v2/machines and the maintainer vanished. Plus, it is
prefixed with /v2/ so it probably can't be deprecated anyway.
2017-06-08 12:05:59 -07:00
12bc2bba36 etcdserver: add leaseExpired debugging metrics
Fix https://github.com/coreos/etcd/issues/8050.

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-06-08 11:23:12 -07:00
3a43afce5a Documentation/op-guide: fix 'grpc_code' field in metrics
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-06-08 10:16:07 -07:00
0e56ea37e7 fileutil: return immediately if preallocating 0 bytes
fallocate will return EINVAL, causing zeroing to the end of a
0 byte file to fail.

Fixes #8045
2017-06-07 12:59:35 -07:00
743192aa3b *: clear rarer shellcheck errors on scripts
Clean up the tail of the warnings
2017-06-06 10:44:59 -07:00
e8b156578f travis: add shellcheck 2017-06-06 10:44:53 -07:00
61f3338ce7 test: shellcheck 2017-06-06 10:44:46 -07:00
effffdbdca test, osutil: disable setting SIG_DFL on linux if built with cov tag
Was causing etcd to terminate before finishing writing its
coverage profile.
2017-06-06 09:47:22 -07:00
9bac803bee Documentation/op-guide: fix typo in grafana.json
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-06-06 09:47:15 -07:00
9169ad0d7d *: fix go tool vet -all -shadow errors 2017-06-06 09:47:06 -07:00
482a7839d9 test: speedup and strengthen go vet checking
Was iterating over every file, reloading everything. Instead,
analyze the package directories. On my machine, the time for
vet checking goes from 34s to 3s. Scans more code too.
2017-06-06 09:46:54 -07:00
ba3058ca79 op-guide: document CN certs in security.md 2017-06-06 09:46:47 -07:00
0e90e504f5 scripts, Documentation: fix swagger generation
Changes to the genproto to support splitting out the grpc-gateway broke
swagger generation.
2017-06-02 11:05:21 -07:00
998fa0de76 Documentation, scripts: regen RPC docs
Was missing the new cancel_reason field. Also includes updated protodoc
sha to fix generating documentation for upcoming txn compare range patchset.
2017-06-02 10:27:49 -07:00
c273735729 op-guide: document configuration flags for gateway 2017-06-01 15:59:49 -07:00
c85f736522 mvcc: time restore in restore benchmark
This never worked.
2017-06-01 14:59:31 -07:00
a375ff172e mvcc: chunk reads for restoring
Loading all keys at once would cause etcd to use twice as much
memory than it would need to serve the keys, causing RSS to spike on
boot. Instead, load the keys into the mvcc by chunk. Uses pipelining
for some concurrency.

Fixes #7822
2017-06-01 14:59:27 -07:00
1893af9bbd integration: use unixs:// if client port configured for tls 2017-06-01 09:47:08 -07:00
b4c655677a clientv3: support unixs:// scheme
For using TLS without giving a TLSConfig to the client.
2017-06-01 09:47:03 -07:00
c2160adf1d clientv3/integration: test dialing to TLS without a TLS config times out
etcdctl was getting ctx errors from timing out trying to issue RPCs to
a TLS endpoint but without using TLS for transmission. Client should
immediately bail out with a time out error.
2017-06-01 09:46:57 -07:00
5ada311416 clientv3: use Endpoints[0] to initialize grpc creds
Dialing out without specifying TLS creds but giving https uses some
default behavior that depends on passing an endpoint with https to
Dial(), so it's not enough to completely rely on the balancer to supply
endpoints.

Fixes #8008

Also ctx-izes grpc.Dial
2017-06-01 09:46:48 -07:00
f042cd7d9c vendor: ghodss/yaml v1.0.0 2017-05-30 14:44:30 -07:00
f0a400a3a8 vendor: kr/pty v1.0.0 2017-05-30 14:44:23 -07:00
6066977280 op-guide: update performance.md
It's been a year, time to refresh with 3.2.0 data.
2017-05-30 10:16:19 -07:00
fc88eccc74 vendor: use v0.2.0 of go-semver 2017-05-30 10:15:23 -07:00
5cb28a7d83 Documentation: add 'yaml.NewConfig' change in 3.2
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-30 10:14:55 -07:00
de57e88643 Documentation: add FAQ entry for "database space exceeded" errors
Also moves miscategorized cluster id mismatch entry from "performance"
to "operation".
2017-05-26 09:13:13 -07:00
967fc70173 Merge pull request #7983 from heyitsanthony/etcdctl-lock-exec
etcdctl: support exec on lock
2017-05-25 10:26:48 -07:00
4a8d32eaa6 Merge pull request #7984 from gyuho/3.2
*: bump up test Go runtime, etcd versions before 3.2 release
2017-05-24 17:20:48 -07:00
643c2a310d etcdctl: support exec on lock
The lock command is clumsy to use from the command line, needing mkfifo,
wait, etc. Instead, make like consul and support launching a command if
one is given.
2017-05-24 16:47:00 -07:00
c3a191b38d e2e: use version.Cluster for release test
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-24 15:20:18 -07:00
83efd2c745 ROADMAP: make 'release-3.2' stable branch
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-24 14:31:43 -07:00
307331cc31 test: release tests with v3.2+
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-24 14:31:30 -07:00
2abd22a13b travis: run tests with Go 1.8.3
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-24 14:28:33 -07:00
2a4db4307f Merge pull request #7982 from heyitsanthony/watch-latency-clients
benchmark: support multiple clients/conns in watch-latency benchmark
2017-05-24 13:23:07 -07:00
ebd6e8c4b1 benchmark: support multiple clients/conns in watch-latency benchmark 2017-05-24 11:31:43 -07:00
8c1ab62bc5 Merge pull request #7975 from raoofm/patch-11
doc: modify vonage usecase, adding kubernetes and vault
2017-05-24 10:40:47 -07:00
8d2b340629 Merge pull request #7966 from heyitsanthony/close-kv-err
etcdserver: close mvcc.KV on init error path
2017-05-23 12:59:20 -07:00
0b449a24bb Merge pull request #7956 from gyuho/container-linux
Documentation: add systemd, Container Linux guide
2017-05-23 12:38:37 -07:00
a1804390b1 doc: modify usecase
adding kubernetes and vault
2017-05-23 14:57:10 -04:00
8b290c680a Documentation: add systemd, Container Linux guide
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-23 11:27:27 -07:00
c1c9a2c96c etcdserver: close mvcc.KV on init error path
Scheduled compaction will panic if KV is not stopped before
closing the backend.
2017-05-23 10:41:37 -07:00
f75e333264 Merge pull request #7958 from heyitsanthony/perm-prefix
etcdctl: improve role --prefix flag
2017-05-22 12:19:16 -07:00
378bac79e1 Merge pull request #7963 from tlossen/patch-1
documentation: fixed typo
2017-05-22 08:29:25 -07:00
20a747ea09 Documentation/learning: fixed typo
(repeated word)
2017-05-22 17:26:34 +02:00
4cd5e7ebb2 Merge pull request #7809 from mitake/auth-watch
protect watch with auth
2017-05-20 13:23:30 +09:00
881903b6d3 e2e: add a new test case for protecting watch with auth 2017-05-20 11:34:45 +09:00
939912c425 clientv3, etcdserver: support auth in Watch() 2017-05-20 11:34:45 +09:00
cbd3807b30 Merge pull request #7959 from heyitsanthony/regen-protodoc
Documentation, scripts: regenerate protobuf docs with updated protodoc
2017-05-19 15:20:44 -07:00
10b1ba7886 Documentation, scripts: regenerate protobuf docs with updated protodoc 2017-05-19 14:57:16 -07:00
2f1467cb27 etcdctl: sync README with etcdctl role command, add prefix example, fix typo
Fixes #7951
2017-05-19 13:53:46 -07:00
bd680c3302 ctlv3: add --prefix support to role revoke-permission, cleanup role flag handling 2017-05-19 13:53:46 -07:00
fd7de051a4 version: bump up to 3.2.0-rc.1+git
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-19 12:39:23 -07:00
9d7ed0e63a version: bump up to 3.2.0-rc.1
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-19 11:46:15 -07:00
b82ef007f5 Merge pull request #7955 from gyuho/timeout
integration: bump up 'TestV3LeaseRequireLeader' timeout to 5-sec
2017-05-18 17:11:23 -07:00
29bbcdd110 integration: bump up 'TestV3LeaseRequireLeader' timeout to 5-sec
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-18 16:44:57 -07:00
0afc51c762 Merge pull request #7939 from gyuho/test
etcd-tester: add '-failpoints' to configure gofail
2017-05-18 12:53:07 -07:00
4a8fbb9d5d Merge pull request #7954 from gyuho/m
*: remove unused, fix typos
2017-05-18 12:36:24 -07:00
d690634bd6 *: remove unused, fix typos
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-18 12:11:18 -07:00
62b44a85f8 etcd-tester: add '-failpoints' to configure gofail
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-18 11:59:07 -07:00
e7d705b25f Merge pull request #7953 from gyuho/aaa
etcd-tester: use 'debugutil.PProfHandlers'
2017-05-18 11:26:40 -07:00
e1640cc72f etcd-tester: use 'debugutil.PProfHandlers'
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-18 11:21:24 -07:00
a6a1eb8378 Merge pull request #7949 from heyitsanthony/godocs
*: fill out missing package godocs
2017-05-18 10:23:26 -07:00
33c375dc44 *: fill out blank package godocs
Mostly one-liner short descriptions, but also includes some typo fixes
and some examples.
2017-05-18 09:41:13 -07:00
1f2dcbb935 Merge pull request #7948 from heyitsanthony/remove-proxy-alpha
op-guide: remove alpha from grpc proxy
2017-05-18 09:31:34 -07:00
c6cf88ef7f op-guide: remove alpha from grpc proxy 2017-05-17 22:27:06 -07:00
4e84bd2e3c Merge pull request #7946 from heyitsanthony/report-weighted
report: add NewWeightedReport
2017-05-17 21:04:53 -07:00
c09f0ca9d4 report: add NewWeightedReport
Reports with weighted results.
2017-05-17 16:07:20 -07:00
218ee40f11 Merge pull request #7945 from xiang90/snapshot_error
etcdserver: more logging on snapshot close path
2017-05-17 15:36:53 -07:00
32c252f003 etcdserver: more logging on snapshot close path 2017-05-17 14:48:52 -07:00
f4641accc3 Merge pull request #7943 from heyitsanthony/tcpproxy-init-msg
tcpproxy: display endpoints, not pointers, in ready to proxy string
2017-05-17 12:20:46 -07:00
b7cda38653 Merge pull request #7935 from heyitsanthony/bridge-latency
bridge: add tx-delay and rx-delay
2017-05-17 11:07:22 -07:00
5bd9b9614f tcpproxy: display endpoints, not pointers, in ready to proxy string
The switch to *net.SRV for endpoints caused the ready string to emit
pointers instead of endpoint strings.

Fixes #7942
2017-05-17 10:51:35 -07:00
201fd70afc Merge pull request #7934 from heyitsanthony/bench-rpc-mutex
benchmark: add rpc mutexes to stm benchmark
2017-05-17 10:44:00 -07:00
1763f7d4d1 Merge pull request #7919 from gyuho/log-dir
functional-tester: use log-dir as data-dir in etcd-agent
2017-05-16 13:46:57 -07:00
271785cd55 Merge pull request #7937 from heyitsanthony/e2e-close-timeout
e2e: Stop() lock/elect etcdctl process if Close times out
2017-05-16 12:34:36 -07:00
8f0d4092c3 e2e: Stop() lock/elect etcdctl process if Close times out
Gets backtrace by sending SIGQUIT if Close hangs after sending a SIGINT.
2017-05-16 11:31:23 -07:00
c6219a209d Merge pull request #7933 from gyuho/travis
travis: test builds in other OSes
2017-05-15 22:25:52 -07:00
22db11f876 bridge: add tx-delay and rx-delay
Injects transmit and receive latencies.
2017-05-15 17:02:27 -07:00
d826f95c77 travis: test builds in other OSes
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-15 16:55:27 -07:00
b6e4858a25 benchmark: add rate limiting to stm 2017-05-15 15:42:54 -07:00
6526097bfc benchmark: add rpc locks to stm benchmark 2017-05-15 15:42:26 -07:00
3e7feb4033 Merge pull request #7931 from gyuho/aaa
pkg/osutil: fix missing 'syscall' import
2017-05-15 14:47:46 -07:00
fba225cee5 pkg/osutil: fix missing 'syscall' import
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-15 14:11:54 -07:00
95078c296d Merge pull request #7932 from gyuho/vet
*: remove unnecessary fmt.Sprint
2017-05-15 14:01:23 -07:00
e15020055e *: remove unnecessary fmt.Sprint
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-15 13:23:31 -07:00
74fd7709ad Merge pull request #7904 from heyitsanthony/osutil-exit
osutil: force SIG_DFL before resending terminating signal
2017-05-15 12:14:37 -07:00
31e3899663 Merge pull request #7925 from heyitsanthony/fix-windows-mmap
backend: force initial mmap size to 0 for windows
2017-05-13 21:42:58 -07:00
8516d8ccc5 backend: force initial mmap size to 0 for windows
boltdb on windows allocates a file with the full mmap size even if the
db is empty. Force the initial mmap size to 0 so there's no huge initial
db file on windows.

Fixes #7910
2017-05-12 14:34:07 -07:00
6ce9aed8c5 Merge pull request #7881 from heyitsanthony/testctl-logging
e2e: more debugging output for lock and elect tests
2017-05-12 12:01:08 -07:00
7a1739a3e8 osutil: force SIG_DFL before resending terminating signal
The go runtime won't always reinstall the default signal handler on the
SIGTERM path, so it's possible the signal won't terminate the process.
Instead, force SIG_DFL for the signal.
2017-05-12 11:56:27 -07:00
5b4677b7d7 integration: reset default logging level in TestRestartRemoved 2017-05-12 10:22:29 -07:00
b9f5a00b13 e2e: more debugging output for lock and elect etcdctl tests
Meant to debug #6464 and #6934

Dumps the output from the etcd/etcdctl servers and SIGQUITs to get a
golang backtrace in case of a hanged process.
2017-05-12 10:22:29 -07:00
90893735cf Merge pull request #7917 from heyitsanthony/refactor-backend-paths
snap, etcdserver: tighten up snapshot path handling
2017-05-12 09:33:37 -07:00
2e3d27e910 functional-tester: use log-dir as data-dir in etcd-agent
Persistent data should be configured in agent side.
There is no need to specify the data-dir in tester side.

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-12 08:30:46 -07:00
f337754e72 Merge pull request #7914 from fanminshi/doc_snap_warning
*: faq for snapshot warning and dynamically determining snapshotWarningTimeout
2017-05-11 16:48:12 -07:00
aa58aff18c Merge pull request #7918 from gyuho/archive-path
etcd-agent: store failure_archive in log dir
2017-05-11 16:34:43 -07:00
0bcab05465 etcd-agent: store failure_archive in log dir
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-11 16:30:04 -07:00
71d7c85b6b expect: reload DEBUG_EXPECT for each process
Lets e2e test cases selectively turn on expect debugging to get
full application output written to stdout.
2017-05-11 16:09:31 -07:00
16e92d1379 faq: explains "snapshotting is taking more..." warning 2017-05-11 15:25:44 -07:00
8468b38631 backend: dynamically set snapshotWarningTimeout based on db size 2017-05-11 15:25:35 -07:00
7a65cb5847 Merge pull request #7916 from heyitsanthony/snip-extra-doc
clientv3: remove duplicate documentation for Do()
2017-05-11 14:45:35 -07:00
f6cd4d4f5b snap, etcdserver: tighten up snapshot path handling
Computing the snapshot file path is error prone; snapshot recovery was
constructing file paths missing a path separator so the snapshot
would never be loaded. Instead, refactor the backend path handling
to use helper functions where possible.
2017-05-11 13:46:59 -07:00
63c7e9f840 clientv3: remove duplicate documentation for Do() 2017-05-11 13:25:26 -07:00
f63eb2f6a4 Merge pull request #7913 from gyuho/srv
pkg/srv: fix error checks from resolveTCPAddr
2017-05-11 12:12:01 -07:00
3505c254e1 pkg/srv: fix error checks from resolveTCPAddr
So that 'terr' can be returned later.

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-11 10:53:03 -07:00
386374a6d0 Merge pull request #7908 from heyitsanthony/concurrency-proxy
grpcproxy: forward v3lock and v3election requests
2017-05-10 16:41:06 -07:00
066062a5e0 Merge pull request #7902 from fanminshi/fix_runner
etcd-runner: remove mutex on validate() and release() in global.go
2017-05-10 13:12:09 -07:00
00da3ca725 integration: add lock and election services to proxy tests 2017-05-10 13:06:27 -07:00
713e006bc6 adpater: adapters for lock and election services 2017-05-10 12:51:05 -07:00
fd01db9e60 grpcproxy, etcdmain: add lock and election services to proxy 2017-05-10 12:19:09 -07:00
b44bd6d2a9 etcd-runner: fix race on nextc 2017-05-10 11:21:17 -07:00
47f5b7c3ad Merge pull request #7876 from fanminshi/fix_7628
etcdserver: renaming db happens after snapshot persists to wal and snap files
2017-05-09 16:15:41 -07:00
87d99fe038 etcd-runner: remove mutex on validate() and release() in global.go
election runner can deadlock in atomic release().

suppose election runner has two clients A and B.
if A is a leader and B is a follower, B obtains lock
for release() and waits for A to close(nextc) which signal
next round is ready. However, A can only close(nextc) if it
obtains lock for release(); hence deadlock.

this pr removes atomicity of validate() and release() in global.go
and gives the responsibility of locking to each runner.

FIXES #7891
2017-05-09 15:38:13 -07:00
dfdaf082c5 etcdserver: add a test to ensure renaming db happens before persisting wal and snap files 2017-05-09 14:00:22 -07:00
8b7b7222dd etcdserver: renaming db happens after snapshot persists to wal and snap files
In the case that follower recieves a snapshot from leader
and crashes before renaming xxx.snap.db to db but after
snapshot has persisted to .wal and .snap, restarting
follower results loading old db, new .wal, and new .snap.
This will causes a index mismatch between snap metadata index
and consistent index from db.

This pr forces an ordering where saving/renaming db must
happen after snapshot is persisted to wal and snap file.
this guarantees wal and snap files are newer than db.
on server restart, etcd server checks if snap index > db consistent index.
if yes, etcd server attempts to load xxx.snap.db where xxx=snap index
if there is any and panic other wise.

FIXES #7628
2017-05-09 14:00:12 -07:00
a53a9e167e Merge pull request #7898 from yudai/nit_remove_dup
v3rpc: remove duplicated error case for lease.ErrLeaseNotFound
2017-05-09 12:35:31 -07:00
b8875515a4 Merge pull request #7890 from yudai/keep_ka_loop_running
clientv3: Do no stop keep alive loop by server side errors
2017-05-09 11:00:21 -07:00
01a985eda5 Merge pull request #7897 from gyuho/bom
scripts: add 'BOM' update script
2017-05-09 10:52:42 -07:00
010ffc0692 v3rpc: remove duplicated error case for lease.ErrLeaseNotFound 2017-05-08 20:09:41 -07:00
8c9f01ef53 scripts: add 'BOM' update script
Need this script when we add external dependencies.

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-08 17:59:11 -07:00
aa85b0cea7 clientv3: Do no stop keep alive loop by server side errors 2017-05-08 15:47:34 -07:00
aac2292ab5 Merge pull request #7882 from heyitsanthony/srv-priority
gateway: DNS SRV priority
2017-05-08 14:17:04 -07:00
3a2e7653f2 Merge pull request #7879 from gyuho/http-server
embed: gracefully close peer handler
2017-05-08 14:00:45 -07:00
c232814003 etcdmain, tcpproxy: srv-priority policy
Adds DNS SRV weighting and priorities to gateway.

Partially addresses #4378
2017-05-08 11:35:18 -07:00
2655540481 Merge pull request #7892 from fanminshi/add_snashot_duration_metric
backend: add prometheus metric for large snapshot duration.
2017-05-08 11:22:51 -07:00
25eef5a6e4 Merge pull request #7893 from philips/readme-tagline
README: use the same tagline from github
2017-05-08 09:11:08 -07:00
7d21d6c894 embed: gracefully close peer handlers on shutdown
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-06 07:47:23 -07:00
af7d051019 Merge pull request #7885 from luedigernet/fix-TestEvent
Fix watch_test.go TestEvent
2017-05-05 23:31:59 -07:00
90af2ff302 README: use the same tagline from github
Just be consistent with the messaging and use of etcd
2017-05-05 18:07:26 -07:00
230106dd3c backend: add prometheus metric for large snapshot duration.
FIXES #7878
2017-05-05 17:27:33 -07:00
8b081ce9b3 clientv3: check IsModify
Fix watch_test.go TestEvent

Prior to This fix the isModify case of the table driven test was never checked.
2017-05-05 19:39:59 +02:00
07ad18178d pkg/srv: package for SRV utilities
Trying to decouple the v2 client from SRV code. Can't move
into discovery/ since that creates a circular dependency. So,
give up and move all the SRV code into a new package.
2017-05-05 09:27:59 -07:00
db6f45e939 Merge pull request #7830 from aaronlehmann/new-nodes-start-active
raft: Set the RecentActive flag for newly added nodes
2017-05-05 08:59:25 -07:00
1f8de1aab0 Merge pull request #7877 from fanminshi/warning_on_snapshotting
backend: print snapshotting duration warning every 30s
2017-05-04 18:03:47 -07:00
f7f30f2361 backend: print snapshotting duration warning every 30s
FIXES #7870
2017-05-04 16:41:03 -07:00
9451fa1f9c raft: Add unit test TestAddNodeCheckQuorum
This test verifies that adding a node does not cause the leader to step
down until at least one full ElectionTick cycle elapses.

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
2017-05-04 15:04:30 -07:00
c3b96f8a69 Merge pull request #7875 from yudai/compact_every_time
compactor: Make periodic compactor runs every hour
2017-05-04 13:24:27 -07:00
60dbad5a85 compactor: Make periodic compactor runs every hour
Closes #7868.
2017-05-04 10:32:51 -07:00
505bf8c708 Merge pull request #7864 from gyuho/doc-link-fixes
*: run 'marker' in CI
2017-05-04 09:14:06 -07:00
2e32d2142d Merge pull request #7869 from heyitsanthony/fix-lease-require-leader-test
clientv3/integration: drain keepalives before waiting for leader loss
2017-05-04 08:29:16 -07:00
282c6fd17d Documentation: remove '[]' from '[DEPRECATED]'
To make 'marker' pass the tests

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-04 08:26:01 -07:00
c2959c998f test: run 'marker' to find broken links
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-04 08:26:00 -07:00
e9a63473a0 scripts,travis: install 'marker' for CI tests
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-04 08:26:00 -07:00
7f05e220a4 Merge pull request #7874 from gyuho/scripts
integration/fixtures-expired: do not force 'rm'
2017-05-03 19:39:00 -07:00
4edbae4a91 integration/fixtures-expired: do not force 'rm'
To make gencerts.sh script safer.

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-03 18:45:44 -07:00
3b251b0ed3 Merge pull request #7871 from gyuho/fix-doc-2
*: fix broken links in markdown
2017-05-03 16:58:38 -07:00
4203320d04 *: fix other broken links in markdown
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-03 16:57:44 -07:00
feb930e357 Documentation/v3: fix broken links
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-03 16:57:38 -07:00
e4e057f8f7 Documentation/v2: fix broken links
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-03 15:37:53 -07:00
9fee35b02d Merge pull request #7842 from heyitsanthony/fix-switch-race
clientv3: don't race on upc/downc/switch endpoints in balancer
2017-05-03 13:48:00 -07:00
f6d0dda187 clientv3/integration: drain keepalives before waiting for leader loss
500ms keepalive delay on proxy side causes client to sometimes send
a second keepalive since it waits more than 500ms for the first response.

Fixes #7658
2017-05-03 13:22:45 -07:00
8f40517adb integration: close proxy's lease client 2017-05-03 13:22:24 -07:00
61c5a0c6ae Merge pull request #7867 from gyuho/fix-tls-test
integration: clean up TLS reload tests, fix no-file while renaming
2017-05-03 12:43:41 -07:00
85fa594265 integration: clean up TLS reload tests, fix no-file while renaming
Fix https://github.com/coreos/etcd/issues/7865.

It is also possible to have mis-matched key file
while renaming directories.

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-03 11:59:09 -07:00
c2d6a92b01 Merge pull request #7853 from gyuho/revert
Documentation/upgrades: revert KeepAlive interface change
2017-05-03 11:04:15 -07:00
24e85b2454 Merge pull request #7852 from heyitsanthony/revert-lease-err-ka
Revert "Merge pull request #7732 from heyitsanthony/lease-err-ka"
2017-05-03 11:03:17 -07:00
27b3bf230b Merge pull request #7863 from heyitsanthony/stm-apis
concurrency: provide old STM functions as deprecated
2017-05-03 10:19:13 -07:00
de2e959b27 Merge pull request #7856 from fanminshi/fix_consistent_index_update
etcdserver: apply() sets consistIndex for any entry type
2017-05-03 09:07:16 -07:00
31d5d610fc concurrency: provide old STM functions as deprecated
semver
2017-05-03 02:07:01 -07:00
e33b10a666 etcdserver: add a test to ensure config change also update ConsistIndex 2017-05-02 16:51:40 -07:00
61abf25859 integration: close accepted connection on stopc path
Connection pausing added another exit condition in the listener
path, causing the bridge to leak connections instead of closing
them when signalled to close. Also adds some additional Close
paranoia.

Fixes #7823
2017-05-02 16:46:43 -07:00
43e5f892f6 clientv3: don't race on upc/downc/switch endpoints in balancer
If the balancer update notification loop starts with a downed
connection and endpoints are switched while the old connection is up,
the balancer can potentially wait forever for an up connection without
refreshing the connections to reflect the current endpoints.

Instead, fetch upc/downc together, only caring about a single transition
either from down->up or up->down for each iteration

Simple way to reproduce failures: add time.Sleep(time.Second) to the
beginning of the update notification loop.
2017-05-02 16:43:24 -07:00
5533c3058a etcdserver: apply() sets consistIndex for any entry type
previously, apply() doesn't set consistIndex for EntryConfChange type.
this causes a misalignment between consistIndex and applied index
where EntryConfChange entry results setting applied index but not consistIndex.

suppose that addMember() is called and leader reflects that change.
1. applied index and consistIndex is now misaligned.
2. a new follower node joined.
3. leader sends the snapshot to follower
	where the applied index is the snapshot metadata index.
4. follower node saves the snapshot and database(includes consistIndex) from leader.
5. restarting follower loads snapshot and database.
6. follower checks snapshot metadata index(same as applied index) and database consistIndex,
	finds them don't match, and then panic.

FIXES #7834
2017-05-02 14:57:36 -07:00
72d2adca62 Merge pull request #7854 from gyuho/lease-retry
integration: ensure revoke completes before TimeToLive
2017-05-02 12:56:56 -07:00
01b6cdf13d integration: ensure revoke completes before TimeToLive
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-02 12:56:26 -07:00
24f0423088 Merge pull request #7855 from tessr/master
raft: add chain core to notable users list
2017-05-02 11:30:03 -07:00
3d504737e4 add chain core to raft users list 2017-05-02 11:23:25 -07:00
bb42ba5f4e Documentation/upgrades: revert KeepAlive interface change
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-02 09:45:06 -07:00
6dd8fb6f24 Revert "Merge pull request #7732 from heyitsanthony/lease-err-ka"
This reverts commit fbbc4a4979, reversing
changes made to f254e38385.

Fixes #7851
2017-05-02 09:36:16 -07:00
fdf445b5a0 Merge pull request #7848 from gyuho/close-grpcc
embed: fix blocking Close before gRPC server start
2017-05-01 18:44:20 -07:00
f065d8e258 Merge pull request #7845 from heyitsanthony/single-node-docker
Documentation: add documentation for single node docker etcd
2017-05-01 16:42:19 -07:00
b0e9d24fb6 embed: fix blocking Close before gRPC server start
If 'StartEtcd' returns before starting gRPC server
(e.g. mismatch snapshot, misconfiguration),
receiving from grpcServerC blocks forever. This patch
just closes the channel to not block on grpcServerC,
and proceeds to next stop operations in Close.

This was masking the issues in https://github.com/coreos/etcd/issues/7834

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-05-01 16:41:13 -07:00
b1720b779c Merge pull request #7846 from heyitsanthony/build-aci-annotate
scripts: annotate with acbuild with supports-systemd-notify
2017-05-01 16:04:03 -07:00
6c1ce697a6 scripts: annotate with acbuild with supports-systemd-notify
Fixes #7840
2017-05-01 12:59:08 -07:00
3f1f5e5215 Merge pull request #7844 from heyitsanthony/v2-docker-tag
Documentation/v2: pin docker guide to use latest 2.3.x
2017-05-01 12:54:03 -07:00
b8f08d400d Documentation: add documentation for single node docker etcd
Fixes #7843
2017-05-01 12:36:16 -07:00
066f9bf7e3 Documentation/v2: pin docker guide to use latest 2.3.x 2017-05-01 11:46:39 -07:00
f0ca65a95d version: bump up to 3.2.0-rc.0+git 2017-04-28 11:06:53 -07:00
7e6d876385 version: bump up to 3.2.0-rc.0 2017-04-28 10:09:39 -07:00
7239249155 Merge pull request #7837 from gyuho/tls-errors
integration: match more TLS errors for wrong certs
2017-04-28 10:08:34 -07:00
cfeab9324e integration: match more TLS errors for wrong certs
Fix https://github.com/coreos/etcd/issues/7835.

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-28 10:03:29 -07:00
77fd369b1c Merge pull request #7832 from gyuho/doc-for-3.2
Documentation: add upgrade to 3.2 doc
2017-04-27 21:27:26 -07:00
cbd7ef4ee6 Documentation: add upgrade to 3.2 doc
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-27 14:39:42 -07:00
747993de08 Merge pull request #7829 from gyuho/certs
pkg/transport: reload TLS certificates for every client requests
2017-04-27 14:36:53 -07:00
96d6f05391 Merge pull request #7831 from gyuho/cc
pkg/wait: add comment and make List private
2017-04-27 13:45:25 -07:00
22943e7e06 integration: test TLS reload
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-27 13:32:09 -07:00
d818ef2c76 pkg/wait: add comment and make List private 2017-04-27 13:25:02 -07:00
4e21f87e3d pkg/transport: reload TLS certificates for every client requests
This changes the baseConfig used when creating tls Configs to utilize
the GetCertificate and GetClientCertificate functions to always reload
the certificates from disk whenever they are needed.

Always reloading the certificates allows changing the certificates via
an external process without interrupting etcd.

Fixes #7576

Cherry-picked by Gyu-Ho Lee <gyuhox@gmail.com>
Original commit can be found at https://github.com/coreos/etcd/pull/7784
2017-04-27 11:22:03 -07:00
52613b262b raft: Set the RecentActive flag for newly added nodes
I found that enabling the CheckQuorum flag led to spurious leader
elections when new nodes joined. It looks like in the time between a new
node joining the cluster, and that node first communicating with the
leader, the quorum check could fail because the new node looks inactive.
To solve this, set the RecentActive flag when nodes are first added.
This gives a grace period for the node to communicate before it causes
the quorum check to fail.

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
2017-04-27 11:19:29 -07:00
c309d745a6 Merge pull request #7819 from heyitsanthony/fix-elect-compact
concurrency: use current revisions for election
2017-04-27 11:01:44 -07:00
2a3229c00a Merge pull request #7808 from heyitsanthony/auto-bom
CI BOM checking
2017-04-27 09:24:59 -07:00
3e7bd47cd5 travis: add bill-of-materials checking
Fixes #7780
2017-04-26 16:29:48 -07:00
2059c8e9e7 vendor: revendor speakeasy to include unix license file
updates BOM
2017-04-26 16:29:48 -07:00
b77de97136 test: bill of materials check pass 2017-04-26 16:29:47 -07:00
633a0a847b Merge pull request #7824 from gyuho/certs
*: test expired certs in client
2017-04-26 13:31:17 -07:00
f674a1b583 clientv3/integration: test client dial with expired certs
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-26 12:32:46 -07:00
7cb860a31b integration/fixtures: add expired certs
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-26 12:22:54 -07:00
d2e69b339f Merge pull request #7816 from heyitsanthony/v3client-blankctx
v3client: wrap watch ctxs with blank ctx
2017-04-25 21:53:14 -07:00
41e77c9db6 Merge pull request #7818 from gyuho/doc
Documentation: require Go 1.8+ for build
2017-04-25 21:46:07 -07:00
50f29bd661 concurrency: use current revisions for election
Watching from the leader's ModRevision could cause live-locking on
observe retry loops when the ModRevision is less than the compacted
revision. Instead, start watching the leader from at least the store
revision of the linearized read used to detect the current leader.

Fixes #7815
2017-04-25 20:15:50 -07:00
6486be673b integration: test Observe can read leaders set prior to compaction 2017-04-25 20:03:49 -07:00
4959663f90 Documentation: require Go 1.8+ for build
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-25 17:04:54 -07:00
c49a87bd04 Merge pull request #7672 from fanminshi/integrate_runner_to_tester
etcd-tester: integrate etcd runner into etcd tester
2017-04-25 15:22:29 -07:00
60b9adc267 Merge pull request #7812 from fanminshi/refactor_runner
etcd-runner: fix runner and minor refactoring.
2017-04-25 15:21:57 -07:00
3ce31acda4 v3client: wrap watch ctxs with blank ctx
Printing the values in ctx.String() will data race if the value
is mutable and doesn't implement String(), which seems to be common.
Instead, just return a fixed string instead of computing it; v3client
watches don't need as much flexibility for creating separate strings,
so separate ctx strings probably aren't necessary at this point.

Fixes #7811
2017-04-25 15:03:06 -07:00
96aaeee4f5 Merge pull request #7814 from gyuho/aaa
etcdserver: do not block on raft stopping
2017-04-25 15:00:06 -07:00
a9e04061b1 etcd-runner: integrate etcd runner in to etcd tester
etcd tester runs etcd runner as a separate binary.
it signals sigstop to the runner when tester wants to stop stressing.
it signals sigcont to the runner when tester wants to start stressing.
when tester needs to clean up, it signals sigint to runner.

FIXES #7026
2017-04-25 14:53:23 -07:00
77fbe10dfc etcd-runner: add --prefix flag, allows inf round, and minor vars refactoring in watch runner. 2017-04-25 14:18:42 -07:00
debc69e1f2 etcd-runner: pass in lock name as a command arg for lock_racer. 2017-04-25 14:18:42 -07:00
72fb756af3 etcd-runner: add lease ttl as a flag and fatal when err in lease-runner. 2017-04-25 14:18:42 -07:00
d57ad8ec8d etcd-runner: add barrier, observe !ok handling, and election name arg to election-runner. 2017-04-25 14:17:59 -07:00
fa85445ef8 etcd-runner: add rate limiting in doRounds() 2017-04-25 14:00:52 -07:00
327f09fcb4 etcdserver: do not block on raft stopping
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-25 13:35:43 -07:00
2af1605db3 Merge pull request #7810 from gyuho/sync-with-apply
etcdserver: ensure waitForApply sync with applyAll
2017-04-25 13:21:30 -07:00
91f6aee4f2 etcdserver: ensure waitForApply sync with applyAll
Problem is:

`Step1`: `etcdserver/raft.go`'s `Ready` process routine sends config-change entries via `r.applyc <- ap` (https://github.com/coreos/etcd/blob/master/etcdserver/raft.go#L193-L203)

`Step2`: `etcdserver/server.go`'s `*EtcdServer.run` routine receives this via `ap := <-s.r.apply()` (https://github.com/coreos/etcd/blob/master/etcdserver/server.go#L735-L738)

`StepA`: `Step1` proceeds without sync, right after sending `r.applyc <- ap`.

`StepB`: `Step2` proceeds without sync, right after `sched.Schedule(s.applyAll(&ep,&ap))`.

`StepC`: `etcdserver` tries to sync with `s.applyAll(&ep,&ap)` by calling `rh.waitForApply()`.

`rh.waitForApply()` waits for all pending jobs to finish in `pkg/schedule`
side. However, the order of `StepA`,`StepB`,`StepC` is not guaranteed. It
is possible that `StepC` happens first, and proceeds without waiting on
apply. And the restarting member comes back as a leader in single-node
cluster, when there is no synchronization between apply-layer and
config-change Raft entry apply. Confirmed with more debugging lines below,
only reproducible with slow CPU VM (~2 vCPU).

```
~:24.005397 I | etcdserver: starting server... [version: 3.2.0+git, cluster version: to_be_decided]
~:24.011136 I | etcdserver: [DEBUG] 29b2d24047a277df waitForApply before
~:24.011194 I | etcdserver: [DEBUG] 29b2d24047a277df starts wait for 0 pending jobs
~:24.011234 I | etcdserver: [DEBUG] 29b2d24047a277df finished wait for 0 pending jobs (current pending 0)
~:24.011268 I | etcdserver: [DEBUG] 29b2d24047a277df waitForApply after
~:24.011348 I | etcdserver: [DEBUG] [0] 29b2d24047a277df is scheduling conf change on 29b2d24047a277df
~:24.011396 I | etcdserver: [DEBUG] [1] 29b2d24047a277df is scheduling conf change on 5edf80e32a334cf0
~:24.011437 I | etcdserver: [DEBUG] [2] 29b2d24047a277df is scheduling conf change on e32e31e76c8d2678
~:24.011477 I | etcdserver: [DEBUG] 29b2d24047a277df scheduled conf change on 29b2d24047a277df
~:24.011509 I | etcdserver: [DEBUG] 29b2d24047a277df scheduled conf change on 5edf80e32a334cf0
~:24.011545 I | etcdserver: [DEBUG] 29b2d24047a277df scheduled conf change on e32e31e76c8d2678
~:24.012500 I | etcdserver: [DEBUG] 29b2d24047a277df applyConfChange on 29b2d24047a277df before
~:24.013014 I | etcdserver/membership: added member 29b2d24047a277df [unix://127.0.0.1:2100515039] to cluster 9250d4ae34216949
~:24.013066 I | etcdserver: [DEBUG] 29b2d24047a277df applyConfChange on 29b2d24047a277df after
~:24.013113 I | etcdserver: [DEBUG] 29b2d24047a277df applyConfChange on 29b2d24047a277df after trigger
~:24.013158 I | etcdserver: [DEBUG] 29b2d24047a277df applyConfChange on 5edf80e32a334cf0 before
~:24.013666 W | etcdserver: failed to send out heartbeat on time (exceeded the 10ms timeout for 11.964739ms)
~:24.013709 W | etcdserver: server is likely overloaded
~:24.013750 W | etcdserver: failed to send out heartbeat on time (exceeded the 10ms timeout for 12.057265ms)
~:24.013775 W | etcdserver: server is likely overloaded
~:24.013950 I | raft: 29b2d24047a277df is starting a new election at term 4
~:24.014012 I | raft: 29b2d24047a277df became candidate at term 5
~:24.014051 I | raft: 29b2d24047a277df received MsgVoteResp from 29b2d24047a277df at term 5
~:24.014107 I | raft: 29b2d24047a277df became leader at term 5
~:24.014146 I | raft: raft.node: 29b2d24047a277df elected leader 29b2d24047a277df at term 5
```

I am printing out the number of pending jobs before we call
`sched.WaitFinish(0)`, and there was no pending jobs, so it returned
immediately (before we schedule `applyAll`).

This is the root cause to:

- https://github.com/coreos/etcd/issues/7595
- https://github.com/coreos/etcd/issues/7739
- https://github.com/coreos/etcd/issues/7802

`sched.WaitFinish(0)` doesn't work when `len(f.pendings)==0` and
`f.finished==0`. Config-change is the first job to apply, so
`f.finished` is 0 in this case.

`f.finished` monotonically increases, so we need `WaitFinish(finished+1)`.
And `finished` must be the one before calling `Schedule`. This is safe
because `Schedule(applyAll)` is the only place adding jobs to `sched`.
Then scheduler waits on the single job of `applyAll`, by getting the
current number of finished jobs before sending `Schedule`.

Or just make it be blocked until `applyAll` routine triggers on the
config-change job. This patch just removes `waitForApply`, and
signal `raftDone` to wait until `applyAll` finishes applying entries.

Confirmed that it fixes the issue, as below:

```
~:43.198354 I | rafthttp: started streaming with peer 36cda5222aba364b (stream MsgApp v2 reader)
~:43.198740 I | etcdserver: [DEBUG] 3988bc20c2b2e40c waitForApply before
~:43.198836 I | etcdserver: [DEBUG] 3988bc20c2b2e40c starts wait for 0 pending jobs, 1 finished jobs
~:43.200696 I | integration: launched 3169361310155633349 ()
~:43.201784 I | etcdserver: [DEBUG] [0] 3988bc20c2b2e40c is scheduling conf change on 36cda5222aba364b
~:43.201884 I | etcdserver: [DEBUG] [1] 3988bc20c2b2e40c is scheduling conf change on 3988bc20c2b2e40c
~:43.201965 I | etcdserver: [DEBUG] [2] 3988bc20c2b2e40c is scheduling conf change on cf5d6cbc2a121727
~:43.202070 I | etcdserver: [DEBUG] 3988bc20c2b2e40c scheduled conf change on 36cda5222aba364b
~:43.202139 I | etcdserver: [DEBUG] 3988bc20c2b2e40c scheduled conf change on 3988bc20c2b2e40c
~:43.202204 I | etcdserver: [DEBUG] 3988bc20c2b2e40c scheduled conf change on cf5d6cbc2a121727
~:43.202444 I | etcdserver: [DEBUG] 3988bc20c2b2e40c applyConfChange on 36cda5222aba364b (request ID: 0) before
~:43.204486 I | etcdserver/membership: added member 36cda5222aba364b [unix://127.0.0.1:2100913646] to cluster 425d73f1b7b01674
~:43.204588 I | etcdserver: [DEBUG] 3988bc20c2b2e40c applyConfChange on 36cda5222aba364b (request ID: 0) after
~:43.204703 I | etcdserver: [DEBUG] 3988bc20c2b2e40c applyConfChange on 36cda5222aba364b (request ID: 0) after trigger
~:43.204791 I | etcdserver: [DEBUG] 3988bc20c2b2e40c applyConfChange on 3988bc20c2b2e40c (request ID: 0) before
~:43.205689 I | etcdserver/membership: added member 3988bc20c2b2e40c [unix://127.0.0.1:2101113646] to cluster 425d73f1b7b01674
~:43.205783 I | etcdserver: [DEBUG] 3988bc20c2b2e40c applyConfChange on 3988bc20c2b2e40c (request ID: 0) after
~:43.205929 I | etcdserver: [DEBUG] 3988bc20c2b2e40c applyConfChange on 3988bc20c2b2e40c (request ID: 0) after trigger
~:43.206056 I | etcdserver: [DEBUG] 3988bc20c2b2e40c applyConfChange on cf5d6cbc2a121727 (request ID: 0) before
~:43.207353 I | etcdserver/membership: added member cf5d6cbc2a121727 [unix://127.0.0.1:2100713646] to cluster 425d73f1b7b01674
~:43.207516 I | etcdserver: [DEBUG] 3988bc20c2b2e40c applyConfChange on cf5d6cbc2a121727 (request ID: 0) after
~:43.207619 I | etcdserver: [DEBUG] 3988bc20c2b2e40c applyConfChange on cf5d6cbc2a121727 (request ID: 0) after trigger
~:43.207710 I | etcdserver: [DEBUG] 3988bc20c2b2e40c finished scheduled conf change on 36cda5222aba364b
~:43.207781 I | etcdserver: [DEBUG] 3988bc20c2b2e40c finished scheduled conf change on 3988bc20c2b2e40c
~:43.207843 I | etcdserver: [DEBUG] 3988bc20c2b2e40c finished scheduled conf change on cf5d6cbc2a121727
~:43.207951 I | etcdserver: [DEBUG] 3988bc20c2b2e40c finished wait for 0 pending jobs (current pending 0, finished 1)
~:43.208029 I | rafthttp: started HTTP pipelining with peer cf5d6cbc2a121727
~:43.210339 I | rafthttp: peer 3988bc20c2b2e40c became active
~:43.210435 I | rafthttp: established a TCP streaming connection with peer 3988bc20c2b2e40c (stream MsgApp v2 reader)
~:43.210861 I | rafthttp: started streaming with peer 3988bc20c2b2e40c (writer)
~:43.211732 I | etcdserver: [DEBUG] 3988bc20c2b2e40c waitForApply after
```

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-25 10:22:27 -07:00
b94b8b5707 etcd-runner: move root cmd into command package
this allows easier sharing of global variable for sub commands.
2017-04-25 10:19:20 -07:00
fbbc4a4979 Merge pull request #7732 from heyitsanthony/lease-err-ka
clientv3: don't halt lease client if there is a lease error
2017-04-25 07:06:31 -07:00
2fd6df922a integration: close proxy's lease client 2017-04-24 23:49:45 -07:00
cb8524fbec benchmark: use new lease interface 2017-04-24 23:49:45 -07:00
78afc853f4 etcd-runner: update to use new lease interface 2017-04-24 23:49:45 -07:00
b5384ac1c0 grpcproxy: use new lease interface 2017-04-24 23:49:44 -07:00
70f0bbe38c etcdcdtl: use new lease interface 2017-04-24 23:49:44 -07:00
f3053265ae clientv3/integration: use new interfaces in lease tests 2017-04-24 23:49:44 -07:00
f224d74ed7 concurrency: use new lease interface in session 2017-04-24 23:49:44 -07:00
d5f414f69b clientv3: don't halt lease client if there is a lease error
Fixes #7488
2017-04-24 23:49:44 -07:00
f254e38385 Merge pull request #7806 from heyitsanthony/testutil-assert
testutil: assert functions
2017-04-23 01:30:39 -07:00
2ef3eac5ca vendor: remove testify
Fixes #7805
2017-04-22 20:29:58 -07:00
76fb6ebcbb scripts: remove testify hack in updatedep 2017-04-22 20:29:58 -07:00
978cf804ca store: replace testify asserts with testutil asserts 2017-04-22 20:29:58 -07:00
6f06e1cb47 testutil: add assert functions 2017-04-22 20:29:58 -07:00
c5d4f3e7db Merge pull request #7804 from heyitsanthony/current-watch-fix
clientv3: set current revision to create rev regardless of CreateNotify
2017-04-22 14:09:17 -07:00
7f159b6a8d Merge pull request #7803 from heyitsanthony/snip-deprecated-machines
v2http: remove deprecated /v2/machines path
2017-04-22 14:08:55 -07:00
ca4acceb1e clientv3: set current revision to create rev regardless of CreateNotify
Turns out the optimization to ignore setting the init rev for
current revision watches breaks some ordering assumptions. Since
Watch only returns a channel once it gets a response, it should
bind the revision at the time of the first create response.

Was causing TestWatchReconnInit to fail.
2017-04-22 13:04:38 -07:00
94f6a11bbf Merge pull request #7756 from heyitsanthony/weaken-v3elect-test
integration: permit dropping intermediate leader values on observe
2017-04-22 12:13:51 -07:00
c1300c81b3 concurrency: clarify Observe semantics; only fetches subsequence 2017-04-22 11:26:11 -07:00
e6a789d541 integration: permit dropping intermediate leader values on observe
Weaken TestV3ElectionObserve so it only checks that it observes a strictly
monotonically ascending leader transition sequence following the first
observed leader. First, the Observe will issue the leader channel before
getting a response for its first get; the election revision is only bound
after returning the channel. So, Observe can't be expected to always
return the leader at the time it was started.  Second, Observe fetches
the current leader based on its create revision, but begins watching on its
ModRevision; this is important so that elections still work in case the
leader issues proclamations following a compaction that exceeds its
creation revision. So, Observe can't be expected to return the entire
proclamation sequence for a single leader.

Fixes #7749
2017-04-22 11:26:11 -07:00
2bb33181b6 v2http: remove deprecated /v2/machines path 2017-04-22 03:11:21 -07:00
7da451640f Merge pull request #7795 from heyitsanthony/dont-force-initrev
clientv3: only update initReq.rev == 0 with watch revision
2017-04-22 02:50:55 -07:00
4ab818a856 clientv3: only update initReq.rev == 0 with creation watch revision
Always updating the initReq.rev on watch create will resume from the wrong
revision if initReq is ever nonzero.
2017-04-21 20:22:51 -07:00
ec470944f8 clientv3/integration: test watch resume with disconnect before first event 2017-04-21 20:22:51 -07:00
fe1ce3a2f0 integration: add pause/unpause to client bridge
Resetting connections sometimes isn't enough; need to stop/resume
accepting connections for some tests while keeping the member up.
2017-04-21 20:22:51 -07:00
91039bef7c Merge pull request #7799 from heyitsanthony/ctxize-resolve
netutil: use "context" and ctx-ize TCP addr resolution
2017-04-21 16:30:32 -07:00
a73950545a Merge pull request #7801 from heyitsanthony/s1027
*: clear redundant return statement warnings (S1027)
2017-04-21 15:18:40 -07:00
14d6ed9e5f *: clear redundant return statement warnings (S1027) 2017-04-21 14:01:00 -07:00
a9087ee659 Merge pull request #7714 from glevand/for-merge-cross
Add multi arch release support
2017-04-21 10:56:01 -07:00
bf987185a9 release.md: Update for multi arch release
Signed-off-by: Geoff Levand <geoff@infradead.org>
2017-04-21 10:04:41 -07:00
07c07cea25 release: Add multi arch support
Signed-off-by: Geoff Levand <geoff@infradead.org>
2017-04-21 10:04:41 -07:00
0c8988aa07 build-docker: Updates for multi-arch release
o Set -e to abort script if a command fails.
 o Allow custom docker 'TAG' from the environment.
 o Move arch suffix to version to allow all images to
   be put into a single repository.
 o Enable cross builds.  When doing cross builds where the
   host and target architectures are different 'RUN mkdir'
   will fail since the target container cannot be run on
   the host.  To work around this, create the directories
   in build-docker, then use ADD in the Dockerfile.
 o Add Dockerfile-release.arm64

Signed-off-by: Geoff Levand <geoff@infradead.org>
2017-04-21 10:04:41 -07:00
8309ca92d7 build-aci: Add multi arch support
Uses GOARCH to build for a targeted arch.

Usage: GOARCH=... BINARYDIR=... BUILDDIR=... ./scripts/build-aci version

Signed-off-by: Geoff Levand <geoff@infradead.org>
2017-04-21 10:04:41 -07:00
fb6287240f build-binary: Add arm64
Signed-off-by: Geoff Levand <geoff@infradead.org>
2017-04-21 10:04:41 -07:00
85e87e8f6b netutil: use "context" and ctx-ize TCP addr resolution 2017-04-21 10:01:53 -07:00
8bad78cb98 Merge pull request #7788 from gyuho/trace
vendor: use 'x/net/trace' with std 'context'
2017-04-20 18:18:33 -07:00
bfd5f38af3 vendor: use 'x/net/trace' with std 'context'
For https://github.com/coreos/etcd/issues/6174.

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-20 17:28:59 -07:00
3a93928b07 Merge pull request #7779 from heyitsanthony/pkgize-gw
*: put gateway stubs in packages separate from pb stubs
2017-04-20 14:53:56 -07:00
82b7e4fd3b Merge pull request #7786 from gyuho/rate
vendor: update 'golang.org/x/time/rate' with context
2017-04-20 13:51:43 -07:00
da1bba8f39 vendor: update 'golang.org/x/time/rate' with context
Go just updated its import path c06e80d930

For https://github.com/coreos/etcd/issues/6174.

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-20 11:18:34 -07:00
633a4e6b52 Merge pull request #7785 from heyitsanthony/printerize-lease
ctlv3: use printer for lease command results
2017-04-20 10:36:58 -07:00
cf8c66c9f0 ctlv3: use printer for lease command results
Fixes #7783
2017-04-20 09:41:04 -07:00
85c9ea92bb Merge pull request #7745 from heyitsanthony/bom
*: add bill of materials
2017-04-19 15:29:20 -07:00
a2b5444a26 test: ensure clientv3 has no grpc-gateway dependency 2017-04-19 13:09:23 -07:00
393e4335b7 *: put gateway stubs into their own packages
Fixes #7773
2017-04-19 13:09:06 -07:00
fd11523af9 scripts: move gateway stubs into gw/ packages 2017-04-19 12:50:04 -07:00
04fc57ac1d Merge pull request #7775 from heyitsanthony/fix-lease-print
ctlv3: keep lease as integer in fields printer
2017-04-19 09:08:17 -07:00
385e18bc6c Merge pull request #7768 from gyuho/close-serverc
embed: signal 'grpcServerC' before cmux serve
2017-04-19 08:24:22 -07:00
35dff4cbc3 Merge pull request #7769 from heyitsanthony/more-time-lease-test
clientv3/integration: sleep less in TestLeaseRenewLostQuorum
2017-04-19 00:57:49 -07:00
d24a763a12 Merge pull request #7771 from heyitsanthony/remove-2.0-version
etcdserver: remove 2.0 StatusNotFound version check
2017-04-19 00:57:19 -07:00
fcd4871e2a ctlv3: keep lease as integer in fields printer
Output was giving %!d(string=) instead of the expected lease ID
value.
2017-04-19 00:48:13 -07:00
d3456b5ecd Merge pull request #7759 from mitake/fix-7724
*: simply ignore ErrAuthNotEnabled in clientv3 if auth is not enabled
2017-04-19 16:07:18 +09:00
3d8e2e1171 etcdserver: remove 2.0 StatusNotFound version check 2017-04-18 20:22:56 -07:00
c654370d6d clientv3/integration: sleep less in TestLeaseRenewLostQuorum
Server Stop+Restart sometimes takes more than 500ms, so with a
one second window the lease client may not get a chance to issue
a keepalive and get a lease extension before the lease client
timer elapses. Instead, sleep for a shorter period of time (while
still guaranteeing a keepalive resend during quorum loss) and
skip the test if server restart takes longer than the lease TTL.

Fixes #7346
2017-04-18 19:35:20 -07:00
e1306bff8f *: simply ignore ErrAuthNotEnabled in clientv3 if auth is not enabled
Fix https://github.com/coreos/etcd/issues/7724
2017-04-19 11:27:14 +09:00
ba299bcaaf embed: signal 'grpcServerC' before cmux serve
CMux.Serve blocks, so grpcServerC was never closed.

Fix https://github.com/coreos/etcdlabs/issues/216.

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-18 17:49:50 -07:00
8fa4b8da6e Merge pull request #7767 from heyitsanthony/transport-resolve-dnsnames
transport: resolve DNSNames when SAN checking
2017-04-18 17:28:01 -07:00
cb408ace21 Merge pull request #7757 from heyitsanthony/fix-speedy-close
etcdserver: initialize raftNode with constructor
2017-04-18 15:06:45 -07:00
05582ad5b2 transport: resolve DNSNames when SAN checking
The current transport client TLS checking will pass an IP address into
VerifyHostnames if there is DNSNames SAN. However, the go runtime will
not resolve the DNS names to match the client IP. Intead, resolve the
names when checking.
2017-04-18 13:21:26 -07:00
30552e28ed Merge pull request #7766 from gyuho/url
embed: use '*url.URL.Hostname(),Port()' for Go 1.8
2017-04-18 13:16:13 -07:00
f10a70401b embed: use '*url.URL.Hostname(),Port()' for Go 1.8
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-18 12:08:59 -07:00
94044cee4f Merge pull request #7765 from gyuho/mutex-profile
pkg/debugutil: add 'mutex' profiler (Go 1.8+)
2017-04-18 11:34:23 -07:00
5161b74799 pkg/debugutil: add 'mutex' profiler (Go 1.8+)
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-18 10:56:06 -07:00
dd0d590217 Merge pull request #7764 from gyuho/NEWS
NEWS: update v3.1.6
2017-04-18 10:31:13 -07:00
2511535ea0 NEWS: update v3.1.6
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-18 10:09:53 -07:00
714b48a4b4 etcdserver: initialize raftNode with constructor
raftNode was being initialized in start(), which was causing
hangs when trying to stop the etcd server since the stop channel
would not be initialized in time for the stop call. Instead,
setup non-configurable bits in a constructor.

Fixes #7668
2017-04-18 09:33:59 -07:00
8fdf8f752b Merge pull request #7752 from heyitsanthony/clientv3-fetch-keyspace-pfx
clientv3: translate WithPrefix() into WithFromKey() for empty key
2017-04-18 09:24:53 -07:00
6dd807481c Merge pull request #7758 from a-robinson/leak
raft: Avoid holding unneeded memory in unstable log's entries array
2017-04-18 08:27:40 -07:00
45406d8486 raft: Avoid holding unneeded memory in unstable log's entries array
Accumulation of old entries in the underlying array backing the
entries slice has been found to cause massive memory growth in
CockroachDB for workloads that do large (1MB) writes
(https://github.com/cockroachdb/cockroach/issues/14776)

This doesn't appear to have much consistent effect on the raft
benchmarks, although it's worth noting that they vary quite a bit
between runs so it's kind of tough to draw strong conclusions from them.
Let me know if there are any different benchmarks you'd like me to run!

Fixes #7746

benchmark              old ns/op     new ns/op     delta
BenchmarkOneNode-8     3283          3125          -4.81%

benchmark              old allocs     new allocs     delta
BenchmarkOneNode-8     6              6              +0.00%

benchmark              old bytes     new bytes     delta
BenchmarkOneNode-8     796           727           -8.67%

benchmark                     old ns/op     new ns/op     delta
BenchmarkProposal3Nodes-8     4269          4337          +1.59%

benchmark                     old allocs     new allocs     delta
BenchmarkProposal3Nodes-8     15             13             -13.33%

benchmark                     old bytes     new bytes     delta
BenchmarkProposal3Nodes-8     5839          4544          -22.18%
2017-04-18 10:55:16 -04:00
4fcea334ad Merge pull request #7737 from gyuho/aaa
*: clean up for Go 1.8+
2017-04-18 03:37:43 -07:00
8aaa1ed911 *: use '*tls.Config.Clone' in Go 1.8
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-17 20:08:27 -07:00
99a2d6c4b1 integration: use 'time.Until' in Go 1.8
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-17 20:08:27 -07:00
cbe37e5213 travis: bump up to Go 1.8.1
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-17 20:08:27 -07:00
e7e7451213 Merge pull request #7689 from mitake/bench-leader
benchmark: a new flag --target-leader for targetting a leader endpoint
2017-04-18 10:24:24 +09:00
e771c6042b Merge pull request #7743 from gyuho/shutdown-grpc-server
*: use gRPC server GracefulStop
2017-04-17 17:12:52 -07:00
c011e2ddd5 Merge pull request #7755 from gyuho/auth-test
clientv3/integration: add 'TestUserErrorAuth'
2017-04-17 17:12:24 -07:00
81291b23b1 clientv3/integration: add 'TestUserErrorAuth'
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-17 17:11:37 -07:00
c798f81398 Merge pull request #7753 from gyuho/helper
etcdserver: fill-in Auth API Header in apply layer
2017-04-17 15:18:46 -07:00
8a5f085a65 *: add bill of materials 2017-04-17 14:50:55 -07:00
cb979bc2cc vendor: update gopkg.in/yaml.v2 to reflect current license 2017-04-17 14:34:59 -07:00
253e5a90bb integration: test auth API response header revision
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-17 14:26:30 -07:00
ac69e63fa8 etcdserver: fill-in Auth API Header in apply layer
Replacing "etcdserver: fill a response header in auth RPCs"
The revision should be set at the time of "apply",
not in later RPC layer.

Fix https://github.com/coreos/etcd/issues/7691

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-17 14:26:26 -07:00
5000d29b4a mvcc: remove stopc select case in Hash
Revert change in 33acbb694b.

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-17 14:19:48 -07:00
8ffd58fb3b mvcc/backend: remove t.tx.DB()==nil checks with GracefulStop
Revert https://github.com/coreos/etcd/pull/6662.

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-17 14:17:00 -07:00
cd470f9ccd Revert "mvcc: test inflight Hash to trigger Size on nil db"
This reverts commit 994e8e4f40.

Since now etcdserver gracefully shuts down the gRPC server
2017-04-17 14:15:43 -07:00
472a536052 integration: test 'inflight' range requests
- Test https://github.com/coreos/etcd/issues/7322.
- Remove test case added in https://github.com/coreos/etcd/pull/6662.

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-17 14:15:36 -07:00
c407e097e2 embed: gracefully shut down gRPC server
Fix https://github.com/coreos/etcd/issues/7322.

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-17 14:12:40 -07:00
ea5f6dab6b etcdmain: trigger embed.Etcd.Close for OS interrupt
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-17 14:07:16 -07:00
0d52598fc1 Merge pull request #7754 from heyitsanthony/doc-check-v3-data
op-guide: add command for checking if there's any v3 data
2017-04-17 14:05:57 -07:00
cf8ab8c7a6 op-guide: add command for checking if there's any v3 data
Fixes #7681
2017-04-17 12:31:21 -07:00
6b030ed7db benchmark: a new flag --target-leader for targetting a leader endpoint
Current benchmark picks destinations of RPCs in a random
manner. However, it will result divergent benchmarking result because
RPCs other than serializable range must be forwarded to a leader node
when a follower node receives it. This commit adds a new flag
--target-leader for avoid the problem. If the flag is passed,
benchmark always picks an endpoint of a leader node.
2017-04-17 14:24:35 +09:00
6ad9d1609a Merge pull request #7717 from mitake/auth-output-fields
etcdctl: show responses of auth RPCs if --write-output=fields is passed
2017-04-17 14:12:59 +09:00
f92c11e1f2 clientv3: translate WithPrefix() into WithFromKey() for empty key 2017-04-16 20:47:18 -07:00
f0143916de clientv3/integration: test fetching entire keyspace 2017-04-16 20:47:18 -07:00
7e3dd74314 Merge pull request #7748 from darasion/master
clientv3/namespace: fix incorrect watching prefix-end
2017-04-15 15:17:35 -07:00
0e7fd4a37c clientv3/namespace: fix incorrect watching prefix-end
using "abc" will watch the wrong range when WithPrefix() specified.
2017-04-15 22:31:50 +08:00
e2d0db95eb Merge pull request #7744 from heyitsanthony/fix-auth-stop-race
auth: fix race on stopping simple token keeper
2017-04-14 12:38:47 -07:00
2951e7f6e4 Merge pull request #7733 from heyitsanthony/fix-client-foreign-dial
clientv3: let client dial endpoints not in the balancer
2017-04-14 10:45:17 -07:00
fdf7798137 auth: fix race on stopping simple token keeper
run goroutine was resetting a field for no reason and without holding a lock.
This patch cleans up the run goroutine management to make the start/stop path
less racey in general.
2017-04-14 09:50:33 -07:00
8efc42e25f etcdctl: show responses of auth RPCs if --write-output=fields is passed 2017-04-14 11:48:42 +09:00
cfbc5e5c3b Merge pull request #7706 from gyuho/wait-apply-conf-change
etcdserver: wait apply on conf change Raft entry
2017-04-13 16:54:06 -07:00
04354f32ab etcdserver: wait apply on conf change Raft entry
When apply-layer sees configuration change entry in
raft.Ready.CommittedEntries, the server should not proceed
until that entry is applied. Otherwise, follower's raft
layer advances, possibly election-timeouts, and becomes
the leader in single-node cluster, before add-node conf
change of other nodes is applied.

Fix https://github.com/coreos/etcd/issues/7595.

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-13 15:59:24 -07:00
957c9cd1df Merge pull request #7734 from mitake/status-auth
etcdserver: let Status() not require authentication
2017-04-13 15:53:33 -07:00
8fdfac2843 Merge pull request #7730 from heyitsanthony/return-member-list
*: return updated member list in v3 rpcs
2017-04-13 15:39:38 -07:00
1153e1e7d9 Merge pull request #7687 from heyitsanthony/deny-tls-ipsan
transport: deny incoming peer certs with wrong IP SAN
2017-04-13 15:03:25 -07:00
7607ace95a Merge pull request #7735 from gyuho/grpc-shutdown
pkg/transport: add 'IsClosedConnError'
2017-04-13 13:16:57 -07:00
6c2fb5105d clientv3/integration: use 'transport.IsClosedConnError'
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-13 11:55:23 -07:00
56b111df0c rafthttp: use 'transport.IsClosedConnError'
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-13 11:55:22 -07:00
8ce579aac9 pkg/transport: add 'IsClosedConnError'
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-13 11:55:18 -07:00
9eb3e2c6b4 Merge pull request #7736 from gyuho/todo
embed: remove ReadTimeout TODO
2017-04-13 11:40:53 -07:00
0b19921ec0 Merge pull request #7729 from heyitsanthony/fix-auth-token-crash
auth: protect simpleToken with single mutex and check if enabled
2017-04-13 11:23:15 -07:00
537c7100b0 embed: remove ReadTimeout TODO
ref. https://github.com/golang/go/issues/9524#issuecomment-271937649

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-13 10:55:45 -07:00
2dd361aba5 Merge pull request #7694 from heyitsanthony/report-test
report: add test for Report interface
2017-04-13 10:39:55 -07:00
8077be93b8 Merge pull request #7728 from nokia/clients
Adding C++ bindings
2017-04-13 10:05:18 -07:00
b9f9d2e786 Documentation: Adding a separate v2 and a v3 API binding for C++
To draw the attention of the community to these.
2017-04-13 13:15:06 +02:00
67f2e41f20 etcdserver: let Status() not require authentication
The information that can be obtained with the RPC doesn't need to be
protected.

Fix https://github.com/coreos/etcd/issues/7721
2017-04-13 17:39:09 +09:00
4582a7e900 Merge pull request #7731 from heyitsanthony/remove-dead-srv-arg
discovery: remove dead token argument from SRVGetCluster
2017-04-12 20:09:11 -07:00
46971fa1db integration: test client can dial endpoints not in balancer 2017-04-12 20:07:04 -07:00
9b8e39e7ca clientv3: let client.Dial() dial endpoints not in the balancer 2017-04-12 20:07:03 -07:00
e58d39611a Merge pull request #7725 from heyitsanthony/platform-subsection
Documentation: reshuffle op-guide to include platforms and upgrading
2017-04-12 17:05:14 -07:00
780a7d359c discovery: remove dead token argument from SRVGetCluster
Can add the argument back when it's actually used something.
2017-04-12 16:49:44 -07:00
33a0496b5e report: add test for Report interface 2017-04-12 16:41:32 -07:00
d9ec6b4d22 *: return updated member list in v3 rpcs
Now it's possible to atomically know the new member configuration from
issuing a membership change RPC.
2017-04-12 16:24:51 -07:00
68837b9693 Documentation: reshuffle op-guide to include platforms and upgrading 2017-04-12 15:40:53 -07:00
2046d66927 Merge pull request #7715 from gyuho/fmt
tools/benchmark: fix misc gofmt warnings
2017-04-12 14:27:37 -07:00
2d97500e64 test: do not ignore 'tools/benchmark/cmd'
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-12 14:13:30 -07:00
373a04a181 tools/benchmark: fix misc gofmt warnings
ref. https://golang.org/cmd/gofmt/#hdr-The_simplify_command

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-12 14:12:05 -07:00
70a9929b5d transport: use actual certs for listener tests 2017-04-12 13:41:33 -07:00
cad1215b18 *: deny incoming peer certs with wrong IP SAN 2017-04-12 13:41:33 -07:00
18bccb4285 auth: protect simpleToken with single mutex and check if enabled
Dual locking doesn't really give a convincing performance improvement and
the lock ordering makes it impossible to safely check if the TTL keeper
is enabled or not.

Fixes #7722
2017-04-12 13:40:09 -07:00
712f6cb0e1 integration: test requests with valid auth token but disabled auth
etcd was crashing since auth was assuming a token implies auth is enabled.
2017-04-12 13:17:33 -07:00
817825d549 Merge pull request #7726 from smeruelo/fix-doc
Documentation: add missing link
2017-04-12 10:57:02 -07:00
79d27328e3 Documentation: add missing link 2017-04-12 19:50:27 +02:00
95c6c4b713 Merge pull request #7712 from heyitsanthony/stm-sersnap
*: rename Snapshot STM isolation to SerializableSnapshot
2017-04-12 09:03:13 -07:00
4f9aa276bd *: rename Snapshot STM isolation to SerializableSnapshot
Pure Snapshot isolation would permit read conflicts. Change the name
from Snapshot to SerializableSnapshot to reflect that it will also
reject read conflicts.
2017-04-11 17:17:50 -07:00
6ebadda395 Merge pull request #7711 from FranGM/master
Documentation: Add Hosted Graphite to prod users
2017-04-11 13:53:13 -07:00
e521a9116f Merge pull request #7693 from heyitsanthony/why-etcd-doc
Documentation/learning: finish why.md
2017-04-11 13:33:17 -07:00
7684bfdf65 Merge pull request #7704 from heyitsanthony/txn-bench
benchmark: add txn-put benchmark
2017-04-11 12:44:20 -07:00
ce2f65508d Documentation: Add Hosted Graphite to prod users 2017-04-11 20:13:57 +01:00
b4869cb03e Documentation/learning: finish why.md 2017-04-11 12:04:46 -07:00
216a6347b2 Merge pull request #7707 from gyuho/net
vendor: update 'golang.org/x/net'
2017-04-11 09:53:03 -07:00
fd5766bdf6 Merge pull request #7708 from gyuho/rkt
*: coreos/rkt -> rkt/rkt
2017-04-11 09:06:00 -07:00
7fb1f68ff8 *: coreos/rkt -> rkt/rkt
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-11 08:48:48 -07:00
a0dc471520 vendor: update 'golang.org/x/net'
There have been a few bug fixes in upstream.
Mainly for our grpc-go sub-dependencies

'idna' package introduces a new dependency 'golang.org/x/text'

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-11 08:46:07 -07:00
4d1b8b1e47 benchmark: add txn-put benchmark
Submits multiple put ops in a single txn.
2017-04-10 17:01:49 -07:00
7da79de74b Merge pull request #7703 from gyuho/rafthttp
rafthttp: move test-only functions to '_test.go'
2017-04-10 16:59:47 -07:00
b694cfc69f Merge pull request #7702 from heyitsanthony/rpc-swagger
v3lock, v3election: generate and serve grpc-gateway endpoints
2017-04-10 16:48:11 -07:00
d26bdbaf81 Merge pull request #7701 from heyitsanthony/cov-strip-generated
test: remove generated files from coverage statistics
2017-04-10 16:22:15 -07:00
8db8d01712 rafthttp: move test-only functions to '_test.go'
Not used in actual code base, only used in tests

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-10 16:07:31 -07:00
2030c85071 test: ignore v3electionpb and v3lockpb for static checks 2017-04-10 15:21:07 -07:00
93594006df embed: register grpc-gateway endpoints for v3lock and v3election 2017-04-10 15:21:07 -07:00
78a5eb79b5 *: add swagger and grpc-gateway assets for v3lock and v3election 2017-04-10 15:21:07 -07:00
b5dd41e625 test: remove generated files from coverage statistics
client/keys.generated.go has poor coverage but it's generated; other
generated files (e.g., pb stuff) are ignored, so this should be ignored too.
2017-04-10 14:30:15 -07:00
a1a72202ff Merge pull request #7666 from calebamiles/aws-platform-guide
Adds AWS platform guide
2017-04-10 14:14:52 -07:00
2a074523a4 Documentation: Adds AWS platform guide
Add guide for deployed etcd on AWS discussing resource planning and cluster design
2017-04-10 13:09:33 -07:00
25acdbf41b Merge pull request #7634 from heyitsanthony/election-rpc
Election RPC service
2017-04-07 20:03:09 -07:00
55e2355326 Merge pull request #7695 from heyitsanthony/upgrade-grpc-gateway
vendor: upgrade grpc-gateway to v1.2.0
2017-04-07 19:04:00 -07:00
5f366db7d1 etcd-runner: update election command to use new Leader() interface 2017-04-07 16:36:38 -07:00
78422eaa17 embed: add Election service 2017-04-07 16:36:38 -07:00
bf047ed9d5 integration: v3 election rpc tests 2017-04-07 16:36:38 -07:00
dc8115a534 v3election: Election RPC service
Fixes #7589
2017-04-07 16:36:38 -07:00
9ba69ff317 scripts: update genproto.sh to include v3election 2017-04-07 16:36:38 -07:00
135a40751e v3rpc: force RangeEnd=nil if length is 0
gRPC will replace empty strings with nil, but for the embedded case it's
possible for []byte{} to slip in and confuse the single key / >= key
watch logic.
2017-04-07 16:36:38 -07:00
4b4f5be74a concurrency: don't skip leader updates in Observe()
The Get for the leader key will fetch based on the latest revision
instead of the deletion revision, missing leader updates between
the delete and the Get.

Although it's usually safe to skip these updates since they're
stale, it makes testing more difficult and in some cases the
full leader update history is desirable.
2017-04-07 16:36:38 -07:00
80c1b9c13a concurrency: support resuming elections if leadership already held
If a client already knows it holds leadership, let it create an
election object with its leadership information.
2017-04-07 16:36:38 -07:00
d1ae4cd5bd concurrency: only delete on election resignation if create revision matches
Addresses a case where two clients share the same lease. A client resigns but
disconnects / crashes and doesn't realize it. Another client reuses the
lease and gets leadership with a new key. The old client comes back and
tries to resign again, revoking the new leadership of the new client.
2017-04-07 16:36:37 -07:00
4b5bb7f212 concurrency: return v3.GetResponse for Election.Leader()
The full information about the leader's key is necessary to
safely use elections with transactions. Instead of returning
only the value on Leader(), return the entire GetResposne.
2017-04-07 16:36:37 -07:00
a6cab69c88 concurrency: expose leader revision and proclaim headers for election 2017-04-07 16:36:37 -07:00
2769cae6bd vendor: upgrade grpc-gateway to v1.2.0 2017-04-07 16:36:14 -07:00
c0560be98a Merge pull request #7692 from heyitsanthony/upgrade-grpc
vendor: upgrade grpc to 1.2.1
2017-04-07 16:04:50 -07:00
9ba435d902 vendor: upgrade grpc to 1.2.1 2017-04-07 14:32:00 -07:00
63bb560820 Merge pull request #7688 from heyitsanthony/short-mask
test: fix fmt pass, shorten warnings, clear SA1016
2017-04-07 12:33:57 -07:00
88d4e7ebeb netutil: fix unused err staticcheck failure
Clears SA4006
2017-04-07 10:52:54 -07:00
7e05b33aa0 *: remove os.Kill from signal.Notify
Clears SA1016 in staticcheck
2017-04-07 10:52:54 -07:00
d31701bab5 test: fix fmt pass and shorten suppression warnings
If gosimple or staticcheck had no output, it no other passes would be
applied because they were using `continue`. Similarly, the suppression
check never worked at all since it wasn't the result data into egrep.

Fixes #7685
2017-04-06 21:33:03 -07:00
25ed908c18 Merge pull request #7684 from gyuho/a
clientv3/integration: fix minor typo in Fatalf
2017-04-06 19:15:51 -07:00
369d561350 clientv3/integration: fix minor typo in Fatalf
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-06 18:26:42 -07:00
7c5991c2e6 Merge pull request #7676 from fanminshi/add_dns_srv
etcdmain: support SRV discovery for gRPC proxy
2017-04-06 12:32:40 -07:00
bea4c62965 Merge pull request #7677 from heyitsanthony/fix-waitsubstream
clientv3: register waitCancelSubstreams closingc goroutine with waitgroup
2017-04-06 11:10:06 -07:00
2bc1dfd921 etcdmain: support SRV discovery for gRPC proxy
FIX #7562
2017-04-06 10:45:19 -07:00
e1cf766695 Merge pull request #7674 from gyuho/debug
ctlv3: add '--debug' flag (to enable grpclog)
2017-04-05 17:39:37 -07:00
7388911e0c ctlv3: add '--debug' flag (to enable grpclog)
By default, grpclog is disabled. It should be configurable
for debugging purposes, as we did in v2.

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-05 17:11:31 -07:00
aab2eda7df clientv3: register waitCancelSubstreams closingc goroutine with waitgroup
Fixes #7598
2017-04-05 16:06:53 -07:00
408de4124b Merge pull request #7675 from gyuho/tls-min-version
clientv3/yaml: use TLS 1.2 in min version
2017-04-05 12:58:16 -07:00
dee467dc24 clientv3/yaml: use TLS 1.2 in min version
To be consistent with 'pkg/transport'

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-05 11:50:35 -07:00
83577a5d08 Merge pull request #7670 from heyitsanthony/fix-lease-be-race
lease: acquire BatchTx lock in fakeDeleter
2017-04-05 11:08:15 -07:00
d42c1f5131 Merge pull request #7646 from andelf/fix-unix-socket-url
*: fix a bug in handling unix socket urls
2017-04-05 09:24:38 -07:00
43f795a485 Merge pull request #7659 from gyuho/aaa
pkg/transport: remove port in Certificate.IPAddresses
2017-04-05 04:29:44 -07:00
4f27981c46 *: fix a bug in handling unix socket urls
Now use url.Host + url.Path as unix socket path

Fixes #7644
2017-04-05 14:33:13 +08:00
c7bdd7e2c5 Merge pull request #7669 from mitake/byte-affine
auth, adt: introduce a new type ByteAffineComparable
2017-04-05 15:19:08 +09:00
c4a45c5713 auth, adt: introduce a new type BytesAffineComparable
It will be useful for avoiding a cost of casting from string to
[]byte. The permission checker is the first user of the type.
2017-04-05 13:17:24 +09:00
42d56d5ef7 lease: acquire BatchTx lock in fakeDeleter
Revoke expects the BatchTx lock to be held when holding the TxnDeleter
because it updates the lease bucket. The tests don't hold the lock so
it may race with the backend commit loop.

Fixes #7662
2017-04-04 20:52:23 -07:00
d51d381eca Merge pull request #7656 from gyuho/more-adapter
*: add cluster API adapter
2017-04-04 20:10:24 -07:00
63355062dc Merge pull request #7649 from mitake/range-open-ended
etcdctl: add a new option --open-ended for unlimited range permission
2017-04-05 11:03:52 +09:00
f7c99208b5 Merge pull request #7667 from ElijahCaine/relative-links-1
Docs: replace absolute links with relative ones.
2017-04-04 18:33:02 -07:00
c0fc389c98 Merge pull request #7661 from heyitsanthony/cov-fail-report
test: generate coverage report even if some tests fail
2017-04-04 16:46:46 -07:00
31c1931b7b Docs: replace absolute links with relative ones. 2017-04-04 15:21:42 -07:00
6978471712 Merge pull request #7664 from gyuho/safe-revision-access
auth: use atomic access to 'authStore.revision'
2017-04-04 13:56:20 -07:00
3edd36315d auth: use atomic access to 'authStore.revision'
Fix https://github.com/coreos/etcd/issues/7660.

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-04 13:16:02 -07:00
23e952ccfd test: generate coverage report even if some tests fail
The coverage data is still useful even if some tests fail. Instead of
terminating the coverage pass on any test failure, collect and pass
the failed tests, generate the coverage report, then report the failed
packages and exit with an error.
2017-04-04 11:12:18 -07:00
1e3274dfa2 integration: use cluster adapter in tests
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-04 10:08:51 -07:00
8a7a548a6d pkg/transport: remove port in Certificate.IPAddresses
etcd passes 'url.URL.Host' to 'SelfCert' which contains
client, peer port. 'net.ParseIP("127.0.0.1:2379")' returns
'nil', and the client on this self-cert will see errors
of '127.0.0.1 because it doesn't contain any IP SANs'

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-04 09:44:59 -07:00
d9069120bb Merge pull request #7657 from gyuho/auth-cleanup
clientv3: remove unused fields from 'auth'
2017-04-04 09:42:17 -07:00
972d8c55ab Merge pull request #7653 from xiang90/pprof
*: add pprof flag to grpc proxy
2017-04-04 09:22:50 -07:00
9bc3c0bd05 clientv3: remove unused fields from 'auth'
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-04 08:17:36 -07:00
7f2d6b3ef6 clientv3,v3client: add cluster embedded client
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-04 08:14:18 -07:00
7adf4d7c94 grpcproxy/adapter: add Cluster API support
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-04-04 08:13:30 -07:00
a204b14503 e2e: add a test case for the --open-ended option 2017-04-04 17:28:59 +09:00
0a7fc7cd34 etcdctl: add a new option --from-key for unlimited range permission
This commit adds a new option --from-key to the command etcdctl role
grant-permission. If the option is passed, an open ended permission
will be granted to a role e.g. from start-key to any keys those are
larger than start-key.

Example:
$ ETCDCTL_API=3 bin/etcdctl --user root:p role grant r1 readwrite a b
$ ETCDCTL_API=3 bin/etcdctl --user root:p role grant --from-key r1 readwrite c
$ ETCDCTL_API=3 bin/etcdctl --user root:p role get r1
Role r1
KV Read:
        [a, b) (prefix a)
        [c, <open ended>
KV Write:
        [a, b) (prefix a)
        [c, <open ended>

Note that a closed parenthesis doesn't follow the above <open ended>
for indicating that the role has an open ended permission ("<open
ended>" is a valid range end).

Fixes https://github.com/coreos/etcd/issues/7468
2017-04-04 17:28:59 +09:00
fd5984af56 *: add pprof flag to grpc proxy 2017-04-03 22:07:17 -07:00
d6efc0b22b Merge pull request #7651 from heyitsanthony/ivt-contains-intersects
*: support checking that an interval tree's keys cover an entire interval
2017-04-03 20:20:56 -07:00
f67bdc2eed *: support checking that an interval tree's keys cover an entire interval 2017-04-03 15:38:07 -07:00
63c6824905 Merge pull request #7650 from philips/add-dims-v3
Documentation: add dims v3 gateway API for python
2017-04-03 15:08:03 -07:00
7dbc4549d9 Merge pull request #7652 from heyitsanthony/fix-gofmt-clientv3
clientv3: fix go1.8 go fmt warning in test
2017-04-03 15:05:41 -07:00
a0149106b8 clientv3: fix go1.8 go fmt warning in test 2017-04-03 14:00:06 -07:00
8963cf2f8b Documentation: add dims v3 gateway API for python 2017-04-03 12:55:24 -07:00
e56e43064f Merge pull request #7637 from lumjjb/patch-2
Documentation: add encryption wrapper to integrations
2017-04-03 12:34:08 -07:00
f13bea0bb0 Merge pull request #7639 from heyitsanthony/fix-userflag-timeout
clientv3: respect dial timeout in auth
2017-04-03 09:30:48 -07:00
ea06ea41e5 Merge pull request #7641 from ggaaooppeenngg/fix-id-doc
idgen: correct comments for id generator
2017-04-03 09:17:55 -07:00
24e4c94d98 Merge pull request #7640 from heyitsanthony/etcdserver-ctx
etcdserver: ctx-ize server initiated requests
2017-04-03 09:07:28 -07:00
8dafaf390a Merge pull request #7642 from davissp14/integration-doc-update
Documentation: Adding new Ruby v3 client entry to integrations.md
2017-04-02 21:55:38 -07:00
8d07200bbf Documentation: Adding new Ruby v3 client entry to integrations.md 2017-04-02 23:54:07 -05:00
38a9149735 Merge pull request #7569 from mitake/interval
auth: store cached permission information in a form of interval tree
2017-04-03 02:41:31 +02:00
d204b6c3b7 idgen: correct comments for id generator
Comments for id generator format is out of
date, correct it.

Fixes #7636

Signed-off-by: Peng Gao <peng.gao.dut@gmail.com>
2017-04-02 20:56:10 +08:00
f5f4791023 integration: test cluster terminates quickly 2017-03-31 19:19:33 -07:00
8ad935ef2c etcdserver: use cancelable context for server initiated requests 2017-03-31 19:19:33 -07:00
5aebe1a52d clientv3: test dial timeout is respected when using auth 2017-03-31 15:14:46 -07:00
62d7bae496 clientv3: respect dial timeout when authenticating
Fixes #7627
2017-03-31 15:14:46 -07:00
e6b685b1ed Documentation: add encryption wrapper to integrations 2017-03-31 13:02:53 -04:00
512bac0ee9 Merge pull request #7630 from heyitsanthony/fix-lease-req-leader
clientv3: support WithRequireLeader in lease client
2017-03-31 09:52:17 -07:00
8024a0d15f clientv3: support WithRequireLeader in lease client
Unconditionally opens a WithRequireLeader stream in the lease client. Any
keep alive channels opened using WithRequireLeader will be closed when
the leader is lost.

Fixes #7275
2017-03-30 21:39:36 -07:00
7db7744737 clientv3/integration: test lease WithRequireLeader 2017-03-30 20:18:33 -07:00
833769f59f v3rpc: return leader loss error if lease stream is canceled
Canceling the stream won't cancel the receive since it's using the internal
grpc context, not the one assigned by etcd.
2017-03-30 20:18:33 -07:00
b55ea6a70b integration: test require leader for a lease stream 2017-03-30 20:18:33 -07:00
9ca7f22e84 Merge pull request #7614 from jsok/7516-default-initial-cluster
embed: Delay setting initial cluster
2017-03-30 18:01:51 -07:00
0472b2dc9f etcdmain: test config file clustering flags
A test to ensure that when clustering flags are correctly and
independently specified no errors are raised.
2017-03-31 10:01:46 +11:00
d0d4b1378b embed: Delay setting initial cluster for YAML
NewConfig() sets an initial cluster (potentially using a default name)
but we should clear it in the event another discovery option has been
specified.

PR #7517 attempted to address this however it only worked if the name
was left as "default".

(Completely) Fixes #7516
2017-03-31 10:01:42 +11:00
ca22c4c384 Merge pull request #7632 from xiang90/fix_periodic
compactor: fix TestPeriodic
2017-03-30 15:13:46 -07:00
ef3bd4ecc5 Merge pull request #7633 from heyitsanthony/protoc-3.2.0
*: use protoc 3.2.0
2017-03-30 15:10:14 -07:00
809e6110a0 compactor: fix TestPeriodic
Perviously, we advance checkCompactionInterval more than we should.
The compaction might happen nondeterministically since there is no
synchronization before we call clock.Advance().

The number of rg.Wait() should be equal to the number of Advance() if
compactor routine and test routine run at the same pace. However, in our current
test, we call Advance() more than rg.Wait().

It works OK when the compactor routine runs "slower" than the test routine, which
is the common case. However, when the speed changes, the compactor routine might
block rg.Rev() since there is not enough calls of rg.Wait().

This commit forces the compactor and test routine to run at the same pace. And we supply
the exact number of Advance() and wg.Wait() that compactor needs.
2017-03-30 15:00:49 -07:00
1ff0b71b30 *: use protoc 3.2.0
Fixes #7631
2017-03-30 13:43:10 -07:00
a0c97282c3 Merge pull request #7626 from akauppi/pr-doc-typos
Fixing small typos in documentation
2017-03-30 13:36:38 -07:00
dae2755253 Documentation: fix typos 2017-03-30 11:41:50 +03:00
36735d52a4 Merge pull request #7622 from heyitsanthony/faq-disk-leader
Documentation: add disk latency leader loss question to FAQ
2017-03-28 19:18:50 -07:00
eafab47f05 Merge pull request #7612 from gyuho/adapter-maintenance-API
*: adapter maintenance api
2017-03-28 16:38:20 -07:00
faad828c51 Documentation: add disk latency leader loss question to FAQ 2017-03-28 15:49:21 -07:00
6b784908ad Merge pull request #7621 from xiang90/c_d
compactor: make TestPeriodic die early
2017-03-28 15:38:59 -07:00
c90a4b96d1 integration: use maintenance API adapter in tests
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-28 14:12:47 -07:00
0bf110e27f clientv3,v3client: maintenance to embedded client
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-28 14:12:43 -07:00
a915ff8419 compactor: make TestPeriodic die early 2017-03-28 13:50:16 -07:00
5c642ae314 grpcproxy/adapter: add maintenance API support
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-28 09:09:06 -07:00
123b25845c Merge pull request #7610 from gyuho/news
NEWS: add v3.1.4, v3.1.5
2017-03-28 05:45:10 -07:00
65ad91b14d Merge pull request #7591 from xiang90/validate
etcdctl: add initial check perf command
2017-03-27 17:23:58 -07:00
60d3375599 etcdctl: add initial check perf command 2017-03-27 17:01:15 -07:00
a4ab5e55f9 Merge pull request #7611 from xiang90/auth_design
doc: link auth design in doc
2017-03-27 13:08:40 -07:00
4c7ffe4442 Merge pull request #7605 from gyuho/wrap-adapter
proxy/grpcproxy: add chanStream helper
2017-03-27 13:01:19 -07:00
fded83f111 doc: link auth design in doc 2017-03-27 11:58:32 -07:00
e70c8ac4a2 Merge pull request #7508 from mitake/auth-v3-design
auth: import design doc
2017-03-27 11:35:55 -07:00
caa73c176f proxy/grpcproxy: add chanStream helper
Prelimiary work for maintenance API in adapter

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-27 11:24:02 -07:00
5dea73860f NEWS: add v3.1.4, v3.1.5
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-27 10:54:51 -07:00
e6f72b4f42 Merge pull request #7603 from heyitsanthony/leak-check-grpc
testutil: check for grpc resources in AfterTest
2017-03-27 10:33:25 -07:00
9381b103bb Merge pull request #7601 from heyitsanthony/fix-proxy-compact
grpcproxy/cache: only check compaction revision for historical revisions
2017-03-27 09:23:17 -07:00
2e1e1c95bd auth: import design doc
This commit imports and refines the design doc of v3 auth:
https://goo.gl/fwBxz6
2017-03-27 07:53:32 -07:00
da6a035afb Merge pull request #7600 from raoofm/patch-10
op-guide: Remove guest role from v3 auth doc
2017-03-25 10:08:36 +09:00
997e83f8ea testutil: check for grpc resources in AfterTest
gRPC leaks only show up at the final leak check, making it difficult to
determine which test is causing the leak.
2017-03-24 16:09:38 -07:00
631f790689 Merge pull request #7574 from fanminshi/fix_mem_leak
raft: use rs.req.Entries[0].Data as the key for deletion in advance()
2017-03-24 15:50:17 -07:00
b2a465e354 grpcproxy/cache: only check compaction revision for historical revisions
Since the current revision is 0, it'll always be less than the compaction
revision. If the proxy sees a compaction, it would always reject the
current revision requests since it's less than the compaction revision.
Instead, check if the revision is historical before trying to reject on
compaction revision.

Fixes #7599
2017-03-24 13:20:46 -07:00
b9cfa4cef9 integration: add serialized range to TestV3CompactCurrentRev
To catch compaction bugs in the proxy key cache.
2017-03-24 13:13:38 -07:00
a26964c855 op-guide: Remove guest role from v3 auth doc 2017-03-24 16:09:58 -04:00
f18ae033a7 raft: use rs.req.Entries[0].Data as the key for deletion in advance()
advance() should use rs.req.Entries[0].Data as the context instead of
req.Context for deletion. Since req.Context is never set, there won't be
any context being deleted from pendingReadIndex; results mem leak.

FIXES #7571
2017-03-24 12:31:21 -07:00
608a2be9c5 Merge pull request #7596 from andelf/fix-typo-bucked
etcdserver: fix a typo in bucket name var
2017-03-24 09:51:05 -07:00
f763048156 Merge pull request #7592 from heyitsanthony/proxy-cov
test: add proxy to coverage tests
2017-03-24 09:42:57 -07:00
54efb460af etcdserver: fix a typo in bucket name var 2017-03-24 13:11:01 +08:00
ab1cf751a3 test: add proxy to coverage tests 2017-03-23 18:27:09 -07:00
ad2111a6f4 auth: store cached permission information in a form of interval tree
This commit change the type of cached permission information from the
home made thing to interval tree. It improves computational complexity
of permission checking from O(n) to O(lg n).
2017-03-24 09:36:14 +09:00
e9bfcc02ce Merge pull request #7590 from gyuho/test
integration: retry TestNetworkPartition5MembersLeaderInMajority
2017-03-23 17:02:32 -07:00
b81cb999fb integration: retry TestNetworkPartition5MembersLeaderInMajority
Fix https://github.com/coreos/etcd/issues/7587.

Retry for possible leader election in majority.

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-23 16:30:38 -07:00
204335d304 Merge pull request #7560 from artem-panchenko/fix_container_resolving
Dockerfile-release: add nsswitch.conf into image
2017-03-23 15:20:14 -07:00
54928f5deb Merge pull request #7524 from mitake/del-and-revoke-role
auth: changes of managing roles and users
2017-03-23 15:10:10 -07:00
3f8eab8439 Merge pull request #7581 from heyitsanthony/ivt-sorted-visit
adt: Visit() interval trees in sorted order
2017-03-23 14:11:08 -07:00
21217c30f9 Merge pull request #7583 from krmayankk/prod-users
add Salesforce to prod users
2017-03-23 12:33:30 -07:00
37bdc94860 Documentation: add salesforce to prod users 2017-03-23 12:29:37 -07:00
36ece32a61 Merge pull request #7582 from heyitsanthony/fix-watch-stream-leak
clientv3: use waitgroup to wait for substream goroutine teardown
2017-03-23 12:24:06 -07:00
0256953b28 Merge pull request #7586 from gyuho/timeout
tools/etcd-tester: add timeout for 'defrag'
2017-03-23 10:23:42 -07:00
8afc468b64 tools/etcd-tester: add timeout for 'defrag'
etcd panic-ed, so defrag response just blocked for "days"
when the actual 'v3rpc' path never returned.

We should catch this earlier.

ref. https://github.com/coreos/etcd/issues/7526

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-23 10:22:20 -07:00
161c7f6bdf Merge pull request #7579 from gyuho/fix-defrage
*: fix panic during defrag operation
2017-03-23 10:08:33 -07:00
23719f99c6 Merge pull request #7563 from heyitsanthony/fix-testdialcancel-leak
clientv3: wait for Get goroutine in TestDialCancel
2017-03-23 10:07:23 -07:00
7ef75e373a Merge pull request #7525 from heyitsanthony/big-backend
etcdserver, backend: configure mmap size based on quota
2017-03-23 10:06:00 -07:00
9dcb975724 Merge pull request #7556 from brancz/prom-rules
Documentation: add Prometheus alerting rules
2017-03-23 09:58:57 -07:00
ed68bf89ff integration: test inflight range requests while defragmenting
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-23 09:48:04 -07:00
26abd25cd3 mvcc/backend: hold 'readTx.Lock' until completing bolt.Tx reset
Fix https://github.com/coreos/etcd/issues/7526.

When resetting `bolt.Tx` in `defrag` and `batchTxBuffered.commit`
operation, we do not hold `readTx` lock, so the inflight range
requests can trigger panic in `mvcc.Range` paths. This fixes by
moving mutexes out and hold it while resetting the `readTx`.

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-23 09:47:43 -07:00
e7a0c9128a Documentation: add Prometheus alerting rules 2017-03-23 09:43:38 +01:00
8d0d942c47 e2e: add a test case for invalid management of root user and role 2017-03-23 16:47:58 +09:00
c40b86bcde auth, etcdserver: forbid invalid auth management
If auth is enabled,
1. deleting the user root
2. revoking the role root from the user root
must not be allowed. This commit forbids them.
2017-03-23 16:47:58 +09:00
0c87467f69 e2e: add a test case role delete and revoke 2017-03-23 16:47:44 +09:00
068d806bde *: revoke a deleted role
This commit resolves a TODO of auth store:
Current scheme of role deletion allows existing users to have the
deleted roles. Assume a case like below:
create a role r1
create a user u1 and grant r1 to u1
delete r1

After this sequence, u1 is still granted the role r1. So if admin
create a new role with the name r1, The new r1 is automatically
granted u1. In some cases, it would be confusing. So we need to
revoke the deleted role from all users.
2017-03-23 16:44:19 +09:00
25e3ce1feb adt: Visit() interval trees in sorted order and terminate early
For all intervals [x, y), Visit will visit intervals in ascending order
sorted by x. Also fixes a bug where Visit would not terminate the search
when requested by the visitor function.
2017-03-23 00:02:29 -07:00
a39107a3b8 clientv3: use waitgroup to wait for substream goroutine teardown
When a grpc watch stream is torn down, it will join on its logical substream
goroutines by waiting for each to close a channel. This doesn't guarantee
the substream is fully exited, though, but only about to exit and can be
waiting to resume even after Watch.Close finishes. Instead, use a
waitgroup.Done at the very end of the substream defer.

Fixes #7573
2017-03-22 23:27:26 -07:00
049ca8746a Merge pull request #7549 from heyitsanthony/namespace-proxy
namespace proxy
2017-03-22 23:26:52 -07:00
85f989ab3d Documentation, op-guide, clientv3: add documentation for namespacing 2017-03-22 16:45:38 -07:00
397a42efbe etcdmain: add prefixing support to grpc proxy
Fixes #6577
2017-03-22 16:45:38 -07:00
f35d7d9608 integration: test namespacing on proxy layer
Hardcode a namespace over the testing grpcproxy.
2017-03-22 16:45:38 -07:00
66d147766f clientv3/integration: simple namespace wrapper tests 2017-03-22 16:45:38 -07:00
facbb64090 Merge pull request #7578 from joshix/patch-1
etcd-2-1-0-bench: Fix an absolute bare link to resource outside of Doc dir
2017-03-22 15:45:58 -07:00
e0de6536c8 etcd-2-1-0-bench: Fix an absolute bare link to resource outside of Documentation dir 2017-03-22 15:27:21 -07:00
1f8c7b33e7 namespace: a wrapper for clientv3 to namespace requests 2017-03-22 14:09:09 -07:00
f9b6066dd6 clientv3: make ops and compares non-opaque and mutable
Fixes #7250
2017-03-22 14:08:59 -07:00
da10d5d057 Merge pull request #7572 from heyitsanthony/fix-restart-member
integration: wait on leader before progress check in TestRestartMember
2017-03-22 14:08:07 -07:00
9f34d3493d integration: wait on leader before progress check in TestRestartMember
In rare cases, the last member may not have the leader by the time the
final cluster progress check tries to open a watch, causing a timeout.
2017-03-22 12:48:31 -07:00
1a75165ed8 Merge pull request #7568 from heyitsanthony/clientv3-redundant-err
clientv3: remove redundant error handling code
2017-03-22 08:55:54 -07:00
dd465d0e40 clientv3: remove redundant error handling code 2017-03-22 01:08:23 -07:00
ff6d6867b0 Merge pull request #7523 from mitake/auth-v3-doc
Documentation: add a doc of v3 auth
2017-03-21 22:46:37 -07:00
5cda22a17d Documentation: add a doc of v3 auth
It is almost same to Documentation/v2/authentication.md because a
major part of its user interface is shared with the v2 auth. The newly
added doc includes some refinements for the v3 auth.
2017-03-22 11:26:54 +09:00
9e034f4b4b Merge pull request #7564 from gyuho/test
client/integration: use only digits in unix port
2017-03-21 17:40:47 -07:00
22c52b6d2e client/integration: use only digits in unix port
Fix https://github.com/coreos/etcd/issues/7558.

Same as https://github.com/coreos/etcd/issues/6959.

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-21 17:10:59 -07:00
d1a9ccb2b9 clientv3: wait for Get goroutine in TestDialCancel 2017-03-21 16:43:39 -07:00
6511171725 Merge pull request #7561 from gyuho/travis
travis: always 'go get -u' in 'before_install'
2017-03-21 14:16:55 -07:00
e127214c6c travis: always 'go get -u' in 'before_install'
See https://github.com/dominikh/go-tools/issues/76#issuecomment-288189194.

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-21 12:21:55 -07:00
327e255695 Merge pull request #7546 from gyuho/fix-blocking-etcd-process
*: fix blocking etcd process
2017-03-21 12:04:53 -07:00
7698a2a546 Merge pull request #7553 from xiang90/fix_defrag
backend: add FillPercent option
2017-03-21 11:16:17 -07:00
2d5f890091 integration: ensure 'StopNotify' on publish error
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-21 10:29:00 -07:00
17e2e762b1 etcdmain: handle StopNotify when ErrStopped aborted publish
Fix https://github.com/coreos/etcd/issues/7512.

If a server starts and aborts due to config error,
it is possible to get stuck in ReadyNotify waits.
This adds select case to get notified on stop channel.

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-21 10:22:39 -07:00
cd70ea33ce Merge pull request #7552 from mitake/ordinary
e2e, etcdserver: fix wrong usages of ordinal
2017-03-21 09:42:27 -07:00
95870a21eb backend: add FillPercent option 2017-03-21 08:06:03 -07:00
5594f695bc e2e, etcdserver: fix wrong usages of ordinal
They must be "ordinary".
2017-03-21 23:50:16 +09:00
b9d91483d0 Dockerfile-release: add nsswitch.conf into image
The file '/etc/nsswitch.conf' is created in order to
take in account '/etc/hosts' entries while resolving
domain names.
2017-03-21 13:08:42 +02:00
004c1388fb Merge pull request #7541 from heyitsanthony/remove-legacy-range
etcdserver: remove legacy range/txn
2017-03-20 19:22:39 -07:00
27550b229a Merge pull request #7545 from gyuho/go1.7-go1.8
*: use 'io.Seek*' for go1.7+
2017-03-20 16:31:21 -07:00
effa6e0767 etcdserver: remove legacy range/txn
Needed for 3.0->3.1. Not needed for 3.1->3.2
2017-03-20 15:17:17 -07:00
aca2abd8fe *: use 'io.Seek*' for go1.7+
For https://github.com/coreos/etcd/issues/6174.

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-20 15:15:24 -07:00
3a1368d4d2 Merge pull request #7543 from heyitsanthony/fix-timeseries
*: fix gosimple warning for fmt.Sprintf("%s")
2017-03-20 15:02:13 -07:00
ae7b4ee8ed *: fix gosimple warning for fmt.Sprintf("%s") 2017-03-20 13:26:39 -07:00
53ca03b655 Merge pull request #7539 from heyitsanthony/fix-protobuf-help
ctlv3: have "protobuf" in output help string instead of "proto"
2017-03-20 11:26:13 -07:00
cfdad38f4e Merge pull request #7531 from heyitsanthony/fix-mem-remove-again
e2e: force endpoint for member removal
2017-03-20 09:52:30 -07:00
432c19de61 ctlv3: have "protobuf" in output help string instead of "proto"
Fixes #7538
2017-03-20 09:40:21 -07:00
fba87558a6 Merge pull request #7529 from fanminshi/fix_closing_embedded_error
embed: don't return error when closing on embed etcd
2017-03-17 17:02:22 -07:00
21ac657e67 e2e: force endpoint for member removal
e2e tests use different invocations of etcdctl, so the endpoint used to get
the member list will not necessarily be the same to make the remove call.
Instead, select an endpoint that is not being remove, and connect with that.
2017-03-17 16:24:54 -07:00
8a3fee15a3 etcdserver, backend: only warn if exceeding max quota 2017-03-17 15:38:57 -07:00
5e4b008106 *: base initial mmap size on quota size 2017-03-17 15:38:49 -07:00
f292a4c953 embed: don't return error when closing on embed etcd
FIXES #7019
2017-03-17 13:41:05 -07:00
5015480e0c Merge pull request #7517 from jsok/7516-discovery-flags
embed: Delay setting initial cluster
2017-03-16 09:17:42 -07:00
79f4c196b8 Merge pull request #7518 from heyitsanthony/filepath
*: replace path.Join on files with filepath.Join
2017-03-16 08:59:49 -07:00
2f1542c06d *: use filepath.Join for files 2017-03-16 07:46:06 -07:00
1a91ed0e99 embed: Clear default initial cluster
NewConfig() should sets initial cluster from name but we should clear it
in the event that another discovery option has been specified.

Fixes #7516
2017-03-16 13:59:06 +11:00
d78b03fb27 Merge pull request #7515 from tessr/master
wal: use path/filepath instead of path
2017-03-15 19:25:08 -07:00
39c733ebe7 wal: use path/filepath instead of path
Use the path/filepath package instead of the path package. The
path package assumes slash-separated paths, which doesn't work
on Windows. But path/filepath manipulates filename paths in a way
that's compatible across OSes.
2017-03-15 17:30:23 -07:00
5856c8bce9 Merge pull request #7513 from gyuho/raft-applied-term
etcdserver: remove possibly compacted entry look-up
2017-03-15 13:35:36 -07:00
80c10e150f etcdserver: remove possibly compacted entry look-up
Fix https://github.com/coreos/etcd/issues/7470.

This patch removes unnecessary term look-up in
'createMergedSnapshotMessage', which can trigger panic
if raft entry at etcdProgress.appliedi got compacted
by subsequent 'MsgSnap' messages--if a follower is
being (in this case, network latency spikes), it
could receive subsequent 'MsgSnap' requests from leader.

etcd server-side 'applyAll' routine and raft's Ready
processing routine becomes asynchronous after raft
entries are persisted. And given that raft Ready routine
takes less time to finish, it is possible that second
'MsgSnap' is being handled, while the slow 'applyAll'
is still processing the first(old) 'MsgSnap'. Then raft
Ready routine can compact the log entries at future
index to 'applyAll'. That is how 'createMergedSnapshotMessage'
tried to look up raft term with outdated etcdProgress.appliedi.

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-15 12:46:56 -07:00
902c676cdb Merge pull request #7397 from fanminshi/fix_SetEndpoints
clientv3/balancer: update eps if pinAddr is not included in updateAddrs
2017-03-15 12:16:15 -07:00
a23609efe6 clientv3: update eps if pinAddr is not included in updateAddrs
FIXES #7392
2017-03-15 11:03:25 -07:00
a2a6b693f1 Merge pull request #7511 from heyitsanthony/fix-v3client-embed
v3client: fix doc to use e.Server
2017-03-15 10:28:41 -07:00
dea2516177 v3client: fix doc to use e.Server
Was passing embed.Etcd instead of etcdserver.EtcdServer.
2017-03-15 09:17:17 -07:00
8f83d11724 Merge pull request #7499 from heyitsanthony/fix-etcdctl-add-member-env
ctlv3: ensure synced member list before printing env vars on member add
2017-03-15 08:59:04 -07:00
27960911af Merge pull request #7500 from heyitsanthony/fix-balancer-test-leak
clientv3: synchronize on goroutines in TestBalancerDoNotBlockOnClose
2017-03-15 08:58:03 -07:00
7a6b61cd6f Merge pull request #7504 from heyitsanthony/fix-watch-wait
clientv3: close open watch channel if substream is closing on reconnect
2017-03-15 08:57:14 -07:00
df839f3b7f Merge pull request #7497 from xiang90/fix_candidate
etcdserver: candidate should wait for applying all configuration changes
2017-03-14 20:10:02 -07:00
3e86779ad5 ctlv3: ensure synced member list before printing env vars on member add
In cases of multiple endpoints, it's possible member add would get a its
member list from a member that has not yet recognized the membership
update. Instead, confirm that the member list response is from the
member that acked the member add or from a member that has synced
with the cluster following the member add.

Fixes #7498
2017-03-14 20:01:44 -07:00
b36734f1d3 clientv3: synchronize on goroutines in TestBalancerDoNotBlockOnClose
Was leaking dialers.
2017-03-14 19:53:33 -07:00
18a813a9fe Merge pull request #7496 from heyitsanthony/v3client-doc
v3client: add example and godoc New
2017-03-14 19:50:01 -07:00
a087325452 clientv3: close open watch channel if substream is closing on reconnect
If substream is closing but outc is still open while reconnecting, then outc
would only be closed once the watch client would connect or once the watch
client is closed. This was leading to deadlocks in the proxy tests. Instead,
close immediately if the context is canceled.

Fixes #7503
2017-03-14 17:25:18 -07:00
7f0733cf46 etcdserver: candidate should wait for applying all configuration changes 2017-03-14 17:20:20 -07:00
eed4a3f035 Merge pull request #7502 from gyuho/scripts
test: mask go1.8 gosimple warnings
2017-03-14 17:00:01 -07:00
a9588952a0 test: mask go1.8 gosimple warnings 2017-03-14 15:10:32 -07:00
ace3a217b0 Merge pull request #7483 from fanminshi/add_tests_to_mutex
integration: add TestMutexWaitsOnCurrentHolder test
2017-03-14 13:01:47 -07:00
276039e835 integration: add TestMutexWaitsOnCurrentHolder test
TestMutexWaitsOnCurrentHolder ensures a series of waiters
obtain lock only after the previous lock requests are gone.
2017-03-14 11:00:07 -07:00
01d1a579bc v3client: add example and godoc New 2017-03-14 10:50:41 -07:00
781196fa87 Merge pull request #7495 from heyitsanthony/more-cov
test: add coverage for more packages
2017-03-14 09:31:01 -07:00
e3218e2dd1 test: add coverage for more packages
Was only getting coverage for packages with test files. Instead, include
packages that don't have test files as well.
2017-03-14 01:08:07 -07:00
1a6be700d8 Merge pull request #7444 from heyitsanthony/lock-service
grpc lock service
2017-03-14 00:01:34 -07:00
148c923c72 Merge pull request #7492 from heyitsanthony/simpletokenttl-deadlock
auth: get rid of deadlocking channel passing scheme in simpleTokenTTL
2017-03-14 14:01:23 +09:00
4409932132 auth: test concurrent authentication 2017-03-13 21:11:35 -07:00
1b1fabef8f auth: get rid of deadlocking channel passing scheme in simpleTokenTTL
Just use the mutex instead.

Fixes #7471
2017-03-13 21:11:35 -07:00
3a61fe596b Merge pull request #7423 from purpleidea/feat/clientv3util-examples
clientv3util: Add KeyExists and KeyMissing examples
2017-03-13 17:26:57 -07:00
94d5936180 Update example_key_test.go 2017-03-13 16:54:26 -07:00
7b541f9003 Merge pull request #7491 from heyitsanthony/learning-api
doc/learning: complete the api guide
2017-03-13 15:39:04 -07:00
300323fa50 integration: test grpc lock service 2017-03-13 15:23:26 -07:00
ad1a790116 embed: serve lock api 2017-03-13 15:23:26 -07:00
c737bf3d2a scripts: generate lock service rpc stubs 2017-03-13 15:23:26 -07:00
47cd9d0277 v3lock: server-side api for locking 2017-03-13 15:23:26 -07:00
763a37d3f1 v3client: a bridge between an etcdserver and a clientv3 2017-03-13 15:23:26 -07:00
d51c8bb640 concurrency: support returning response header for mutex 2017-03-13 15:23:26 -07:00
a2cdd908dc clientv3: permit creating client without grpc connection
For creating client from etcdserver.
2017-03-13 15:23:26 -07:00
b025cdd097 adapter, integration: split out grpc adapters from grpcproxy package
Break cyclic dependency:
clientv3/naming <-> integration <-> v3client <-> grpcproxy <-> clientv3/naming
2017-03-13 15:23:26 -07:00
90b5f3587d doc/learning: complete the api guide
Fixes #7378
2017-03-13 14:34:12 -07:00
5193965005 Merge pull request #7481 from heyitsanthony/testafter-clientv3
clientv3: use CheckAfterTest after terminating cluster
2017-03-13 13:25:52 -07:00
34fca0caa9 Merge pull request #7476 from gyuho/NEWS
NEWS: update v3.1.3
2017-03-13 13:17:52 -07:00
312ac5824f Merge pull request #7486 from oberstet/doc-integr-add-txaio-etcd
add txaio-etcd to intergrations.md
2017-03-13 11:42:08 -07:00
d051b3b4e4 Documentation: add txaio-etcd to integrations 2017-03-13 18:24:46 +01:00
76aa7f6935 Merge pull request #7479 from heyitsanthony/auth-admin-nilcheck
auth: nil check AuthInfo when checking admin permissions
2017-03-11 23:30:33 -08:00
bf0aa68f89 Merge pull request #7480 from raoofm/patch-10
op-guide: update gateway routing policy
2017-03-11 23:29:59 -08:00
fbcc6db64c Merge pull request #7482 from gyuho/lll
discovery: fix print format
2017-03-10 17:05:40 -08:00
60bdc47fa0 discovery: fix print format
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-10 15:04:46 -08:00
38f27599b9 op-guide: update gateway routing policy
Update from single available endpoint to round robin.
2017-03-10 17:43:10 -05:00
593489d454 clientv3: use CheckAfterTest after terminating cluster
AfterTest() has a delay that waits for runtime goroutines to exit;
CheckLeakedGoroutine does not. Since the test runner manages the
test cluster for examples, there is no delay between terminating
the cluster and checking for leaked goroutines. Instead, apply
Aftertest checking before running CheckLeakedGoroutine to let runtime
http goroutines finish.
2017-03-10 12:23:46 -08:00
eb6a47f87e testutil: add CheckAfterTest for calling AfterTest without a testing.T 2017-03-10 12:18:24 -08:00
52bc997e0b auth: nil check AuthInfo when checking admin permissions
If the context does not include auth information, get authinfo will
return a nil auth info and a nil error. This is then passed to
IsAdminPermitted, which would dereference the nil auth info.
2017-03-10 11:07:11 -08:00
d0d3c768d9 Merge pull request #7478 from hubt/patch-2
doc: add branch.io use case into production users
2017-03-10 10:37:59 -08:00
9c9156b478 doc: add branch.io use case into production users 2017-03-10 10:01:05 -08:00
b744cecd20 NEWS: update v3.1.3
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-10 09:19:12 -08:00
0d851e49e3 Merge pull request #7475 from xiang90/baidu
doc: fix title size
2017-03-10 09:08:21 -08:00
debeccd605 doc: fix title size 2017-03-10 09:06:25 -08:00
c848ee9d86 Merge pull request #7473 from xiang90/baidu
doc: add Baidu Waimai
2017-03-10 09:05:21 -08:00
0a692b0524 Merge pull request #7443 from fanminshi/fix_balancer_deadlock
clientv3: serialize updating notifych in balancer
2017-03-10 07:48:47 -08:00
911ae60edf doc: add Baidu Waimai 2017-03-10 07:29:21 -08:00
0c38f1ff8d Merge pull request #7469 from gyuho/manual
Documentation: add huawei product user
2017-03-09 13:09:04 -08:00
0a9e2fe1f2 Documentation: add huawei product user 2017-03-09 13:06:20 -08:00
9afe4e87fd Merge pull request #7453 from allencloud/use-case-daocloud-io
add production user daocloud
2017-03-09 12:24:15 -08:00
310641630e clientv3: send frst down() func after recieving first notified addr
This ensures the ordering of down and up calls.
2017-03-09 12:20:36 -08:00
8baaa06cce clientv3: serialize updating notifych in balancer
FIXES #7283
2017-03-09 12:20:28 -08:00
5351953425 Merge pull request #7467 from gyuho/sd-notify
etcdmain: SdNotify when gateway, grpc-proxy are ready
2017-03-09 11:23:58 -08:00
01dd60c0f7 etcdmain: SdNotify when gateway, grpc-proxy are ready
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-09 10:10:21 -08:00
ad1d48b73d Merge pull request #7014 from gyuho/auto-sync-grpc-proxy
*: register grpc-proxy members
2017-03-09 09:35:59 -08:00
c8ea343a76 Merge pull request #7463 from heyitsanthony/cov-buildi
test: install packages when building coverage tests
2017-03-09 09:15:22 -08:00
4d69d9663b Documentation/op-guide: document grpcproxy sync
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-09 02:47:24 -08:00
095407df58 etcdmain: add register,resolver flags
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-09 02:47:12 -08:00
f862b47e92 grpcproxy: configure register to Cluster API
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-09 02:40:13 -08:00
5f4412996d clientv3: define error type for closed watcher 2017-03-09 02:29:54 -08:00
ddcf14102e Merge pull request #7105 from heyitsanthony/mvcc-txn
mvcc: txns and r/w views
2017-03-09 00:25:16 -08:00
889dd1b22f clientv3util: Add KeyExists and KeyMissing examples 2017-03-09 02:34:30 -05:00
dbf654cf77 test: install packages when building coverage tests
Lots of repeated compilation. Cache results with go build -i.
2017-03-08 22:24:16 -08:00
8bc6cea90c doc: Add daocloud.io to production users
Signed-off-by: allencloud <allen.sun@daocloud.io>
2017-03-09 13:30:53 +08:00
d1dcc828c8 etcdctl: support mvcc txn 2017-03-08 20:54:15 -08:00
0ed3c83e49 benchmark: support mvcc txn 2017-03-08 20:54:15 -08:00
58da8b17ee etcdserver: support mvcc txn 2017-03-08 20:54:15 -08:00
f0c184b3a2 lease: support mvcc txn 2017-03-08 20:54:15 -08:00
33acbb694b mvcc: txns and r/w views
Clean-up of the mvcc interfaces to use txn interfaces instead of an id.

Adds support for concurrent read-only mvcc transactions.

Fixes #7083
2017-03-08 20:52:59 -08:00
8d438c2939 backend: readtx
ReadTxs are designed for read-only accesses to the backend using a
read-only boltDB transaction. Since BatchTx's are long-running
transactions, all writes to BatchTx will writeback to ReadTx, overlaying
the base read-only transaction.
2017-03-08 20:52:59 -08:00
39dc5315ed Merge pull request #7461 from heyitsanthony/fix-member-remove
e2e: don't remove member used to connect to etcd cluster
2017-03-08 20:21:57 -08:00
cd7d68fed0 Merge pull request #7458 from reterVision/patch-1
Documentation: add Grab etcd use case
2017-03-08 19:59:31 -08:00
e4f40f6554 Merge pull request #7462 from gyuho/typo
*: fix minor typos
2017-03-08 16:41:18 -08:00
beb58c434c *: fix minor typos
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-08 16:21:52 -08:00
7f94afdb8c Documentation: add Grab etcd use case 2017-03-08 16:12:32 -08:00
13e36f963d e2e: don't remove member used to connect to etcd cluster
Fixes #7204
2017-03-08 15:58:45 -08:00
e016015196 Merge pull request #7455 from gyuho/release-doc
Documentation: sign source zip files
2017-03-08 15:57:30 -08:00
1bcbd82c8b Merge pull request #7457 from gyuho/lease-guard
lease: guard 'Lease.itemSet' from concurrent writes
2017-03-08 14:48:00 -08:00
7a25257fb2 clientv3: close balancer to avoid goroutine leak in balancer_test.go 2017-03-08 13:37:18 -08:00
9713b1f3ef Merge pull request #7454 from bdudelsack/gateway-dns-discovery
gateway: fix the dns discovery method
2017-03-08 13:07:59 -08:00
234c4b1685 Documentation: sign source zip files
For https://github.com/coreos/etcd/issues/7449

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-08 11:53:52 -08:00
6f0723f23f lease: guard 'Lease.itemSet' from concurrent writes
Fix https://github.com/coreos/etcd/issues/7448.

Affected if etcd builds with Go 1.8+.

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-08 11:01:42 -08:00
0d48fc5511 gateway: fix the dns discovery method
strip the scheme from the endpoints to have a clean hostname for TCP proxy

Fixes #7452
2017-03-08 19:11:55 +01:00
7f43fdde74 Merge pull request #7438 from meitu/master
Add use case in Meitu Inc.
2017-03-08 06:59:30 -08:00
3fa3d7dac6 doc: Add use case in Meitu Inc. 2017-03-08 14:27:53 +08:00
320768b2e9 Merge pull request #7435 from gnawux/use_case_hyper_sh
Add hyper.sh to production users
2017-03-07 19:14:30 -08:00
4a7b27921d doc: Add hyper.sh to production users 2017-03-08 10:45:56 +08:00
3f515e1849 Merge pull request #7441 from gyuho/warning
Documentation: warn membership change while migration
2017-03-07 11:38:28 -08:00
43eca30a08 Documentation: warn membership change while migration
Fix https://github.com/coreos/etcd/issues/7429.

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-07 11:27:36 -08:00
1a3a345468 Merge pull request #7437 from hustcat/tx-case
Add Tencent Games user case
2017-03-07 09:21:19 -08:00
3eb2fdbd99 Merge pull request #6082 from mitake/auth-v3-jwt
*: support jwt token in v3 auth API
2017-03-07 16:21:57 +09:00
df657d4690 Documentation: Add Tencent Games to production users 2017-03-07 15:17:10 +08:00
7907936066 Merge pull request #7433 from nekto0n/add_production_user
Documentation: add production user
2017-03-06 22:38:01 -08:00
1fc0803840 doc: update use case of qiniu 2017-03-06 22:11:17 -08:00
382ffe679d Documentation: add production user 2017-03-07 11:10:21 +05:00
831abf82b1 doc: add usecase of qiniu 2017-03-06 21:58:02 -08:00
ed90481510 Documentation: add qingcloud to production user 2017-03-06 19:53:47 -08:00
f8a290e7ca *: support jwt token in v3 auth API
This commit adds jwt token support in v3 auth API.

Remaining major ToDos:
- Currently token type isn't hidden from etcdserver. In the near
  future the information should be completely invisible from
  etcdserver package.
- Configurable expiration of token. Currently tokens can be valid
  until keys are changed.

How to use:
1. generate keys for signing and verfying jwt tokens:
 $ openssl genrsa -out app.rsa 1024
 $ openssl rsa -in app.rsa -pubout > app.rsa.pub
2.  add command line options to etcd like below:
--auth-token-type jwt \
--auth-jwt-pub-key app.rsa.pub --auth-jwt-priv-key app.rsa \
--auth-jwt-sign-method RS512
3. launch etcd cluster

Below is a performance comparison of serializable read w/ and w/o jwt
token. Every (3) etcd node is executed on a single machine. Signing
method is RS512 and key length is 1024 bit. As the results show, jwt
based token introduces a performance overhead but it would be
acceptable for a case that requires authentication.

w/o jwt token auth (no auth):

Summary:
  Total:        1.6172 secs.
  Slowest:      0.0125 secs.
  Fastest:      0.0001 secs.
  Average:      0.0002 secs.
  Stddev:       0.0004 secs.
  Requests/sec: 6183.5877

Response time histogram:
  0.000 [1]     |
  0.001 [9982]  |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
  0.003 [1]     |
  0.004 [1]     |
  0.005 [0]     |
  0.006 [0]     |
  0.008 [6]     |
  0.009 [0]     |
  0.010 [1]     |
  0.011 [5]     |
  0.013 [3]     |

Latency distribution:
  10% in 0.0001 secs.
  25% in 0.0001 secs.
  50% in 0.0001 secs.
  75% in 0.0001 secs.
  90% in 0.0002 secs.
  95% in 0.0002 secs.
  99% in 0.0003 secs.

w/ jwt token auth:

Summary:
  Total:        2.5364 secs.
  Slowest:      0.0182 secs.
  Fastest:      0.0002 secs.
  Average:      0.0003 secs.
  Stddev:       0.0005 secs.
  Requests/sec: 3942.5185

Response time histogram:
  0.000 [1]     |
  0.002 [9975]  |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
  0.004 [0]     |
  0.006 [1]     |
  0.007 [11]    |
  0.009 [2]     |
  0.011 [4]     |
  0.013 [5]     |
  0.015 [0]     |
  0.016 [0]     |
  0.018 [1]     |

Latency distribution:
  10% in 0.0002 secs.
  25% in 0.0002 secs.
  50% in 0.0002 secs.
  75% in 0.0002 secs.
  90% in 0.0003 secs.
  95% in 0.0003 secs.
  99% in 0.0004 secs.
2017-03-06 19:46:03 -08:00
a7a93f54a4 vendor: import jwt-go for auth v3 2017-03-06 19:46:03 -08:00
7b1ccca373 Merge pull request #7428 from siddontang/patch-1
Documentation: add PD to production users
2017-03-06 19:31:17 -08:00
a4a84184e8 Documentation: add PD to production users 2017-03-07 09:04:52 +08:00
e5d94a296f Merge pull request #7347 from gyuho/static-check
*: add 'staticcheck' to 'test'
2017-03-06 16:20:25 -08:00
3d75395875 *: remove never-unused vars, minor lint fix
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-06 14:59:12 -08:00
bd6e6c11f8 test: run 'staticcheck'
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-06 14:59:12 -08:00
79de3be6a7 Merge pull request #7430 from heyitsanthony/lock-more-deps
vendor: lock down some soft dependencies
2017-03-06 14:54:45 -08:00
db560574dd Merge pull request #7416 from heyitsanthony/test-eschew-you
test: eschew you
2017-03-06 13:30:57 -08:00
317f3571ff Merge pull request #7420 from heyitsanthony/dial-timeout-report
clientv3: pass back dial error on dial timeout
2017-03-06 12:58:18 -08:00
3f187a103b vendor: lock down some soft dependencies
Locks down:
* go-rundewidth (via tablewriter)
* golang.org/x/sys
* prometheus/{common,procfs} (via prometheus-client)
2017-03-06 12:03:45 -08:00
c8a2c7f64f *: eschew you from documentation
Removed line wrapping in affected files as well.
2017-03-06 11:40:46 -08:00
270dc9427b clientv3: pass back dial error on dial timeout
Fixes #7419
2017-03-06 09:33:10 -08:00
4e1ce81e17 test: eschew you
Per https://github.com/coreos/docs/blob/master/STYLE.md#eschew-you
2017-03-06 09:16:03 -08:00
4e2fe050f5 Merge pull request #7425 from mitake/gosimple
contrib: suppress gosimple errors of raftexample
2017-03-06 09:09:49 -08:00
b6eedbacf9 contrib: suppress gosimple errors of raftexample
Travis claimed errors of gosimple like below
(https://travis-ci.org/coreos/etcd/jobs/208098545):
gosimple checking failed:
contrib/raftexample/raftexample_test.go:78:6: should write erri := <-clus.errorC[i] instead of erri, _ := <-clus.errorC[i]
contrib/raftexample/raftexample_test.go:114:10: should write err := <-eC instead of err, _ := <-eC

This commit fixes the errors.
2017-03-06 16:17:22 +09:00
5039c7b4ab Merge pull request #7417 from purpleidea/feat/key-exists
clientv3: Add KeyExists and KeyNotExists Cmp helpers
2017-03-05 17:50:34 -08:00
8a57b90e7f Merge pull request #7422 from tmjd/docs_fix_migrate_example
etcdctl: Fix migrate example in README.md
2017-03-04 18:17:01 -08:00
9ba658f59b etcdctl: Fix migrate example in README.md 2017-03-04 19:42:27 -06:00
b68416f735 Merge pull request #7394 from gyuho/fix-advertise-client-url-host
*: use machine default host only for default value, 0.0.0.0
2017-03-03 16:35:31 -08:00
71937151d0 clientv3: Add KeyExists and KeyNotExists Cmp helpers
This is quite useful for transactions.
2017-03-03 18:45:10 -05:00
4aa68e0231 etcdmain: log machine default host after update check
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-03 14:25:39 -08:00
b7ee8f4967 embed: use machine default host only for default value, 0.0.0.0
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-03 14:25:34 -08:00
2831b9dcfd Merge pull request #7415 from gyuho/etcd-tester-lease-check-with-ttl
etcd-tester: check expired lease with -1 TTL
2017-03-03 12:49:58 -08:00
fb81fb44fa etcd-tester: check expired lease with -1 TTL
Following the change at 2ca1823a96

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-03 11:41:53 -08:00
e16db3347a Merge pull request #7413 from philips/update-etcd-integrations-and-users
production-users: add Kubernetes
2017-03-03 14:12:39 -05:00
e52f41a6d1 production-users: add Kubernetes 2017-03-03 13:09:36 -05:00
bd6f1c9e48 libraries-and-tools: rename to integrations
I want to create a more consistent naming system across the repos. Some
of our projects won't have libraries or tools (like Clair) but others
have integrated their software with Clair in various ways.

So, use a generic term: integrations.
2017-03-03 13:09:36 -05:00
85c22f4562 Merge pull request #7408 from heyitsanthony/v3-capable
api: default to V3 capability
2017-03-02 16:53:01 -08:00
42c98123b3 Merge pull request #7411 from heyitsanthony/mirror-batch
etcdctl: correctly batch revisions in make-mirror
2017-03-02 16:09:50 -08:00
ad45958841 etcdctl: correctly batch revisions in make-mirror
Fixes #7410
2017-03-02 14:30:24 -08:00
1753623f87 integration: don't set v3 capability since now default 2017-03-02 14:02:09 -08:00
5da5b834e5 api: default to V3 capability
Fixes #7154
2017-03-02 14:02:09 -08:00
9cc013fec0 Merge pull request #7409 from heyitsanthony/doc-ionice
Documentation: suggest ionice for disk tuning
2017-03-02 14:00:05 -08:00
1e252f1feb Documentation: suggest ionice for disk tuning
Also cleaned up tuning.md newlines to conform with style.
2017-03-02 13:58:07 -08:00
763aef87b9 Merge pull request #7405 from heyitsanthony/fast-gosimple
test: run unused and gosimple over all packages at once
2017-03-02 10:40:26 -08:00
6092e1ad24 Merge pull request #7403 from gyuho/do
Documentation/op-guide: use exact certs dir for Container Linux
2017-03-02 10:33:42 -08:00
ae0c4b4c87 Documentation/op-guide: use exact certs dir for Container Linux
Use the one that works in Container Linux

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-02 10:20:59 -08:00
3296c15a32 test: run unused and gosimple over all packages at once
fmt pass went from ~20 CPU minutes to ~1 CPU minute.

Fixes #7377
2017-03-02 10:17:46 -08:00
5cdb557560 Merge pull request #7390 from fanminshi/put_ctl_warning
etcdctl: show warning if ETCDCTL_API is not set
2017-03-02 10:17:19 -08:00
db91277216 Merge pull request #7400 from heyitsanthony/fix-example-ctx
clientv3: bump example requestTimeout for slow CI
2017-03-01 21:57:34 -08:00
2eb8243d94 Merge pull request #7402 from heyitsanthony/fix-watchconnerr
grpcproxy: return closing error when stream is canceled from conn close
2017-03-01 21:56:36 -08:00
134d1cb4e0 Merge pull request #7404 from xiang90/nt
raft: make TestNodeTick reliable
2017-03-01 20:02:25 -08:00
931cf3454a raft: make TestNodeTick reliable
TestNodeTick relies on a unreliable func `waitForSchedule` when running
with GOMAXPROCS > 1. This commit changes the test to make sure we stop
the node afte it drains the tick chan. The test should be reliable now.
2017-03-01 17:35:58 -08:00
010cc287bb Merge pull request #7401 from gyuho/docker-guide
op-guide: add notes on mounting certs directory
2017-03-01 16:50:24 -08:00
28e9ba365a grpcproxy: return closing error when stream is canceled from conn close
Fixes #6630
2017-03-01 16:46:13 -08:00
d111c8fe3b op-guide: add notes on mounting certs directory
Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
2017-03-01 16:45:03 -08:00
cf547aa403 clientv3: bump example requestTimeout for slow CI
Fixes #7398
2017-03-01 14:37:40 -08:00
f76ca01aed etcdctl: show warning if ETCDCTL_API is not set in v2 --help
FIXES #7385
2017-03-01 11:29:59 -08:00
d3aebbf0ce Merge pull request #7387 from fanminshi/rework_coverage_ctl
e2e: rework coverage ctl
2017-03-01 10:01:13 -08:00
edd298f85a test: build test binary for etcdctl 2017-02-28 17:08:24 -08:00
1f413cff64 e2e: add etcdctl to e2e test 2017-02-28 17:08:17 -08:00
aca4ea2a29 etcdctl: modify etcdctl v2 and v3 for code coverage 2017-02-28 14:50:27 -08:00
17ae440991 Merge pull request #7379 from fanminshi/fix_TestRestartMember
integration: integration: ensure leader is up in waitLeader() and clusterMustProgress()
2017-02-28 10:57:49 -08:00
324d2383b8 integration: ensure leader is up in waitLeader() and clusterMustProgress()
The issue is caused by leader loss even after waitLeader() returns
which can happen if the test machine is flaky which triggers a leader loss
or the killed node is the leader since waitLeader() only scans followers in
TestRestartMember() and they can have the same older leader.
In those cases, clusterMustProgress() proceeds with no leader which triggers
the no leader error.

To get around that, use linearizable get in waitLeader() to ensure leader is up
and retries on kapi.create() in clusterMustProgress() to ensure it proceeds with
a leader.

FIX #7258
2017-02-28 09:17:03 -08:00
1a9cd7bf36 Merge pull request #7294 from mkumatag/ppc64le_docker
Build docker image for ppc64le
2017-02-28 09:04:03 -08:00
8f744fe46b Merge pull request #7384 from heyitsanthony/debug-grpc-tracing
etcdmain: enable grpc tracing with --debug
2017-02-27 16:05:04 -08:00
633cfbe241 script: Build docker image for ppc64le 2017-02-27 19:04:32 -05:00
bbd8f4e6f6 Merge pull request #7386 from heyitsanthony/doc-lease-coalesce
Documentation: add documentation for grpc lease stream coalescing
2017-02-27 15:30:45 -08:00
22f0386683 Documentation: add documentation for grpc lease stream coalescing 2017-02-27 14:45:01 -08:00
c4f1e64de7 embed: enable debug endpoint if Debug is set and add net.trace events
/debug/ was only being enabled for Pprof.
2017-02-27 11:34:58 -08:00
298d58841e etcdmain: enable grpc tracing with --debug 2017-02-27 11:18:13 -08:00
01557ebc8f Merge pull request #7376 from heyitsanthony/fix-example-metrics-port
clientv3: use any port for metrics example
2017-02-24 16:24:52 -08:00
c231950cdb clientv3: use any port for metrics example
Was getting bind conflicts causing failures on semaphore.
2017-02-24 14:33:08 -08:00
15d8ca7726 Merge pull request #7375 from heyitsanthony/fix-e2e-cov
e2e: fix -tags cov builds
2017-02-24 13:01:11 -08:00
2ec8572a8c e2e: fix -tags cov builds
Wasn't compiling.
2017-02-24 09:47:31 -08:00
833aa518d8 Merge pull request #7372 from gyuho/updates
*: miscellaneous updates on release 3.2 cycle
2017-02-23 17:42:35 -08:00
9fbdd0a84a Merge pull request #7373 from gyuho/news
NEWS: add v3.1.2 release notes
2017-02-23 17:19:31 -08:00
3eaf2f6558 *: remove trailing space, upgrade test on v3.1 2017-02-23 16:19:24 -08:00
119d0520c6 NEWS: add v3.1.2 release notes 2017-02-23 15:02:36 -08:00
3f756d502b travis: use Go 1.8 in master branch 2017-02-23 14:38:47 -08:00
9d74eb5c60 MAINTAINERS: add Fanmin 2017-02-23 14:38:14 -08:00
86c9bf5c3f Merge pull request #7371 from gyuho/grpc-proxy-register
grpcproxy: add 'register' address
2017-02-22 17:30:38 -08:00
72a531e8b2 grpcproxy: add 'register' address
For https://github.com/coreos/etcd/issues/6902.
2017-02-22 16:47:48 -08:00
5df56fa615 Merge pull request #7366 from heyitsanthony/fix-watch-stream-counting
integration: permit background watch streams in TestWatchCancelOnServer
2017-02-22 10:36:36 -08:00
df3bb333ca Merge pull request #7368 from heyitsanthony/fix-netutil-ipv4
netutil: use ipv4 host by default
2017-02-22 09:57:56 -08:00
c3a678be75 integration: permit background watch streams in TestWatchCancelOnServer
Fixes #7272
2017-02-22 09:54:08 -08:00
c0c4c7cb76 Merge pull request #7364 from gyuho/auth-revi
auth: keep old revision in 'NewAuthStore'
2017-02-22 09:40:01 -08:00
f97a077257 netutil: use ipv4 host by default
Was non-deterministic.
2017-02-21 20:11:35 -08:00
f2e9936de5 integration: add 'TestV3HashRestart' 2017-02-21 16:20:56 -08:00
6431382a75 auth: keep old revision in 'NewAuthStore'
When there's no changes yet (right after auth
store initialization), we should commit old revision.

Fix https://github.com/coreos/etcd/issues/7359.
2017-02-21 16:18:47 -08:00
c90c757a56 Merge pull request #7355 from hhkbp2/fix-test-case-typo
raft: revise test case and fix typo
2017-02-21 16:15:22 -08:00
dd16463ad4 Merge pull request #7363 from heyitsanthony/fix-short-lease-ttl
clientv3: do not set next keepalive time <= now+TTL
2017-02-21 15:36:37 -08:00
25403970f5 Merge pull request #7361 from heyitsanthony/fix-gateway-goroutine
tcpproxy: don't use range variable in reactivate goroutine
2017-02-21 13:26:53 -08:00
12d3e4e473 integration: test keepalives for short TTLs 2017-02-21 13:15:45 -08:00
3c306cdb3e clientv3: do not set next keepalive time <= now+TTL 2017-02-21 13:15:45 -08:00
8b097f279d tcpproxy: don't use range variable in reactivate goroutine
Ends up trying to reactivate only the last endpoint.
2017-02-21 12:39:49 -08:00
0c0fbbd7c5 Merge pull request #7342 from heyitsanthony/client-version
clientv3: version checking
2017-02-21 11:46:48 -08:00
3c20bdd004 Merge pull request #7345 from heyitsanthony/fix-stream-err
grpcproxy: only return ctx error in chan stream if recvc is empty
2017-02-21 11:08:49 -08:00
86cb9f2490 Merge pull request #7358 from gyuho/manual
clientv3: fix typo in README
2017-02-21 11:03:49 -08:00
29a6fd65ad grpcproxy: only return ctx error in chan stream if recvc is empty
Since select{} won't prioritize, ctx.Done() can sometimes override
a pending message on recvc. Loop if recvc has messages instead.

Fixes #7340
2017-02-21 10:53:58 -08:00
56b4e6b71f clientv3: fix typo in README
Fix https://github.com/coreos/etcd/issues/7337
2017-02-21 10:33:17 -08:00
2ac44eab81 Merge pull request #7341 from gyuho/host
op-guide: use host volume in Docker command
2017-02-21 10:31:50 -08:00
6f193ea1df op-guide: use host volume in Docker command 2017-02-21 10:28:29 -08:00
4e114d3549 Merge pull request #7351 from davecheney/fixedbugs/7350
pkg/transport: remove dependency on pkg/fileutils
2017-02-21 09:21:53 -08:00
bc6bebe7b0 raft: revise test case and fix typo 2017-02-21 15:23:42 +08:00
9b84127739 pkg/transport: remove dependency on pkg/fileutils
4a0f922 changed SelfCert to use a helper from pkg/fileutils which
introduced a transitive dependency on coreos/pkg/capnslog. This means
anyone who imports pkg/transport to use TLS with the clientv3 library
has the default stdlib logger hijacked by capnslog.

This PR reverts 4a0f922. There are no tests because 4a0f922 contained no
test and was not attached to a PR.

Fixes #7350
2017-02-20 12:32:04 +11:00
2533c2a50c Merge pull request #7254 from fanminshi/rework_coverage_e2e
e2e: add code coverage to e2e
2017-02-17 15:51:47 -08:00
f203a61469 e2e: unshadow err and remove bogus err checking in spawnWithExpects() 2017-02-17 14:47:24 -08:00
07129a6370 *: add and expose StopSignal field in ExpectProcess
add and expose StopSignal to ExpectProcess allows user
to define what signal to send on ExpectProcess.close()

coverage testing code sets StopSignal to SIGTERM allowing
the test binary to shutdown gracefully so that it can generate
a coverage report.
2017-02-17 14:47:06 -08:00
78fbe669ad Merge pull request #7332 from hhkbp2/fix-read-index
raft: fix read index request for #7331
2017-02-17 14:27:42 -08:00
b5be18a744 test: add e2e to coverage test 2017-02-17 14:15:26 -08:00
51435df179 integration: test RejectOldCluster 2017-02-16 21:33:14 -08:00
4d2aa80ecf clientv3: add cluster version checking 2017-02-16 18:14:14 -08:00
c9452c6ad4 clientv3: let user provide a client context through Config 2017-02-16 18:14:14 -08:00
9342647e0c raft: fix read index request for #7331 2017-02-17 09:45:41 +08:00
a5cf7fdc87 Merge pull request #7221 from fanminshi/grpcproxy_support_lease_coalescing
grpcproxy: support lease coalescing
2017-02-16 13:42:49 -08:00
507bd2ab4b Merge pull request #7339 from xiang90/fix_l
clientv3: fix lease keepalive duration
2017-02-16 13:35:27 -08:00
4fb8d30f0a clientv3: fix lease keepalive duration 2017-02-16 12:04:07 -08:00
5d3597a5f2 Merge pull request #7338 from xiang90/fix_l
clientv3: fix lease keepalive duration
2017-02-16 11:58:10 -08:00
65b59f4423 grpcproxy: incorporate lease proxy into existing proxy framework 2017-02-16 11:50:59 -08:00
ba52bd07ba grpcproxy: add lease coalescing support 2017-02-16 11:50:50 -08:00
05b82f2022 grpcproxy: refactor chan stream out of watch_client_adapter 2017-02-16 11:41:21 -08:00
4274db46f2 clientv3: fix lease keepalive duration 2017-02-16 11:25:26 -08:00
49a12371c1 Merge pull request #7335 from heyitsanthony/leadership-kick
grpcproxy: support forcing leader as available
2017-02-16 09:40:08 -08:00
4608210154 Documentation/libraries-and-tools: add vitess 2017-02-15 21:35:19 -08:00
80de75431e grpcproxy: support forcing leader as available
Leadership timeout can sometimes take too long, such as in test cases.
However, it is possible to infer a leader is available based on RPCs
that must go through consensus. Therefore, have a way to update the
leadership status off the watch path.
2017-02-15 16:49:41 -08:00
2510a1488c Merge pull request #7327 from heyitsanthony/fix-runtime-conf-doc
op-guide: fix remove instructions in runtime-configuration and conform to style
2017-02-15 10:22:47 -08:00
80ab321f9d etcdmain: whitelist etcd binary flags 2017-02-15 09:51:50 -08:00
1d521556ae e2e: modify e2e to run code coverage 2017-02-15 09:51:50 -08:00
2f8b9ce9aa Merge pull request #7314 from heyitsanthony/fix-leadership
grpcproxy: split out / tighten up leadership detection
2017-02-15 07:01:38 -08:00
a4a8393cb7 integration: wait five elections before creating watch for require leader test
Otherwise new watch will race with the leader watcher receiving the loss event.
2017-02-15 00:16:25 -08:00
36f5b713bf grpcproxy: don't wait for ctx.Done() to close kv donec
Causes a goroutine leak in ActiveConnection.Close() tests. Channel is
vestigial since removing ccache; revisit if kv ever needs goroutines.
2017-02-15 00:16:25 -08:00
49a0a63fc3 grpcproxy: split out leadership detection code
Move out of watch code since will be shared with lease code. Also assumes
leader does not exist unless watch can be successfully created.
2017-02-15 00:16:25 -08:00
ad1b754e02 Merge pull request #7330 from fanminshi/fix_keepAliveOnce
clientv3: KeepAliveOnce returns ErrLeaseNotFound if TTL <= 0
2017-02-14 15:42:18 -08:00
8cb5e05fc9 clientv3: KeepAliveOnce returns ErrLeaseNotFound if TTL <= 0 2017-02-14 15:19:29 -08:00
67e3fc55d7 op-guide: fix remove instructions in runtime-configuration and conform to style
Fixes #7326
2017-02-14 13:41:51 -08:00
78d153fc5a Merge pull request #7328 from heyitsanthony/travis-spam
travis: disable email notifications
2017-02-14 12:33:32 -08:00
2cc273291d travis: disable email notifications
Was spamming security@coreos.com
2017-02-14 12:08:49 -08:00
808ee4e57c Merge pull request #7313 from gyuho/simplify-auth
auth: simplify merging range perm
2017-02-14 14:18:06 +09:00
3d994f8653 Merge pull request #7317 from petermattis/pmattis/ready-must-sync
raft: add Ready.MustSync
2017-02-13 17:53:08 -08:00
c200be6432 Merge pull request #7319 from heyitsanthony/fix-compact-watch
grpcproxy: respect CompactRevision in watcher
2017-02-13 16:46:34 -08:00
e0ddded077 auth: simplify merging range perm
No need of separate function to filter duplicates.
Just merge ranges in-place

```
go test -v -run=xxx -bench=BenchmarkMergeOld -benchmem
BenchmarkMergeOld-8   	  100000	     13524 ns/op	    1104 B/op	       8 allocs/op

go test -v -run=xxx -bench=BenchmarkMergeNew -benchmem
BenchmarkMergeNew-8   	  100000	     13432 ns/op	     936 B/op	       3 allocs/op
```

Not much performance boost, but less memory allocation
and simpler
2017-02-13 16:37:43 -08:00
853f68071b grpcproxy: respect CompactRevision in watcher
CompactRevision wasn't sent over watch stream, causing TestKVCompact to hang.
2017-02-13 15:43:41 -08:00
43740a8d3c Merge pull request #7318 from heyitsanthony/limit-doc
etcdserverpb, clientv3: clarify WithLimit documentation
2017-02-13 15:35:37 -08:00
e52a985a3a Merge pull request #7307 from heyitsanthony/proxy-countonly
grpcproxy: support CountOnly
2017-02-13 13:30:31 -08:00
fb7dd0f688 etcdserverpb, clientv3: clarify WithLimit documentation
Fixes #7316
2017-02-13 12:37:44 -08:00
ab03a42f06 raft: add Ready.MustSync
Add Ready.MustSync which indicates that the hard state and raft log
entries in a Ready message must be synchronously written to persistent
storage.
2017-02-13 15:13:21 -05:00
2925f02aac Merge pull request #7305 from fanminshi/return_header_for_timetolive
lease: LeaseTimeToLive returns TTL=-1 resp on lease not found
2017-02-13 11:24:36 -08:00
0d08ffa282 integration: don't expect lease not found error for TestV3GetNonExistLease 2017-02-10 17:35:43 -08:00
bcfbb096e2 clientv3/integration: test lease not found on TimeToLive() 2017-02-10 16:41:47 -08:00
2ca1823a96 v3rpc: LeaseTimeToLive returns TTL=-1 resp on lease not found 2017-02-10 16:33:31 -08:00
c22ba766d5 grpcproxy: support CountOnly
TestKVRange from client integration tests was failing.
2017-02-10 16:06:24 -08:00
9f8e82e1c0 Merge pull request #7304 from heyitsanthony/remove-ccache
Remove ccache
2017-02-10 16:02:31 -08:00
1fe2a9b124 Revert "Merge pull request #7139 from heyitsanthony/proxy-rlock"
This reverts commit 304606ab0b, reversing
changes made to 7dfe503f1c.
2017-02-10 14:37:48 -08:00
47cb8a012a Merge pull request #7301 from ghostplant/master
Fix a command error.
2017-02-10 09:31:22 -08:00
cc14f14216 Documentation: replace px typo with ps
Signed-off-by: CUI Wei <ghostplant@qq.com>
2017-02-11 00:23:37 +08:00
1a4a4fa7ac Merge pull request #7295 from mkumatag/fix_gosimple
test: Fix gosimple errors
2017-02-09 07:39:55 -08:00
98249bc950 Merge pull request #7297 from mkumatag/update_travis
travis: Update fmt check gotools
2017-02-09 07:26:00 -08:00
5afa4e4fdf travis: Update fmt check gotools 2017-02-09 10:17:36 -05:00
0914b8b707 test: Fix gosimple errors
Getting gosimple suggestion while running test script, so this PR is for fixing gosimple S1019 check.
raft/node_test.go:456:40: should use make([]raftpb.Entry, 1) instead (S1019)
raft/node_test.go:457:49: should use make([]raftpb.Entry, 1) instead (S1019)
raft/node_test.go:458:43: should use make([]raftpb.Message, 1) instead (S1019)

Refer https://github.com/dominikh/go-tools/blob/master/cmd/gosimple/README.md#checks for more information.
2017-02-09 08:01:28 -05:00
c4fc8c0989 Merge pull request #7260 from mitake/auth-state
auth: correct initialization in NewAuthStore()
2017-02-08 18:11:13 -08:00
9b72c8ba1b Merge pull request #7285 from fanminshi/uses_direct_client_call_for_tests
clientv3: integration test uses direct client calls
2017-02-07 12:09:37 -08:00
366e689eae clientv3: uses direct client calls in integration tests
clientv3 integration test was using clientv3.NewKV, clientv3.NewWatcher, etc to create specific client.
replace those with direct client calls so that the direct calls can also test grpc proxy.
2017-02-07 11:09:19 -08:00
0944a50d3f Merge pull request #7288 from fanminshi/fix_TestLeaseKeepAliveInitTimeout_test
clientv3/integration:  stop member before keepalive in TestLeaseKeepAliveInitTimeout
2017-02-07 10:48:54 -08:00
c182428e52 clientv3/integration: stop member before keepalive in TestLeaseKeepAliveInitTimeout 2017-02-07 10:07:03 -08:00
bf5ecf6555 Merge pull request #7262 from mkumatag/ppc64le_binary
scripts: Add support to build ppc64le binary for release
2017-02-07 09:52:12 -08:00
cf5cc18f02 Merge pull request #7286 from heyitsanthony/lease-snip-cancel-stop
clientv3: remove cancelWhenStop from lease implementation
2017-02-07 09:12:34 -08:00
a213b3abf5 clientv3: remove cancelWhenStop from lease implementation
Only have Close() cancel out outstanding goroutines. Canceling out
single-shot RPCs will mask connection close on client.Close().
2017-02-06 17:21:46 -08:00
739accc242 Merge pull request #7281 from heyitsanthony/no-default-ka
clientv3: only start lease stream after first keepalive call
2017-02-06 13:51:43 -08:00
a9f10bdeee clientv3: only start lease stream after first keepalive call
Fixes #7274
2017-02-06 11:52:57 -08:00
9976d869c1 auth: correct initialization in NewAuthStore()
Because of my own silly mistake, current NewAuthStore() doesn't
initialize authStore in a correct manner. For example, after recovery
from snapshot, it cannot revive the flag of enabled/disabled. This
commit fixes the problem.

Fix https://github.com/coreos/etcd/issues/7165
2017-02-06 16:05:49 +09:00
280b65fe4d auth: add a test case for recoverying from snapshot 2017-02-06 15:42:09 +09:00
6fb99a8585 Merge pull request #7276 from fanminshi/fix_lease_keep_alive_loop
clientv3: sends keepalive reqs immediately after lease keep alive stream reset
2017-02-04 21:28:56 -08:00
4d055ca73b Merge pull request #7277 from gyuho/second-point
pkg/report: add min/max latency per second
2017-02-04 12:47:12 -08:00
950a9da9d9 pkg/report: add min/max latency per second
For https://github.com/coreos/dbtester/issues/221.
2017-02-04 12:46:54 -08:00
720234d32b clientv3: sends keepalive reqs immediately after lease keep alive stream reset
when lease client reset lease keep alive stream, sendKeepAliveLoop() should send out keep alive reqs immediately instead of waiting for 500ms.
2017-02-03 16:36:24 -08:00
23b5a29101 Merge pull request #7273 from heyitsanthony/snip-prom
clientv3: add DialOptions to config
2017-02-03 15:54:20 -08:00
8c43bd06a0 clientv3: add DialOptions to config
Removes strict prometheus dependency.

Fixes #7058
2017-02-03 12:00:20 -08:00
4203c766fb Merge pull request #7270 from gyuho/pkg
pkg/netutil: name GetDefaultInterfaces consistent
2017-02-03 08:06:15 -08:00
01a1dae7ae pkg/netutil: name GetDefaultInterfaces consistent 2017-02-03 00:37:31 -08:00
d159353d51 Merge pull request #7268 from heyitsanthony/proxy-test-clientv3
test: add proxy tests for clientv3 integration tests
2017-02-02 20:31:05 -08:00
ae5c89ff12 Merge pull request #7266 from heyitsanthony/snip-yaml
clientv3: remove strict yaml dependency
2017-02-02 16:07:12 -08:00
56c706ff91 Merge pull request #7269 from sinsharat/use_requestWithContext_for_cancel
*: Use http.Request.WithContext instead of Cancel
2017-02-02 09:53:09 -08:00
e42fa18ccf grpcproxy: don't use WithRequireLeader for watch event stream
Ohterwise leader loss will reject all stream creation.
2017-02-02 09:32:25 -08:00
9def4cb9fe *: Use http.Request.WithContext instead of Cancel 2017-02-02 22:50:07 +05:30
e3f4b43614 test: clientv3 integration tests with proxy 2017-02-01 22:04:18 -08:00
b465b48476 clientv3: remove strict yaml dependency
Moved to clientv3/yaml
2017-02-01 21:02:45 -08:00
42e7d4d09d Merge pull request #7255 from sinsharat/use_requestWithContext_for_cancel
rafthttp: use http.Request.WithContext instead of Cancel
2017-02-01 15:49:43 -08:00
f74142187d Merge pull request #7263 from Rushit/test_isadminpermited
auth: test for AuthStore.IsAdminPermitted
2017-02-01 13:46:31 -08:00
2656b594bb rafthttp: use http.Request.WithContext instead of Cancel 2017-02-02 02:30:36 +05:30
5d41e7f09b scripts: Add support to build ppc64le binary for release 2017-02-02 00:45:56 +05:30
beef5eea37 auth: test for AuthStore.IsAdminPermitted
This will cover test for AuthStore.IsAdminPermitted in store.go
2017-02-01 08:39:09 -08:00
0df1822212 Merge pull request #7257 from Rushit/auth_test
auth: unit-test for authStore.AuthDisable()
2017-01-31 20:45:39 -08:00
46cac6f292 auth: unit-test for authStore.AuthDisable()
This will cover unit-test for AuthDisable in store.go
2017-01-31 18:18:56 -08:00
89bb9048dd Merge pull request #6881 from mitake/auth-v3-cn
authenticate clients based on certificate CommonName in v3 API
2017-01-31 17:21:53 -08:00
c6e9892af4 Merge pull request #7256 from Felixoid/issue_7219
netutil: add dualstack to linux_route
2017-01-31 16:49:40 -08:00
0f53ad0b84 netutil: add dualstack to linux_route
in v3.1.0 netutil couldn't get default interface for ipv6only hosts

Fixes #7219
2017-01-31 22:19:47 +03:00
cd9f0a1721 e2e: add a case for CommonName auth of v3 API 2017-01-31 17:22:12 +09:00
0191509637 auth, etcdserver: authenticate clients based on certificate CommonName
This commit lets v3 auth mechanism authenticate clients based on
CommonName of certificate like v2 auth.
2017-01-31 17:22:12 +09:00
7d6280fa82 Merge pull request #7248 from ravigadde/session-w-lease
clientv3: start a session with existing lease
2017-01-30 20:12:23 -08:00
c586218ec6 clientv3: start a session with existing lease
This change is needed to handle process restarts with elections. When the
leader process is restarted, it should be able to hang on to the leadership
by using the existing lease.

Fixes #7166
2017-01-30 18:07:22 -08:00
d2716fc5ae Merge pull request #7238 from mkumatag/support_ppc64le
ppc64le platform support
2017-01-26 21:16:33 -08:00
9767098331 etcdmain: ppc64le platform support 2017-01-26 21:08:07 -08:00
f127f462c6 Merge pull request #7229 from Rushit/auth-tests
auth: Adding unit tests
2017-01-27 11:52:03 +09:00
75ae50a90f Merge pull request #7243 from gyuho/doc
contrib: add etcd cluster deploy on systemd docs
2017-01-26 17:04:21 -08:00
5dace5f6dc Merge pull request #7242 from xiang90/fix_test
e2e: do not remove the member we connect to
2017-01-26 16:59:03 -08:00
19d30fd4a7 contrib: add etcd cluster deploy on systemd docs
Fix https://github.com/coreos/etcd/issues/5971
2017-01-26 16:56:55 -08:00
78540c5e7b e2e: do not remove the member we connect to 2017-01-26 15:43:27 -08:00
3351a71e84 Merge pull request #7240 from fanminshi/balancer_fix
clientv3: fix balancer update address bug
2017-01-26 15:08:50 -08:00
ae2e8fa462 Merge pull request #7241 from nmiyake/fixTestMessage
test: fix failure message in TestEmbedEtcd
2017-01-26 14:42:02 -08:00
18af48a9dc integration: add test case in dial_test to ensure balancer.updateAddrs works properly 2017-01-26 14:21:29 -08:00
e3b325c196 test: fix failure message in TestEmbedEtcd 2017-01-26 14:00:32 -08:00
9dbde1cc52 Merge pull request #7236 from heyitsanthony/no-dns-bind
embed: reject domain names before binding (again)
2017-01-26 13:52:30 -08:00
0c4e67c1f4 clientv3: fix balancer update address bug 2017-01-26 13:33:10 -08:00
5a67b0aba6 embed: reject binding listeners to domain names
Fixes #6336
2017-01-26 12:37:34 -08:00
63572567b4 integration: test domain name URLs are rejected before binding 2017-01-26 12:37:34 -08:00
54cf0317c3 Merge pull request #7237 from heyitsanthony/bump-e2e
test: bump e2e timeout to 15 minutes
2017-01-26 12:32:40 -08:00
b1b78c537c auth: Adding unit tests
This covers tests for User and Role related operations.
This tests brings code coverage in store.go from 40.2% to 72.1%.
2017-01-26 09:03:52 -08:00
6838ac3ba5 Merge pull request #7234 from Rushit/store_test_refactoring
auth: refactor auth store test to use common setup
2017-01-26 14:52:17 +09:00
072eda508b test: bump e2e timeout to 15 minutes
PPC64 timing out; integration tests already at 15 minutes.
2017-01-25 20:56:31 -08:00
fa1cbd5890 auth: refactor test to use common setup
Refactored tests to pull common setup into a method.
2017-01-25 19:07:15 -08:00
094be295a1 Merge pull request #7227 from heyitsanthony/clientv3-dial-ctx
clientv3: use DialContext
2017-01-25 13:28:29 -08:00
56286ccd29 clientv3: use DialContext
Fixes #7216
2017-01-25 09:49:41 -08:00
a2c44a8b65 clientv3: test closing client cancels blocking dials 2017-01-25 09:49:41 -08:00
11619f8db2 Merge pull request #7233 from rlenferink/documentation
Documentation: Deleted non-existing project from libraries-and-tools.md
2017-01-25 09:06:48 -08:00
eb42a5cb2f Documentation: Deleted non-existing project from libraries-and-tools.md 2017-01-25 11:43:56 -05:00
55c98982d1 Merge pull request #7231 from rlenferink/documentation
Documentation: C library added
2017-01-25 06:56:49 -08:00
10a401c7c6 Documentation: C library added 2017-01-25 15:10:48 +01:00
fb7365ef3c Merge pull request #7230 from Rushit/gitignore
.gitignore: Adding .idea to .gitignore
2017-01-24 22:25:52 -08:00
af20ba21cb .gitignore: Adding .idea to .gitignore
This will keep  all intellij IDEA IDE related files out of git.
This helps contributors using IDEA IDE for development.
2017-01-24 22:14:20 -08:00
6bef2bddca Merge pull request #7215 from disksing/grpc-service
embed: support user defined grpc services.
2017-01-24 15:02:43 -08:00
d7cc9be3fd Merge pull request #7214 from sinsharat/support_put_ignore_lease
*: 'ignore_lease' to detach value with PutRequest
2017-01-24 14:53:51 -08:00
2fce80e4c0 grpcproxy: handle 'IgnoreLease' field in PutRequest 2017-01-25 03:14:31 +05:30
37fb2c454f e2e: test put command with '--ignore-lease' flag 2017-01-25 03:12:48 +05:30
84a81d8caf ctlv3: add '--ignore-lease' flag to put command 2017-01-25 03:11:19 +05:30
d3191d1afb clientv3: add WithIgnoreLease option 2017-01-25 03:09:30 +05:30
95edd1bc58 integration: put,txn with 'ignore_lease' flag 2017-01-25 03:07:23 +05:30
8a87769a09 etcdserver: use prev-lease for 'ignore_lease' writes 2017-01-25 03:05:55 +05:30
5ac4e4255a v3rpc: error for non empty lease with 'ignore_lease' 2017-01-25 03:04:07 +05:30
508c9dfe5c *: regenrate proto files with 'ignore_lease' 2017-01-25 03:01:47 +05:30
a9bf593bdc *: 'ignore_lease' to detach value with PutRequest 2017-01-25 02:59:30 +05:30
90f6a4a28d Merge pull request #7226 from gyuho/vendor
ctlv3: right-align table output, fix typo in vendor
2017-01-24 12:03:58 -08:00
ce9f73a34c ctlv3: right-align the table output 2017-01-24 11:41:47 -08:00
a674116f07 vendor: update tablewritier 2017-01-24 11:41:47 -08:00
b9bbfda874 Merge pull request #7210 from jimmycuadra/rust-etcd
Add rust-etcd to the list of libraries.
2017-01-24 07:53:15 -08:00
13b70ed545 tools: add rust-etcd to the list of libraries. 2017-01-24 01:41:37 -08:00
0fea49f8fa Merge pull request #7222 from gyuho/manual
client: add GetVersion method
2017-01-23 19:14:49 -08:00
02f4a9a034 client: add GetVersion method
For retrieving etcdserver and etcdcluster version
2017-01-23 18:52:39 -08:00
ab532524b0 Merge pull request #7206 from heyitsanthony/redoc-rangerequest
etcdserverpb: rework documentation for range request
2017-01-23 13:08:04 -08:00
aace95a5bd Merge pull request #7209 from heyitsanthony/etcdmain-help
etcdmain: add gateway and grpc-proxy commands to etcd help
2017-01-23 13:07:30 -08:00
e75f52b97a Merge pull request #7220 from vimalk78/fix-recipes-newSequentialKV-comment
contrib/recipes/key.go : fixed comment in method newSequentialKV
2017-01-23 12:47:48 -08:00
6443c25422 contrib/recipes/key.go : fixed method comment 2017-01-23 23:42:50 +05:30
e0f4dd4cca Merge pull request #7079 from heyitsanthony/stm-prefetch
STM: prefetch and more
2017-01-23 09:45:36 -08:00
8b952fb8dc Merge pull request #7217 from xiang90/doc
doc: mention HTTP JSON in doc link
2017-01-23 09:41:57 -08:00
5aab92414f Merge pull request #7199 from heyitsanthony/netutil-test-arch
pkg/netutil: use native byte ordering
2017-01-23 09:41:20 -08:00
861cb5cfa2 embed: add example for ServiceRegister. 2017-01-23 10:47:01 +08:00
165c77f14e doc: mention HTTP JSON in doc link
It is not clear to users immediately what is the gRPC
gateway. Adding a more explaination to make it clear that
etcd3 supports HTTP API through the gateway.
2017-01-22 10:55:21 -08:00
4374d944d4 embed: support user defined grpc services.
Fixes #7200
2017-01-22 18:21:19 +08:00
89f7cc51fa Merge pull request #7155 from andrewstuart/upgrade-etcd3-docs
Documentation: add upgrade gotchas/further info for better visibility on google, etc
2017-01-21 12:56:07 -08:00
deb11b3594 Documentation: Add upgrade gotchas/further info for better search visibility 2017-01-21 13:46:27 -07:00
555b8047e6 integration: fix STM tests to compile against new interface 2017-01-20 16:30:58 -08:00
13420b33a0 benchmark: update for new stm interface 2017-01-20 16:22:43 -08:00
8695511153 concurrency: STM snapshot isolation level 2017-01-20 16:22:43 -08:00
8604d1863b concurrency: STM WithPrefetch option
Fixes #6923
2017-01-20 16:22:42 -08:00
a81234a25b concurrency: extend STM interface to Get from any of a list of keys
Now possible to fetch multiple keys in a single txn.
2017-01-20 16:22:42 -08:00
59880a0ab8 concurrency: variadic stm options
Makes txn isolation and the context variadic options.
2017-01-20 16:22:42 -08:00
7e31ddd32a etcdserverpb: rework documentation for range request 2017-01-20 16:12:09 -08:00
dfb2ed07db etcdmain: add gateway and grpc-proxy commands to etcd help 2017-01-20 15:54:13 -08:00
92cec10103 Merge pull request #7208 from gyuho/REAMDE
README: remove ACI, update Go version
2017-01-20 14:19:58 -08:00
074af101f1 Merge pull request #7207 from xiang90/roadmap
roadmap: update roadmap
2017-01-20 13:58:20 -08:00
aa79523d33 roadmap: update roadmap 2017-01-20 13:50:36 -08:00
367b064bcd README: remove ACI, update Go version 2017-01-20 13:42:11 -08:00
3196d08c7a Merge pull request #7205 from gyuho/doc
op-guide: change grpc-proxy from 'pre' to alpha'
2017-01-20 13:23:01 -08:00
b788790e56 op-guide: change grpc-proxy from 'pre' to alpha' 2017-01-20 13:20:32 -08:00
71c45906ad Merge pull request #7196 from heyitsanthony/build-goget
documentation: update build documentation
2017-01-20 11:19:50 -08:00
a630735c29 Merge pull request #7170 from vimalk78/make-v2-endpoint-optional-#7100
embed/etcd.go: make v2 endpoint optional. fixes #7100
2017-01-20 11:14:20 -08:00
5d8cceb164 Merge pull request #7183 from vimalk78/fix-test-script-function-arguments
test: passed the test script arguments to the function parameters
2017-01-20 11:09:09 -08:00
06a27d8590 documentation: update build documentation 2017-01-20 11:04:40 -08:00
1ada4f939f pkg/netutil: use native byte ordering for route information
Fixes #7199
2017-01-20 10:44:05 -08:00
9d0d4be7d1 Merge pull request #7203 from xiang90/fix_snap
etcdctlv3: snapshot restore works with lease key
2017-01-20 10:05:22 -08:00
3902d5ab0a Merge pull request #7195 from gyuho/fix-stm-restart
concurrency: fix stm restart on concurrent key deletion
2017-01-20 09:49:16 -08:00
96e0f50673 etcdctlv3: snapshot restore works with lease key 2017-01-20 09:37:39 -08:00
82d56b6314 Merge pull request #7197 from vimalk78/fix-ETCD-prefix-check
pkg/flags: fixed prefix checking of the env variables
2017-01-20 08:17:02 -08:00
e446c2c2c7 pkg/cpuutil: add cpuutil
A package for unsafe cpu-ish things.
2017-01-20 01:47:56 -08:00
e4b8c874d2 pkg/flags: fixed prefix checking of the env variables 2017-01-20 13:13:40 +05:30
a94d20d1e4 integration: test STM apply on concurrent deletion 2017-01-19 22:59:01 -08:00
f80914fba2 embed/etcd.go: make v2 endpoint optional. fixes #7100 2017-01-20 11:49:52 +05:30
acec15ebc6 clientv3/concurrency: fix rev comparison on concurrent key deletion 2017-01-19 20:51:31 -08:00
94eec5d41a Merge pull request #7193 from gyuho/manual
Documentation: fix typo s/endpoint-health/endpoint health/
2017-01-19 20:47:17 -08:00
1cd3fd81c8 Merge pull request #7194 from gyuho/backport
NEWS: fix date for v3.1 release
2017-01-19 17:56:14 -08:00
8ad5e29447 NEWS: fix date for v3.1 release 2017-01-19 16:59:02 -08:00
be28981234 Documentation: fix typo s/endpoint-health/endpoint health/ 2017-01-19 16:52:26 -08:00
4fad94246d Merge pull request #7190 from gyuho/docs
Documentation: update experimental_apis for v3.1 release
2017-01-19 12:41:58 -08:00
8a779ce709 Merge pull request #7144 from tobilarscheid/enhancement/highlight-differences-in-docker-commands
Highlight differences between example run commands in docker_guide
2017-01-19 12:29:52 -08:00
81c1288d60 Documentation: update experimental_apis for v3.1 release 2017-01-19 11:32:06 -08:00
5cf0d6678b Merge pull request #7174 from vimalk78/support-v3-txn-without-condition
clientv3/txn.go : removed the TODO: add a Do for shortcut the txn without any condition
2017-01-19 08:45:34 -08:00
d03d7f0c0d Merge pull request #7188 from jl2005/dir-expire
store: set e.Node.Dir attribute, when node expired
2017-01-19 08:33:37 -08:00
99639186cd store: set Dir attribute, when node expired 2017-01-19 18:00:56 +08:00
eb88a5f288 Polish note about varying parameters for each member 2017-01-18 14:55:02 -08:00
b2d5c91f0e Merge pull request #7186 from gyuho/vendor
*: update 'golang.org/x/net/context' and its dependencies
2017-01-18 13:09:57 -08:00
90509008e9 Merge pull request #7159 from heyitsanthony/proxy-stop-cache
grpcproxy, etcdmain, integration: add close channel to kv proxy
2017-01-18 13:04:31 -08:00
8c0282ab24 grpcproxy, etcdmain, integration: add close channel to kv proxy
ccache launches goroutines that need to be explicitly stopped.

Fixes #7158
2017-01-18 11:51:16 -08:00
85e14a841a vendor: update 'golang.org/x/net' 2017-01-18 10:29:49 -08:00
933bcac6da glide: update 'golang.org/x/net' 2017-01-18 10:29:43 -08:00
293c75b133 test: passed the test script arguments as the test function parameters 2017-01-18 21:28:57 +05:30
fcaa509e4c clientv3/txn.go : removed the TODO: add a Do for shortcut the txn without any condition 2017-01-18 11:37:29 +05:30
1a962df596 Merge pull request #7176 from heyitsanthony/bump-lread-timeout
etcdserver: use ReqTimeout for linearized read
2017-01-17 16:08:50 -08:00
5c774ff571 etcdserver: use ReqTimeout for linearized read
Fixes #7136
2017-01-17 14:55:39 -08:00
307e14028c Merge pull request #7175 from gyuho/report
pkg/report: add nil checking for getTimeSeries
2017-01-17 13:22:20 -08:00
462dbfe10d Merge pull request #7172 from gyuho/upgrade-doc
Documentation: document upgrading to v3.1
2017-01-17 13:21:37 -08:00
abf7847fa5 Documentation: document upgrading to v3.1 2017-01-17 13:20:24 -08:00
69606bb95f pkg/report: add nil checking for getTimeSeries 2017-01-17 12:51:47 -08:00
3a40421aa5 Merge pull request #7157 from fanminshi/clientv3_balancer_uses_one_connection
clientv3: balancer uses one connection at a time
2017-01-17 12:12:35 -08:00
2db9d3b702 Merge pull request #6440 from lclarkmichalek/how-to-ssl-question-mark
Obey the usual rules of SSL server name verification when using a private PKI
2017-01-17 10:28:22 -08:00
bad2f03cd0 Merge pull request #7173 from gyuho/manual
ctlv3: print cluster info after adding new member
2017-01-17 10:15:39 -08:00
df55438a60 clientv3: balancer uses one connection at a time
FIX #7080
2017-01-17 10:09:41 -08:00
b8e9bd2b42 ctlv3: print cluster info after adding new member 2017-01-17 09:52:38 -08:00
eba41cd7b3 pkg/transport: Obey the usual laws of ssl when using a private PKI 2017-01-15 21:27:53 +00:00
017ea3df50 Merge pull request #7164 from elimisteve/patch-1
clientv3: Fixed []byte to string conversion syntax in KV comment
2017-01-15 13:12:01 -08:00
eb7a804ca8 kv.go: Fixed []byte to string conversion syntax in comment 2017-01-15 05:57:16 -08:00
b9d3bd8d42 Merge pull request #7163 from gyuho/snapshot-count
etcd-tester: use 10K for '--snapshot-count'
2017-01-14 17:52:09 -08:00
6f9a20803c etcd-tester: use 10K for '--snapshot-count'
Since we want to send snapshot more often in failure injected cluster
2017-01-14 17:29:35 -08:00
699b1e5b3a Merge pull request #7160 from xiang90/snapshotcount
etcdserver: increase snapshot to 100,000
2017-01-14 16:53:44 -08:00
26d99269c0 Merge pull request #6898 from mitake/auth-maintain
RFC, WIP: etcdserver: let maintenance services require root role
2017-01-14 11:22:14 -08:00
783eaf9de6 e2e: add cases for defrag and snapshot with authentication 2017-01-14 19:36:24 +09:00
9886e9448e auth, etcdserver: let maintenance services require root role
This commit lets maintenance services require root privilege. It also
moves AuthInfoFromCtx() from etcdserver to auth pkg for cleaning purpose.
2017-01-14 19:36:24 +09:00
c5a9d54835 etcdserver: increase snapshot to 100,000
Keep more wal entries in memory for fast follower recovery.
10,000 was a too small number that triggers quite a few snapshots.
ZK proves that 100,000 is a reasonable number for even old less prowerful
machines.

Eventually we should provide both count and max memory (for large entries).
2017-01-13 18:05:25 -08:00
118fd18eb6 Merge pull request #6894 from gyuho/preserve-value
*: 'ignore_value' to detach lease with PutRequest
2017-01-13 16:02:19 -08:00
0f8060bede grpcproxy: handle 'IgnoreValue' field in PutRequest 2017-01-13 15:13:18 -08:00
5dffa38fb2 e2e: test put command with '--ignore-value' flag 2017-01-13 15:13:18 -08:00
e03850c4ac ctlv3: add '--ignore-value' flag to 'put' command 2017-01-13 15:13:18 -08:00
d94d22122b clientv3: add 'WithIgnoreValue' option 2017-01-13 15:13:18 -08:00
a66f133209 integration: test Put,Txn with ignore_value flag 2017-01-13 15:13:18 -08:00
8752ee52a5 etcdserver: use prev-value for ignore_value writes 2017-01-13 15:13:18 -08:00
e655420d33 v3rpc: error for non-empty value with ignore_value 2017-01-13 15:13:18 -08:00
7f8b5774a4 *: regenerate proto files with 'ignore_value' 2017-01-13 15:13:18 -08:00
8eea93942d *: 'ignore_value' to detach lease with PutRequest 2017-01-13 15:13:18 -08:00
4730bddea7 Merge pull request #7153 from gyuho/cap
etcdserver/api, rafthttp: add version v3.2
2017-01-13 14:59:14 -08:00
fa9a78450c rafthttp: add 3.2.0 stream type 2017-01-13 14:23:15 -08:00
ea94aea136 etcdserver/api: add 3.2 in capability 2017-01-13 14:00:03 -08:00
a8cc11375f version: bump to v3.2.0+git 2017-01-13 12:58:15 -08:00
3d97da0672 improve documentation regarding docker cluster
instead of trying to highlight stuff within markdown code blocks, this commits adds a descriptive sentence explaining the differences.
2017-01-13 09:20:37 +01:00
c624caabb1 improve example run commands in docker_guide
When bootstrapping a cluster, the docker run command is mostly the same for all cluster member. This commits highlight the small variations between the commands to make them stand out.
2017-01-12 09:16:21 +01:00
722 changed files with 56525 additions and 17122 deletions

View File

@ -1,7 +1,6 @@
# Bug reporting
A good bug report has some very specific qualities, so please read over our short document on
[reporting bugs][report_bugs] before you submit your bug report.
A good bug report has some very specific qualities, so please read over our short document on [reporting bugs][report_bugs] before submitting a bug report.
To ask a question, go ahead and ignore this.

1
.gitignore vendored
View File

@ -12,3 +12,4 @@
*.test
tools/functional-tester/docker/bin
hack/tls-setup/certs
.idea

View File

@ -4,12 +4,18 @@ go_import_path: github.com/coreos/etcd
sudo: false
go:
- 1.7.4
- 1.8.3
- tip
notifications:
on_success: never
on_failure: never
env:
matrix:
- TARGET=amd64
- TARGET=darwin-amd64
- TARGET=windows-amd64
- TARGET=arm64
- TARGET=arm
- TARGET=386
@ -20,6 +26,10 @@ matrix:
allow_failures:
- go: tip
exclude:
- go: tip
env: TARGET=darwin-amd64
- go: tip
env: TARGET=windows-amd64
- go: tip
env: TARGET=arm
- go: tip
@ -31,15 +41,21 @@ matrix:
addons:
apt:
sources:
- debian-sid
packages:
- libpcap-dev
- libaspell-dev
- libhunspell-dev
- shellcheck
before_install:
- go get -v github.com/chzchzchz/goword
- go get -v honnef.co/go/simple/cmd/gosimple
- go get -v honnef.co/go/unused/cmd/unused
- go get -v -u github.com/chzchzchz/goword
- go get -v -u github.com/coreos/license-bill-of-materials
- go get -v -u honnef.co/go/tools/cmd/gosimple
- go get -v -u honnef.co/go/tools/cmd/unused
- go get -v -u honnef.co/go/tools/cmd/staticcheck
- ./scripts/install-marker.sh amd64
# disable godep restore override
install:
@ -51,6 +67,12 @@ script:
amd64)
GOARCH=amd64 ./test
;;
darwin-amd64)
GO_BUILD_FLAGS="-a -v" GOPATH="" GOOS=darwin GOARCH=amd64 ./build
;;
windows-amd64)
GO_BUILD_FLAGS="-a -v" GOPATH="" GOOS=windows GOARCH=amd64 ./build
;;
386)
GOARCH=386 PASSES="build unit" ./test
;;

View File

@ -1,6 +1,6 @@
# How to contribute
etcd is Apache 2.0 licensed and accepts contributions via GitHub pull requests. This document outlines some of the conventions on commit message formatting, contact points for developers and other resources to make getting your contribution into etcd easier.
etcd is Apache 2.0 licensed and accepts contributions via GitHub pull requests. This document outlines some of the conventions on commit message formatting, contact points for developers, and other resources to help get contributions into etcd.
# Email and chat
@ -14,24 +14,20 @@ etcd is Apache 2.0 licensed and accepts contributions via GitHub pull requests.
## Reporting bugs and creating issues
Reporting bugs is one of the best ways to contribute. However, a good bug report
has some very specific qualities, so please read over our short document on
[reporting bugs](https://github.com/coreos/etcd/blob/master/Documentation/reporting_bugs.md)
before you submit your bug report. This document might contain links known
issues, another good reason to take a look there, before reporting your bug.
Reporting bugs is one of the best ways to contribute. However, a good bug report has some very specific qualities, so please read over our short document on [reporting bugs](https://github.com/coreos/etcd/blob/master/Documentation/reporting_bugs.md) before submitting a bug report. This document might contain links to known issues, another good reason to take a look there before reporting a bug.
## Contribution flow
This is a rough outline of what a contributor's workflow looks like:
- Create a topic branch from where you want to base your work. This is usually master.
- Create a topic branch from where to base the contribution. This is usually master.
- Make commits of logical units.
- Make sure your commit messages are in the proper format (see below).
- Push your changes to a topic branch in your fork of the repository.
- Make sure commit messages are in the proper format (see below).
- Push changes in a topic branch to a personal fork of the repository.
- Submit a pull request to coreos/etcd.
- Your PR must receive a LGTM from two maintainers found in the MAINTAINERS file.
- The PR must receive a LGTM from two maintainers found in the MAINTAINERS file.
Thanks for your contributions!
Thanks for contributing!
### Code style
@ -48,8 +44,7 @@ the body of the commit should describe the why.
```
scripts: add the test-cluster command
this uses tmux to setup a test cluster that you can easily kill and
start for debugging.
this uses tmux to setup a test cluster that can easily be killed and started for debugging.
Fixes #38
```
@ -64,7 +59,4 @@ The format can be described more formally as follows:
<footer>
```
The first line is the subject and should be no longer than 70 characters, the
second line is always blank, and other lines should be wrapped at 80 characters.
This allows the message to be easier to read on GitHub as well as in various
git tools.
The first line is the subject and should be no longer than 70 characters, the second line is always blank, and other lines should be wrapped at 80 characters. This allows the message to be easier to read on GitHub as well as in various git tools.

View File

@ -5,6 +5,12 @@ ADD etcdctl /usr/local/bin/
RUN mkdir -p /var/etcd/
RUN mkdir -p /var/lib/etcd/
# Alpine Linux doesn't use pam, which means that there is no /etc/nsswitch.conf,
# but Golang relies on /etc/nsswitch.conf to check the order of DNS resolving
# (see https://github.com/golang/go/commit/9dee7771f561cf6aee081c0af6658cc81fac3918)
# To fix this we just create /etc/nsswitch.conf and add the following line:
RUN echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' >> /etc/nsswitch.conf
EXPOSE 2379 2380
# Define default command.

11
Dockerfile-release.arm64 Normal file
View File

@ -0,0 +1,11 @@
FROM aarch64/ubuntu:16.04
ADD etcd /usr/local/bin/
ADD etcdctl /usr/local/bin/
ADD var/etcd /var/etcd
ADD var/lib/etcd /var/lib/etcd
EXPOSE 2379 2380
# Define default command.
CMD ["/usr/local/bin/etcd"]

View File

@ -0,0 +1,11 @@
FROM ppc64le/ubuntu:16.04
ADD etcd /usr/local/bin/
ADD etcdctl /usr/local/bin/
ADD var/etcd /var/etcd
ADD var/lib/etcd /var/lib/etcd
EXPOSE 2379 2380
# Define default command.
CMD ["/usr/local/bin/etcd"]

View File

@ -49,4 +49,4 @@ Bootstrap another machine and use the [hey HTTP benchmark tool][hey] to send req
| 256 | 256 | all servers | 3061 | 119.3 |
[hey]: https://github.com/rakyll/hey
[hack-benchmark]: /hack/benchmark/
[hack-benchmark]: https://github.com/coreos/etcd/tree/master/hack/benchmark

View File

@ -69,4 +69,4 @@ Bootstrap another machine and use the [hey HTTP benchmark tool][hey] to send req
[hey]: https://github.com/rakyll/hey
[c7146bd5]: https://github.com/coreos/etcd/commits/c7146bd5f2c73716091262edc638401bb8229144
[etcd-2.1-benchmark]: etcd-2-1-0-alpha-benchmarks.md
[hack-benchmark]: /hack/benchmark/
[hack-benchmark]: ../../hack/benchmark/

View File

@ -39,7 +39,7 @@ The length of key name is always 64 bytes, which is a reasonable length of avera
## Data Size Threshold
- When etcd reaches data size threshold, it may trigger leader election easily and drop part of proposals.
- At most cases, etcd cluster should work smoothly if it doesn't hit the threshold. If it doesn't work well due to insufficient resources, you need to decrease its data size.
- For most cases, the etcd cluster should work smoothly if it doesn't hit the threshold. If it doesn't work well due to insufficient resources, decrease its data size.
| value bytes | key number limitation | suggested data size threshold(MB) | consumed RSS(MB) |
|-------------|-----------------------|-----------------------------------|------------------|

View File

@ -39,4 +39,4 @@ The performance is nearly the same as the one with empty server handler.
The performance with empty server handler is not affected by one put. So the
performance downgrade should be caused by storage package.
[etcd-v3-benchmark]: /tools/benchmark/
[etcd-v3-benchmark]: ../../tools/benchmark/

View File

@ -0,0 +1,168 @@
### etcd concurrency API Reference
This is a generated documentation. Please read the proto files for more.
##### service `Lock` (etcdserver/api/v3lock/v3lockpb/v3lock.proto)
The lock service exposes client-side locking facilities as a gRPC interface.
| Method | Request Type | Response Type | Description |
| ------ | ------------ | ------------- | ----------- |
| Lock | LockRequest | LockResponse | Lock acquires a distributed shared lock on a given named lock. On success, it will return a unique key that exists so long as the lock is held by the caller. This key can be used in conjunction with transactions to safely ensure updates to etcd only occur while holding lock ownership. The lock is held until Unlock is called on the key or the lease associate with the owner expires. |
| Unlock | UnlockRequest | UnlockResponse | Unlock takes a key returned by Lock and releases the hold on lock. The next Lock caller waiting for the lock will then be woken up and given ownership of the lock. |
##### message `LockRequest` (etcdserver/api/v3lock/v3lockpb/v3lock.proto)
| Field | Description | Type |
| ----- | ----------- | ---- |
| name | name is the identifier for the distributed shared lock to be acquired. | bytes |
| lease | lease is the ID of the lease that will be attached to ownership of the lock. If the lease expires or is revoked and currently holds the lock, the lock is automatically released. Calls to Lock with the same lease will be treated as a single acquistion; locking twice with the same lease is a no-op. | int64 |
##### message `LockResponse` (etcdserver/api/v3lock/v3lockpb/v3lock.proto)
| Field | Description | Type |
| ----- | ----------- | ---- |
| header | | etcdserverpb.ResponseHeader |
| key | key is a key that will exist on etcd for the duration that the Lock caller owns the lock. Users should not modify this key or the lock may exhibit undefined behavior. | bytes |
##### message `UnlockRequest` (etcdserver/api/v3lock/v3lockpb/v3lock.proto)
| Field | Description | Type |
| ----- | ----------- | ---- |
| key | key is the lock ownership key granted by Lock. | bytes |
##### message `UnlockResponse` (etcdserver/api/v3lock/v3lockpb/v3lock.proto)
| Field | Description | Type |
| ----- | ----------- | ---- |
| header | | etcdserverpb.ResponseHeader |
##### service `Election` (etcdserver/api/v3election/v3electionpb/v3election.proto)
The election service exposes client-side election facilities as a gRPC interface.
| Method | Request Type | Response Type | Description |
| ------ | ------------ | ------------- | ----------- |
| Campaign | CampaignRequest | CampaignResponse | Campaign waits to acquire leadership in an election, returning a LeaderKey representing the leadership if successful. The LeaderKey can then be used to issue new values on the election, transactionally guard API requests on leadership still being held, and resign from the election. |
| Proclaim | ProclaimRequest | ProclaimResponse | Proclaim updates the leader's posted value with a new value. |
| Leader | LeaderRequest | LeaderResponse | Leader returns the current election proclamation, if any. |
| Observe | LeaderRequest | LeaderResponse | Observe streams election proclamations in-order as made by the election's elected leaders. |
| Resign | ResignRequest | ResignResponse | Resign releases election leadership so other campaigners may acquire leadership on the election. |
##### message `CampaignRequest` (etcdserver/api/v3election/v3electionpb/v3election.proto)
| Field | Description | Type |
| ----- | ----------- | ---- |
| name | name is the election's identifier for the campaign. | bytes |
| lease | lease is the ID of the lease attached to leadership of the election. If the lease expires or is revoked before resigning leadership, then the leadership is transferred to the next campaigner, if any. | int64 |
| value | value is the initial proclaimed value set when the campaigner wins the election. | bytes |
##### message `CampaignResponse` (etcdserver/api/v3election/v3electionpb/v3election.proto)
| Field | Description | Type |
| ----- | ----------- | ---- |
| header | | etcdserverpb.ResponseHeader |
| leader | leader describes the resources used for holding leadereship of the election. | LeaderKey |
##### message `LeaderKey` (etcdserver/api/v3election/v3electionpb/v3election.proto)
| Field | Description | Type |
| ----- | ----------- | ---- |
| name | name is the election identifier that correponds to the leadership key. | bytes |
| key | key is an opaque key representing the ownership of the election. If the key is deleted, then leadership is lost. | bytes |
| rev | rev is the creation revision of the key. It can be used to test for ownership of an election during transactions by testing the key's creation revision matches rev. | int64 |
| lease | lease is the lease ID of the election leader. | int64 |
##### message `LeaderRequest` (etcdserver/api/v3election/v3electionpb/v3election.proto)
| Field | Description | Type |
| ----- | ----------- | ---- |
| name | name is the election identifier for the leadership information. | bytes |
##### message `LeaderResponse` (etcdserver/api/v3election/v3electionpb/v3election.proto)
| Field | Description | Type |
| ----- | ----------- | ---- |
| header | | etcdserverpb.ResponseHeader |
| kv | kv is the key-value pair representing the latest leader update. | mvccpb.KeyValue |
##### message `ProclaimRequest` (etcdserver/api/v3election/v3electionpb/v3election.proto)
| Field | Description | Type |
| ----- | ----------- | ---- |
| leader | leader is the leadership hold on the election. | LeaderKey |
| value | value is an update meant to overwrite the leader's current value. | bytes |
##### message `ProclaimResponse` (etcdserver/api/v3election/v3electionpb/v3election.proto)
| Field | Description | Type |
| ----- | ----------- | ---- |
| header | | etcdserverpb.ResponseHeader |
##### message `ResignRequest` (etcdserver/api/v3election/v3electionpb/v3election.proto)
| Field | Description | Type |
| ----- | ----------- | ---- |
| leader | leader is the leadership to relinquish by resignation. | LeaderKey |
##### message `ResignResponse` (etcdserver/api/v3election/v3electionpb/v3election.proto)
| Field | Description | Type |
| ----- | ----------- | ---- |
| header | | etcdserverpb.ResponseHeader |
##### message `Event` (mvcc/mvccpb/kv.proto)
| Field | Description | Type |
| ----- | ----------- | ---- |
| type | type is the kind of event. If type is a PUT, it indicates new data has been stored to the key. If type is a DELETE, it indicates the key was deleted. | EventType |
| kv | kv holds the KeyValue for the event. A PUT event contains current kv pair. A PUT event with kv.Version=1 indicates the creation of a key. A DELETE/EXPIRE event contains the deleted key with its modification revision set to the revision of deletion. | KeyValue |
| prev_kv | prev_kv holds the key-value pair before the event happens. | KeyValue |
##### message `KeyValue` (mvcc/mvccpb/kv.proto)
| Field | Description | Type |
| ----- | ----------- | ---- |
| key | key is the key in bytes. An empty key is not allowed. | bytes |
| create_revision | create_revision is the revision of last creation on this key. | int64 |
| mod_revision | mod_revision is the revision of last modification on this key. | int64 |
| version | version is the version of the key. A deletion resets the version to zero and any modification of the key increases its version. | int64 |
| value | value is the value held by the key, in bytes. | bytes |
| lease | lease is the ID of the lease that attached to key. When the attached lease expires, the key will be deleted. If lease is 0, then no lease is attached to the key. | int64 |

View File

@ -40,8 +40,6 @@ This is a generated documentation. Please read the proto files for more.
##### service `KV` (etcdserver/etcdserverpb/rpc.proto)
for grpc-gateway
| Method | Request Type | Response Type | Description |
| ------ | ------------ | ------------- | ----------- |
| Range | RangeRequest | RangeResponse | Range gets the keys in the range from the key-value store. |
@ -94,8 +92,6 @@ for grpc-gateway
##### message `AlarmRequest` (etcdserver/etcdserverpb/rpc.proto)
default, used to query if any alarm is active space quota is exhausted
| Field | Description | Type |
| ----- | ----------- | ---- |
| action | action is the kind of alarm request to issue. The action may GET alarm statuses, ACTIVATE an alarm, or DEACTIVATE a raised alarm. | AlarmAction |
@ -427,8 +423,8 @@ Empty field.
| Field | Description | Type |
| ----- | ----------- | ---- |
| key | key is the first key to delete in the range. | bytes |
| range_end | range_end is the key following the last key to delete for the range [key, range_end). If range_end is not given, the range is defined to contain only the key argument. If range_end is one bit larger than the given key, then the range is all the all keys with the prefix (the given key). If range_end is '\0', the range is all keys greater than or equal to the key argument. | bytes |
| prev_kv | If prev_kv is set, etcd gets the previous key-value pairs before deleting it. The previous key-value pairs will be returned in the delte response. | bool |
| range_end | range_end is the key following the last key to delete for the range [key, range_end). If range_end is not given, the range is defined to contain only the key argument. If range_end is one bit larger than the given key, then the range is all the keys with the prefix (the given key). If range_end is '\0', the range is all keys greater than or equal to the key argument. | bytes |
| prev_kv | If prev_kv is set, etcd gets the previous key-value pairs before deleting it. The previous key-value pairs will be returned in the delete response. | bool |
@ -557,6 +553,7 @@ Empty field.
| ----- | ----------- | ---- |
| header | | ResponseHeader |
| member | member is the member information for the added member. | Member |
| members | members is a list of all members after adding the new member. | (slice of) Member |
@ -588,6 +585,7 @@ Empty field.
| Field | Description | Type |
| ----- | ----------- | ---- |
| header | | ResponseHeader |
| members | members is a list of all members after removing the member. | (slice of) Member |
@ -605,6 +603,7 @@ Empty field.
| Field | Description | Type |
| ----- | ----------- | ---- |
| header | | ResponseHeader |
| members | members is a list of all members after updating the member. | (slice of) Member |
@ -616,6 +615,8 @@ Empty field.
| value | value is the value, in bytes, to associate with the key in the key-value store. | bytes |
| lease | lease is the lease ID to associate with the key in the key-value store. A lease value of 0 indicates no lease. | int64 |
| prev_kv | If prev_kv is set, etcd gets the previous key-value pair before changing it. The previous key-value pair will be returned in the put response. | bool |
| ignore_value | If ignore_value is set, etcd updates the key using its current value. Returns an error if the key does not exist. | bool |
| ignore_lease | If ignore_lease is set, etcd updates the key using its current lease. Returns an error if the key does not exist. | bool |
@ -632,9 +633,9 @@ Empty field.
| Field | Description | Type |
| ----- | ----------- | ---- |
| key | default, no sorting lowest target value first highest target value first key is the first key for the range. If range_end is not given, the request only looks up key. | bytes |
| range_end | range_end is the upper bound on the requested range [key, range_end). If range_end is '\0', the range is all keys >= key. If the range_end is one bit larger than the given key, then the range requests get the all keys with the prefix (the given key). If both key and range_end are '\0', then range requests returns all keys. | bytes |
| limit | limit is a limit on the number of keys returned for the request. | int64 |
| key | key is the first key for the range. If range_end is not given, the request only looks up key. | bytes |
| range_end | range_end is the upper bound on the requested range [key, range_end). If range_end is '\0', the range is all keys >= key. If range_end is key plus one (e.g., "aa"+1 == "ab", "a\xff"+1 == "b"), then the range request gets all keys prefixed with key. If both key and range_end are '\0', then the range request returns all keys. | bytes |
| limit | limit is a limit on the number of keys returned for the request. When limit is set to 0, it is treated as no limit. | int64 |
| revision | revision is the point-in-time of the key-value store to use for the range. If revision is less or equal to zero, the range is over the newest key-value store. If the revision has been compacted, ErrCompacted is returned as a response. | int64 |
| sort_order | sort_order is the order for returned sorted results. | SortOrder |
| sort_target | sort_target is the key-value field to use for sorting. | SortTarget |
@ -765,7 +766,7 @@ From google paxosdb paper: Our implementation hinges around a powerful primitive
| range_end | range_end is the end of the range [key, range_end) to watch. If range_end is not given, only the key argument is watched. If range_end is equal to '\0', all keys greater than or equal to the key argument are watched. If the range_end is one bit larger than the given key, then all keys with the prefix (the given key) will be watched. | bytes |
| start_revision | start_revision is an optional revision to watch from (inclusive). No start_revision is "now". | int64 |
| progress_notify | progress_notify is set so that the etcd server will periodically send a WatchResponse with no events to the new watcher if there are no recent events. It is useful when clients wish to recover a disconnected watcher starting from a recent known revision. The etcd server may decide how often it will send notifications based on current load. | bool |
| filters | filter out put event. filter out delete event. filters filter the events at server side before it sends back to the watcher. | (slice of) FilterType |
| filters | filters filter the events at server side before it sends back to the watcher. | (slice of) FilterType |
| prev_kv | If prev_kv is set, created watcher gets the previous KV before the event happens. If the previous KV is already compacted, nothing will be returned. | bool |
@ -789,6 +790,7 @@ From google paxosdb paper: Our implementation hinges around a powerful primitive
| created | created is set to true if the response is for a create watch request. The client should record the watch_id and expect to receive events for the created watcher from the same stream. All events sent to the created watcher will attach with the same watch_id. | bool |
| canceled | canceled is set to true if the response is for a cancel watch request. No further events will be sent to the canceled watcher. | bool |
| compact_revision | compact_revision is set to the minimum index if a watcher tries to watch at a compacted index. This happens when creating a watcher at a compacted revision or the watcher cannot catch up with the progress of the key-value store. The client should treat the watcher as canceled and should not try to create any watcher with the same start_revision again. | int64 |
| cancel_reason | cancel_reason indicates the reason for canceling the watcher. | string |
| events | | (slice of) mvccpb.Event |

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,334 @@
{
"swagger": "2.0",
"info": {
"title": "etcdserver/api/v3election/v3electionpb/v3election.proto",
"version": "version not set"
},
"schemes": [
"http",
"https"
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {
"/v3alpha/election/campaign": {
"post": {
"summary": "Campaign waits to acquire leadership in an election, returning a LeaderKey\nrepresenting the leadership if successful. The LeaderKey can then be used\nto issue new values on the election, transactionally guard API requests on\nleadership still being held, and resign from the election.",
"operationId": "Campaign",
"responses": {
"200": {
"description": "",
"schema": {
"$ref": "#/definitions/v3electionpbCampaignResponse"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/v3electionpbCampaignRequest"
}
}
],
"tags": [
"Election"
]
}
},
"/v3alpha/election/leader": {
"post": {
"summary": "Leader returns the current election proclamation, if any.",
"operationId": "Leader",
"responses": {
"200": {
"description": "",
"schema": {
"$ref": "#/definitions/v3electionpbLeaderResponse"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/v3electionpbLeaderRequest"
}
}
],
"tags": [
"Election"
]
}
},
"/v3alpha/election/observe": {
"post": {
"summary": "Observe streams election proclamations in-order as made by the election's\nelected leaders.",
"operationId": "Observe",
"responses": {
"200": {
"description": "(streaming responses)",
"schema": {
"$ref": "#/definitions/v3electionpbLeaderResponse"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/v3electionpbLeaderRequest"
}
}
],
"tags": [
"Election"
]
}
},
"/v3alpha/election/proclaim": {
"post": {
"summary": "Proclaim updates the leader's posted value with a new value.",
"operationId": "Proclaim",
"responses": {
"200": {
"description": "",
"schema": {
"$ref": "#/definitions/v3electionpbProclaimResponse"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/v3electionpbProclaimRequest"
}
}
],
"tags": [
"Election"
]
}
},
"/v3alpha/election/resign": {
"post": {
"summary": "Resign releases election leadership so other campaigners may acquire\nleadership on the election.",
"operationId": "Resign",
"responses": {
"200": {
"description": "",
"schema": {
"$ref": "#/definitions/v3electionpbResignResponse"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/v3electionpbResignRequest"
}
}
],
"tags": [
"Election"
]
}
}
},
"definitions": {
"etcdserverpbResponseHeader": {
"type": "object",
"properties": {
"cluster_id": {
"type": "string",
"format": "uint64",
"description": "cluster_id is the ID of the cluster which sent the response."
},
"member_id": {
"type": "string",
"format": "uint64",
"description": "member_id is the ID of the member which sent the response."
},
"revision": {
"type": "string",
"format": "int64",
"description": "revision is the key-value store revision when the request was applied."
},
"raft_term": {
"type": "string",
"format": "uint64",
"description": "raft_term is the raft term when the request was applied."
}
}
},
"mvccpbKeyValue": {
"type": "object",
"properties": {
"key": {
"type": "string",
"format": "byte",
"description": "key is the key in bytes. An empty key is not allowed."
},
"create_revision": {
"type": "string",
"format": "int64",
"description": "create_revision is the revision of last creation on this key."
},
"mod_revision": {
"type": "string",
"format": "int64",
"description": "mod_revision is the revision of last modification on this key."
},
"version": {
"type": "string",
"format": "int64",
"description": "version is the version of the key. A deletion resets\nthe version to zero and any modification of the key\nincreases its version."
},
"value": {
"type": "string",
"format": "byte",
"description": "value is the value held by the key, in bytes."
},
"lease": {
"type": "string",
"format": "int64",
"description": "lease is the ID of the lease that attached to key.\nWhen the attached lease expires, the key will be deleted.\nIf lease is 0, then no lease is attached to the key."
}
}
},
"v3electionpbCampaignRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"format": "byte",
"description": "name is the election's identifier for the campaign."
},
"lease": {
"type": "string",
"format": "int64",
"description": "lease is the ID of the lease attached to leadership of the election. If the\nlease expires or is revoked before resigning leadership, then the\nleadership is transferred to the next campaigner, if any."
},
"value": {
"type": "string",
"format": "byte",
"description": "value is the initial proclaimed value set when the campaigner wins the\nelection."
}
}
},
"v3electionpbCampaignResponse": {
"type": "object",
"properties": {
"header": {
"$ref": "#/definitions/etcdserverpbResponseHeader"
},
"leader": {
"$ref": "#/definitions/v3electionpbLeaderKey",
"description": "leader describes the resources used for holding leadereship of the election."
}
}
},
"v3electionpbLeaderKey": {
"type": "object",
"properties": {
"name": {
"type": "string",
"format": "byte",
"description": "name is the election identifier that correponds to the leadership key."
},
"key": {
"type": "string",
"format": "byte",
"description": "key is an opaque key representing the ownership of the election. If the key\nis deleted, then leadership is lost."
},
"rev": {
"type": "string",
"format": "int64",
"description": "rev is the creation revision of the key. It can be used to test for ownership\nof an election during transactions by testing the key's creation revision\nmatches rev."
},
"lease": {
"type": "string",
"format": "int64",
"description": "lease is the lease ID of the election leader."
}
}
},
"v3electionpbLeaderRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"format": "byte",
"description": "name is the election identifier for the leadership information."
}
}
},
"v3electionpbLeaderResponse": {
"type": "object",
"properties": {
"header": {
"$ref": "#/definitions/etcdserverpbResponseHeader"
},
"kv": {
"$ref": "#/definitions/mvccpbKeyValue",
"description": "kv is the key-value pair representing the latest leader update."
}
}
},
"v3electionpbProclaimRequest": {
"type": "object",
"properties": {
"leader": {
"$ref": "#/definitions/v3electionpbLeaderKey",
"description": "leader is the leadership hold on the election."
},
"value": {
"type": "string",
"format": "byte",
"description": "value is an update meant to overwrite the leader's current value."
}
}
},
"v3electionpbProclaimResponse": {
"type": "object",
"properties": {
"header": {
"$ref": "#/definitions/etcdserverpbResponseHeader"
}
}
},
"v3electionpbResignRequest": {
"type": "object",
"properties": {
"leader": {
"$ref": "#/definitions/v3electionpbLeaderKey",
"description": "leader is the leadership to relinquish by resignation."
}
}
},
"v3electionpbResignResponse": {
"type": "object",
"properties": {
"header": {
"$ref": "#/definitions/etcdserverpbResponseHeader"
}
}
}
}
}

View File

@ -0,0 +1,146 @@
{
"swagger": "2.0",
"info": {
"title": "etcdserver/api/v3lock/v3lockpb/v3lock.proto",
"version": "version not set"
},
"schemes": [
"http",
"https"
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {
"/v3alpha/lock/lock": {
"post": {
"summary": "Lock acquires a distributed shared lock on a given named lock.\nOn success, it will return a unique key that exists so long as the\nlock is held by the caller. This key can be used in conjunction with\ntransactions to safely ensure updates to etcd only occur while holding\nlock ownership. The lock is held until Unlock is called on the key or the\nlease associate with the owner expires.",
"operationId": "Lock",
"responses": {
"200": {
"description": "",
"schema": {
"$ref": "#/definitions/v3lockpbLockResponse"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/v3lockpbLockRequest"
}
}
],
"tags": [
"Lock"
]
}
},
"/v3alpha/lock/unlock": {
"post": {
"summary": "Unlock takes a key returned by Lock and releases the hold on lock. The\nnext Lock caller waiting for the lock will then be woken up and given\nownership of the lock.",
"operationId": "Unlock",
"responses": {
"200": {
"description": "",
"schema": {
"$ref": "#/definitions/v3lockpbUnlockResponse"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/v3lockpbUnlockRequest"
}
}
],
"tags": [
"Lock"
]
}
}
},
"definitions": {
"etcdserverpbResponseHeader": {
"type": "object",
"properties": {
"cluster_id": {
"type": "string",
"format": "uint64",
"description": "cluster_id is the ID of the cluster which sent the response."
},
"member_id": {
"type": "string",
"format": "uint64",
"description": "member_id is the ID of the member which sent the response."
},
"revision": {
"type": "string",
"format": "int64",
"description": "revision is the key-value store revision when the request was applied."
},
"raft_term": {
"type": "string",
"format": "uint64",
"description": "raft_term is the raft term when the request was applied."
}
}
},
"v3lockpbLockRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"format": "byte",
"description": "name is the identifier for the distributed shared lock to be acquired."
},
"lease": {
"type": "string",
"format": "int64",
"description": "lease is the ID of the lease that will be attached to ownership of the\nlock. If the lease expires or is revoked and currently holds the lock,\nthe lock is automatically released. Calls to Lock with the same lease will\nbe treated as a single acquistion; locking twice with the same lease is a\nno-op."
}
}
},
"v3lockpbLockResponse": {
"type": "object",
"properties": {
"header": {
"$ref": "#/definitions/etcdserverpbResponseHeader"
},
"key": {
"type": "string",
"format": "byte",
"description": "key is a key that will exist on etcd for the duration that the Lock caller\nowns the lock. Users should not modify this key or the lock may exhibit\nundefined behavior."
}
}
},
"v3lockpbUnlockRequest": {
"type": "object",
"properties": {
"key": {
"type": "string",
"format": "byte",
"description": "key is the lock ownership key granted by Lock."
}
}
},
"v3lockpbUnlockResponse": {
"type": "object",
"properties": {
"header": {
"$ref": "#/definitions/etcdserverpbResponseHeader"
}
}
}
}
}

View File

@ -1,8 +1,11 @@
# Experimental APIs and features
For the most part, the etcd project is stable, but we are still moving fast! We believe in the release fast philosophy. We want to get early feedback on features still in development and stabilizing. Thus, there are, and will be more, experimental features and APIs. We plan to improve these features based on the early feedback from the community, or abandon them if there is little interest, in the next few releases. If you are running a production system, please do not rely on any experimental features or APIs.
For the most part, the etcd project is stable, but we are still moving fast! We believe in the release fast philosophy. We want to get early feedback on features still in development and stabilizing. Thus, there are, and will be more, experimental features and APIs. We plan to improve these features based on the early feedback from the community, or abandon them if there is little interest, in the next few releases. Please do not rely on any experimental features or APIs in production environment.
## The current experimental API/features are:
- v3 auth API: expect to be stable in 3.1 release
- etcd gateway: expect to be stable in 3.1 release
- [gateway][gateway]: beta, to be stable in 3.2 release
- [gRPC proxy][grpc-proxy]: alpha, to be stable in 3.2 release
[gateway]: ../op-guide/gateway.md
[grpc-proxy]: ../op-guide/grpc_proxy.md

View File

@ -10,7 +10,7 @@ export ETCDCTL_API=3
## Find versions
etcdctl version and Server API version can be useful in finding the appropriate commands to be used for performing various opertions on etcd.
etcdctl version and Server API version can be useful in finding the appropriate commands to be used for performing various operations on etcd.
Here is the command to find the versions:

View File

@ -2,7 +2,7 @@
## Request size limit
etcd is designed to handle small key value pairs typical for metadata. Larger requests will work, but may increase the latency of other requests. For the time being, etcd guarantees to support RPC requests with up to 1MB of data. In the future, the size limit may be loosened or made it configurable.
etcd is designed to handle small key value pairs typical for metadata. Larger requests will work, but may increase the latency of other requests. For the time being, etcd guarantees to support RPC requests with up to 1MB of data. In the future, the size limit may be loosened or made configurable.
## Storage size limit

View File

@ -3,7 +3,7 @@
etcd uses the [capnslog][capnslog] library for logging application output categorized into *levels*. A log message's level is determined according to these conventions:
* Error: Data has been lost, a request has failed for a bad reason, or a required resource has been lost
* Examples:
* Examples:
* A failure to allocate disk space for WAL
* Warning: (Hopefully) Temporary conditions that may cause errors, but may work fine. A replica disappearing (that may reconnect) is a warning.
@ -26,4 +26,4 @@ etcd uses the [capnslog][capnslog] library for logging application output catego
* Send a normal message to a remote peer
* Write a log entry to disk
[capnslog]: [https://github.com/coreos/pkg/tree/master/capnslog]
[capnslog]: https://github.com/coreos/pkg/tree/master/capnslog

View File

@ -2,7 +2,7 @@
The guide talks about how to release a new version of etcd.
The procedure includes some manual steps for sanity checking but it can probably be further scripted. Please keep this document up-to-date if making changes to the release process.
The procedure includes some manual steps for sanity checking, but it can probably be further scripted. Please keep this document up-to-date if making changes to the release process.
## Prepare release
@ -58,7 +58,7 @@ Run release script in root directory:
It generates all release binaries and images under directory ./release.
## Sign binaries and images
## Sign binaries, images, and source code
etcd project key must be used to sign the generated binaries and images.`$SUBKEYID` is the key ID of etcd project Yubikey. Connect the key and run `gpg2 --card-status` to get the ID.
@ -68,6 +68,15 @@ The following commands are used for public release sign:
cd release
for i in etcd-*{.zip,.tar.gz}; do gpg2 --default-key $SUBKEYID --armor --output ${i}.asc --detach-sign ${i}; done
for i in etcd-*{.zip,.tar.gz}; do gpg2 --verify ${i}.asc ${i}; done
# sign zipped source code files
wget https://github.com/coreos/etcd/archive/${VERSION}.zip
gpg2 --armor --default-key $SUBKEYID --output ${VERSION}.zip.asc --detach-sign ${VERSION}.zip
gpg2 --verify ${VERSION}.zip.asc ${VERSION}.zip
wget https://github.com/coreos/etcd/archive/${VERSION}.tar.gz
gpg2 --armor --default-key $SUBKEYID --output ${VERSION}.tar.gz.asc --detach-sign ${VERSION}.tar.gz
gpg2 --verify ${VERSION}.tar.gz.asc ${VERSION}.tar.gz
```
The public key for GPG signing can be found at [CoreOS Application Signing Key](https://coreos.com/security/app-signing-key)

View File

@ -10,29 +10,35 @@ The easiest way to get etcd is to use one of the pre-built release binaries whic
## Build the latest version
For those wanting to try the very latest version, build etcd from the `master` branch.
[Go](https://golang.org/) version 1.6+ (with HTTP2 support) is required to build the latest version of etcd.
etcd vendors its dependency for official release binaries, while making vendoring optional to avoid import conflicts.
[`build` script][build-script] would automatically include the vendored dependencies from [`cmd`][cmd-directory] directory.
For those wanting to try the very latest version, build etcd from the `master` branch. [Go](https://golang.org/) version 1.8+ is required to build the latest version of etcd. To ensure etcd is built against well-tested libraries, etcd vendors its dependencies for official release binaries. However, etcd's vendoring is also optional to avoid potential import conflicts when embedding the etcd server or using the etcd client.
Here are the commands to build an etcd binary from the `master` branch:
To build `etcd` from the `master` branch without a `GOPATH` using the official `build` script:
```
# go is required
$ go version
go version go1.6 darwin/amd64
# GOPATH should be set correctly
$ echo $GOPATH
/Users/example/go
$ mkdir -p $GOPATH/src/github.com/coreos
$ cd $GOPATH/src/github.com/coreos
```sh
$ git clone https://github.com/coreos/etcd.git
$ cd etcd
$ ./build
$ ./bin/etcd
...
```
To build a vendored `etcd` from the `master` branch via `go get`:
```sh
# GOPATH should be set
$ echo $GOPATH
/Users/example/go
$ go get github.com/coreos/etcd/cmd/etcd
$ $GOPATH/bin/etcd
```
To build `etcd` from the `master` branch without vendoring (may not build due to upstream conflicts):
```sh
# GOPATH should be set
$ echo $GOPATH
/Users/example/go
$ go get github.com/coreos/etcd
$ $GOPATH/bin/etcd
```
## Test the installation

View File

@ -12,9 +12,10 @@ The easiest way to get started using etcd as a distributed key-value store is to
- [Setting up local clusters][local_cluster]
- [Interacting with etcd][interacting]
- [API references][api_ref]
- [gRPC gateway][api_grpc_gateway]
- gRPC [etcd core][api_ref] and [etcd concurrency][api_concurrency_ref] API references
- [HTTP JSON API through the gRPC gateway][api_grpc_gateway]
- [gRPC naming and discovery][grpc_naming]
- [Client][namespace_client] and [proxy][namespace_proxy] namespacing
- [Embedding etcd][embed_etcd]
- [Experimental features and APIs][experimental]
- [System limits][system-limit]
@ -25,39 +26,51 @@ Administrators who need to create reliable and scalable key-value stores for the
- [Setting up etcd clusters][clustering]
- [Setting up etcd gateways][gateway]
- [Setting up etcd gRPC proxy (pre-alpha)][grpc_proxy]
- [Run etcd clusters inside containers][container]
- [Setting up etcd gRPC proxy][grpc_proxy]
- [Hardware recommendations][hardware]
- [Configuration][conf]
- [Security][security]
- [Authentication][authentication]
- [Monitoring][monitoring]
- [Maintenance][maintenance]
- [Understand failures][failures]
- [Disaster recovery][recovery]
- [Performance][performance]
- [Versioning][versioning]
- [Supported platform][supported_platform]
### Platform guides
- [Supported systems][supported_platforms]
- [Docker container][container_docker]
- [Container Linux, systemd][container_linux_platform]
- [rkt container][container_rkt]
- [Amazon Web Services][aws_platform]
- [FreeBSD][freebsd_platform]
### Upgrading and compatibility
- [Migrate applications from using API v2 to API v3][v2_migration]
- [Upgrading a v2.3 cluster to v3.0][v3_upgrade]
- [Upgrading a v3.0 cluster to v3.1][v31_upgrade]
- [Upgrading a v3.1 cluster to v3.2][v32_upgrade]
## Learning
To learn more about the concepts and internals behind etcd, read the following pages:
- [Why etcd][why] (TODO)
- [Why etcd?][why]
- [Understand data model][data_model]
- [Understand APIs][understand_apis]
- [Glossary][glossary]
- Internals (TODO)
## Upgrading and compatibility
- [Migrate applications from using API v2 to API v3][v2_migration]
- [Updating v2.3 to v3.0][v3_upgrade]
- Internals
- [Auth subsystem][auth_design]
## Frequently Asked Questions (FAQ)
Answers to [common questions] about etcd.
[api_ref]: dev-guide/api_reference_v3.md
[api_concurrency_ref]: dev-guide/api_concurrency_reference_v3.md
[api_grpc_gateway]: dev-guide/api_grpc_gateway.md
[clustering]: op-guide/clustering.md
[conf]: op-guide/configuration.md
@ -72,6 +85,8 @@ Answers to [common questions] about etcd.
[failures]: op-guide/failures.md
[gateway]: op-guide/gateway.md
[glossary]: learning/glossary.md
[namespace_client]: https://godoc.org/github.com/coreos/etcd/clientv3/namespace
[namespace_proxy]: op-guide/grpc_proxy.md#namespacing
[grpc_proxy]: op-guide/grpc_proxy.md
[hardware]: op-guide/hardware.md
[interacting]: dev-guide/interacting_v3.md
@ -82,9 +97,17 @@ Answers to [common questions] about etcd.
[security]: op-guide/security.md
[monitoring]: op-guide/monitoring.md
[v2_migration]: op-guide/v2-migration.md
[container]: op-guide/container.md
[container_rkt]: op-guide/container.md#rkt
[container_docker]: op-guide/container.md#docker
[understand_apis]: learning/api.md
[versioning]: op-guide/versioning.md
[supported_platform]: op-guide/supported-platform.md
[supported_platforms]: op-guide/supported-platform.md
[container_linux_platform]: platforms/container-linux-systemd.md
[freebsd_platform]: platforms/freebsd.md
[aws_platform]: platforms/aws.md
[experimental]: dev-guide/experimental_apis.md
[v3_upgrade]: upgrades/upgrade_3_0.md
[v31_upgrade]: upgrades/upgrade_3_1.md
[v32_upgrade]: upgrades/upgrade_3_2.md
[authentication]: op-guide/authentication.md
[auth_design]: learning/auth_design.md

View File

@ -78,6 +78,26 @@ On the other hand, if the downed member is removed from cluster membership first
etcd sets `strict-reconfig-check` in order to reject reconfiguration requests that would cause quorum loss. Abandoning quorum is really risky (especially when the cluster is already unhealthy). Although it may be tempting to disable quorum checking if there's quorum loss to add a new member, this could lead to full fledged cluster inconsistency. For many applications, this will make the problem even worse ("disk geometry corruption" being a candidate for most terrifying).
#### Why does etcd lose its leader from disk latency spikes?
This is intentional; disk latency is part of leader liveness. Suppose the cluster leader takes a minute to fsync a raft log update to disk, but the etcd cluster has a one second election timeout. Even though the leader can process network messages within the election interval (e.g., send heartbeats), it's effectively unavailable because it can't commit any new proposals; it's waiting on the slow disk. If the cluster frequently loses its leader due to disk latencies, try [tuning][tuning] the disk settings or etcd time parameters.
#### What does the etcd warning "request ignored (cluster ID mismatch)" mean?
Every new etcd cluster generates a new cluster ID based on the initial cluster configuration and a user-provided unique `initial-cluster-token` value. By having unique cluster ID's, etcd is protected from cross-cluster interaction which could corrupt the cluster.
Usually this warning happens after tearing down an old cluster, then reusing some of the peer addresses for the new cluster. If any etcd process from the old cluster is still running it will try to contact the new cluster. The new cluster will recognize a cluster ID mismatch, then ignore the request and emit this warning. This warning is often cleared by ensuring peer addresses among distinct clusters are disjoint.
#### What does "mvcc: database space exceeded" mean and how do I fix it?
The [multi-version concurrency control][api-mvcc] data model in etcd keeps an exact history of the keyspace. Without periodically compacting this history (e.g., by setting `--auto-compaction`), etcd will eventually exhaust its storage space. If etcd runs low on storage space, it raises a space quota alarm to protect the cluster from further writes. So long as the alarm is raised, etcd responds to write requests with the error `mvcc: database space exceeded`.
To recover from the low space quota alarm:
1. [Compact][maintenance-compact] etcd's history.
2. [Defragment][maintenance-defragment] every etcd endpoint.
3. [Disarm][maintenance-disarm] the alarm.
### Performance
#### How should I benchmark etcd?
@ -108,11 +128,10 @@ A slow network can also cause this issue. If network metrics among the etcd mach
If none of the above suggestions clear the warnings, please [open an issue][new_issue] with detailed logging, monitoring, metrics and optionally workload information.
#### What does the etcd warning "request ignored (cluster ID mismatch)" mean?
#### What does the etcd warning "snapshotting is taking more than x seconds to finish ..." mean?
Every new etcd cluster generates a new cluster ID based on the initial cluster configuration and a user-provided unique `initial-cluster-token` value. By having unique cluster ID's, etcd is protected from cross-cluster interaction which could corrupt the cluster.
etcd sends a snapshot of its complete key-value store to refresh slow followers and for [backups][backup]. Slow snapshot transfer times increase MTTR; if the cluster is ingesting data with high throughput, slow followers may livelock by needing a new snapshot before finishing receiving a snapshot. To catch slow snapshot performance, etcd warns when sending a snapshot takes more than thirty seconds and exceeds the expected transfer time for a 1Gbps connection.
Usually this warning happens after tearing down an old cluster, then reusing some of the peer addresses for the new cluster. If any etcd process from the old cluster is still running it will try to contact the new cluster. The new cluster will recognize a cluster ID mismatch, then ignore the request and emit this warning. This warning is often cleared by ensuring peer addresses among distinct clusters are disjoint.
[hardware-setup]: ./op-guide/hardware.md
[supported-platform]: ./op-guide/supported-platform.md
@ -126,3 +145,7 @@ Usually this warning happens after tearing down an old cluster, then reusing som
[runtime reconfiguration]: https://github.com/coreos/etcd/blob/master/Documentation/op-guide/runtime-configuration.md
[benchmark]: https://github.com/coreos/etcd/tree/master/tools/benchmark
[benchmark-result]: https://github.com/coreos/etcd/blob/master/Documentation/op-guide/performance.md
[api-mvcc]: learning/api.md#revisions
[maintenance-compact]: op-guide/maintenance.md#history-compaction
[maintenance-defragment]: op-guide/maintenance.md#defragmentation
[maintenance-disarm]: ../etcdctl/README.md#alarm-disarm

View File

@ -21,6 +21,7 @@
- [etcd/clientv3](https://github.com/coreos/etcd/blob/master/clientv3) - the officially maintained Go client for v3
- [etcd/client](https://github.com/coreos/etcd/blob/master/client) - the officially maintained Go client for v2
- [go-etcd](https://github.com/coreos/go-etcd) - the deprecated official client. May be useful for older (<2.0.0) versions of etcd.
- [encWrapper](https://github.com/lumjjb/etcd/tree/enc_wrapper/clientwrap/encwrapper) - encWrapper is an encryption wrapper for the etcd client Keys API/KV.
**Java libraries**
@ -44,6 +45,8 @@
- [russellhaering/txetcd](https://github.com/russellhaering/txetcd) - a Twisted Python library
- [cholcombe973/autodock](https://github.com/cholcombe973/autodock) - A docker deployment automation tool
- [lisael/aioetcd](https://github.com/lisael/aioetcd) - (Python 3.4+) Asyncio coroutines client (Supports v2)
- [txaio-etcd](https://github.com/crossbario/txaio-etcd) - Asynchronous etcd v3-only client library for Twisted (today) and asyncio (future)
- [dims/etcd3-gateway](https://github.com/dims/etcd3-gateway) - etcd v3 API library using the HTTP grpc gateway
**Node libraries**
@ -56,9 +59,11 @@
- [iconara/etcd-rb](https://github.com/iconara/etcd-rb)
- [jpfuentes2/etcd-ruby](https://github.com/jpfuentes2/etcd-ruby)
- [ranjib/etcd-ruby](https://github.com/ranjib/etcd-ruby) - Supports v2
- [davissp14/etcdv3-ruby](https://github.com/davissp14/etcdv3-ruby) - Supports v3
**C libraries**
- [apache/celix/etcdlib](https://github.com/apache/celix/tree/develop/etcdlib) - Supports v2
- [jdarcy/etcd-api](https://github.com/jdarcy/etcd-api) - Supports v2
- [shafreeck/cetcd](https://github.com/shafreeck/cetcd) - Supports v2
@ -86,7 +91,7 @@
**PHP Libraries**
- [linkorb/etcd-php](https://github.com/linkorb/etcd-php)
- [activecollab/etcd](https://github.com/activecollab/etcd)
- [activecollab/etcd](https://github.com/activecollab/etcd)
**Haskell libraries**
@ -104,6 +109,10 @@
- [efrecon/etcd-tcl](https://github.com/efrecon/etcd-tcl) - Supports v2, except wait.
**Rust libraries**
- [jimmycuadra/rust-etcd](https://github.com/jimmycuadra/rust-etcd) - Supports v2
**Gradle Plugins**
- [gradle-etcd-rest-plugin](https://github.com/cdancy/gradle-etcd-rest-plugin) - Supports v2
@ -123,10 +132,11 @@
**Projects using etcd**
- [apache/celix](https://github.com/apache/celix) - an implementation of the OSGi specification adapted to C and C++
- [binocarlos/yoda](https://github.com/binocarlos/yoda) - etcd + ZeroMQ
- [blox/blox](https://github.com/blox/blox) - a collection of open source projects for container management and orchestration with AWS ECS
- [calavera/active-proxy](https://github.com/calavera/active-proxy) - HTTP Proxy configured with etcd
- [chain/chain](https://github.com/chain/chain) - software designed to operate and connect to highly scalable permissioned blockchain networks
- [chain/chain](https://github.com/chain/chain) - software designed to operate and connect to highly scalable permissioned blockchain networks
- [derekchiang/etcdplus](https://github.com/derekchiang/etcdplus) - A set of distributed synchronization primitives built upon etcd
- [go-discover](https://github.com/flynn/go-discover) - service discovery in Go
- [gleicon/goreman](https://github.com/gleicon/goreman/tree/etcd) - Branch of the Go Foreman clone with etcd support
@ -135,7 +145,6 @@
- [mattn/etcdenv](https://github.com/mattn/etcdenv) - "env" shebang with etcd integration
- [kelseyhightower/confd](https://github.com/kelseyhightower/confd) - Manage local app config files using templates and data from etcd
- [configdb](https://git.autistici.org/ai/configdb/tree/master) - A REST relational abstraction on top of arbitrary database backends, aimed at storing configs and inventories.
- [scrz](https://github.com/scrz/scrz) - Container manager, stores configuration in etcd.
- [fleet](https://github.com/coreos/fleet) - Distributed init system
- [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes) - Container cluster manager introduced by Google.
- [mailgun/vulcand](https://github.com/mailgun/vulcand) - HTTP proxy that uses etcd as a configuration backend.
@ -146,3 +155,4 @@
- [lytics/metafora](https://github.com/lytics/metafora) - Go distributed task library
- [ryandoyle/nss-etcd](https://github.com/ryandoyle/nss-etcd) - A GNU libc NSS module for resolving names from etcd.
- [Gru](https://github.com/dnaeon/gru) - Orchestration made easy with Go
- [Vitess](http://vitess.io/) - Vitess is a database clustering system for horizontal scaling of MySQL.

View File

@ -1,10 +1,35 @@
# etcd3 API
NOTE: this doc is not finished!
This document is meant to give an overview of the etcd3 API's central design. It is by no means all encompassing, but intended to focus on the basic ideas needed to understand etcd without the distraction of less common API calls. All etcd3 API's are defined in [gRPC services][grpc-service], which categorize remote procedure calls (RPCs) understood by the etcd server. A full listing of all etcd RPCs are documented in markdown in the [gRPC API listing][grpc-api].
## Response header
## gRPC Services
All Responses from etcd API have a [response header][response_header] attached. The response header includes the metadata of the response.
Every API request sent to an etcd server is a gRPC remote procedure call. RPCs in etcd3 are categorized based on functionality into services.
Services important for dealing with etcd's key space include:
* KV - Creates, updates, fetches, and deletes key-value pairs.
* Watch - Monitors changes to keys.
* Lease - Primitives for consuming client keep-alive messages.
Services which manage the cluster itself include:
* Auth - Role based authentication mechanism for authenticating users.
* Cluster - Provides membership information and configuration facilities.
* Maintenance - Takes recovery snapshots, defragments the store, and returns per-member status information.
### Requests and Responses
All RPCs in etcd3 follow the same format. Each RPC has a function `Name` which takes `NameRequest` as an argument and returns `NameResponse` as a response. For example, here is the `Range` RPC description:
```protobuf
service KV {
Range(RangeRequest) returns (RangeResponse)
...
}
```
### Response header
All Responses from etcd API have an attached response header which includes cluster metadata for the response:
```proto
message ResponseHeader {
@ -15,10 +40,10 @@ message ResponseHeader {
}
```
* Cluster_ID - the ID of the cluster that generates the response
* Member_ID - the ID of the member that generates the response
* Revision - the revision of the key-value store when the response is generated
* Raft_Term - the Raft term of the member when the response is generated
* Cluster_ID - the ID of the cluster generating the response.
* Member_ID - the ID of the member generating the response.
* Revision - the revision of the key-value store when generating the response.
* Raft_Term - the Raft term of the member when generating the response.
An application may read the Cluster_ID (Member_ID) field to ensure it is communicating with the intended cluster (member).
@ -28,11 +53,13 @@ Applications can use `Raft_Term` to detect when the cluster completes a new lead
## Key-Value API
Key-Value API is used to manipulate key-value pairs stored inside etcd. The key-value API is defined as a [gRPC service][kv-service]. The Key-Value pair is defined as structured data in [protobuf format][kv-proto].
The Key-Value API manipulates key-value pairs stored inside etcd. The majority of requests made to etcd are usually key-value requests.
### System primitives
### Key-Value pair
A key-value pair is the smallest unit that the key-value API can manipulate. Each key-value pair has a number of fields:
A key-value pair is the smallest unit that the key-value API can manipulate. Each key-value pair has a number of fields, defined in [protobuf format][kv-proto]:
```protobuf
message KeyValue {
@ -52,6 +79,403 @@ message KeyValue {
* Mod_Revision - revision of the last modification on the key.
* Lease - the ID of the lease attached to the key. If lease is 0, then no lease is attached to the key.
In addition to just the key and value, etcd attaches additional revision metadata as part of the key message. This revision information orders keys by time of creation and modification, which is useful for managing concurrency for distributed synchronization. The etcd client's [distributed shared locks][locks] use the creation revision to wait for lock ownership. Similarly, the modification revision is used for detecting [software transactional memory][STM] read set conflicts and waiting on [leader election][elections] updates.
#### Revisions
etcd maintains a 64-bit cluster-wide counter, the store revision, that is incremented each time the key space is modified. The revision serves as a global logical clock, sequentially ordering all updates to the store. The change represented by a new revisions is incremental; the data associated with a revision is the data that changed the store. Internally, a new revision means writing the changes to the backend's B+tree, keyed by the incremented revision.
Revisions become more valuable when taking considering etcd3's [multi-version concurrency control][mvcc] backend. The MVCC model means that the key-value store can be viewed from past revisions since historical key revisions are retained. The retention policy for this history can be configured by cluster administrators for fine-grained storage management; usually etcd3 discards old revisions of keys on a timer. A typical etcd3 cluster retains superseded key data for hours. This also buys reliable handling for long client disconnection, not just transient network disruptions: watchers simply resume from the last observed historical revision. Similarly, to read from the store at a particular point-in-time, read requests can be tagged with a revision to return keys from a view of the key space at the point in time that revision was committed.
#### Key ranges
The etcd3 data model indexes all keys over a flat binary key space. This differs from other key-value store systems that use a hierarchical system of organizing keys into directories. Instead of listing keys by directory, keys are listed by key intervals `[a, b)`.
These intervals are often referred to as "ranges" in etcd3. Operations over ranges are more powerful than operations on directories. Like a hierarchical store, intervals support single key lookups via `[a, a+1)` (e.g., ['a', 'a\x00') looks up 'a') and directory lookups by encoding keys by directory depth. In addition to those operations, intervals can also encode prefixes; for example the interval `['a', 'b')` looks up all keys prefixed by the string 'a'.
By convention, ranges for a Request are denoted by the fields `key` and `range_end`. The `key` field is the first key of the range and should be non-empty. The `range_end` is the key following the last key of the range. If `range_end` is not given or empty, the range is defined to contain only the key argument. If `range_end` is `key` plus one (e.g., "aa"+1 == "ab", "a\xff"+1 == "b"), then the range represents all keys prefixed with key. If both `key` and `range_end` are '\0', then range represents all keys. If `range_end` is '\0', the range is all keys greater than or equal to the key argument.
### Range
Keys are fetched from the key-value store using the `Range` API call, which takes a `RangeRequest`:
```protobuf
message RangeRequest {
enum SortOrder {
NONE = 0; // default, no sorting
ASCEND = 1; // lowest target value first
DESCEND = 2; // highest target value first
}
enum SortTarget {
KEY = 0;
VERSION = 1;
CREATE = 2;
MOD = 3;
VALUE = 4;
}
bytes key = 1;
bytes range_end = 2;
int64 limit = 3;
int64 revision = 4;
SortOrder sort_order = 5;
SortTarget sort_target = 6;
bool serializable = 7;
bool keys_only = 8;
bool count_only = 9;
int64 min_mod_revision = 10;
int64 max_mod_revision = 11;
int64 min_create_revision = 12;
int64 max_create_revision = 13;
}
```
* Key, Range_End - The key range to fetch.
* Limit - the maximum number of keys returned for the request. When limit is set to 0, it is treated as no limit.
* Revision - the point-in-time of the key-value store to use for the range. If revision is less or equal to zero, the range is over the latest key-value store If the revision is compacted, ErrCompacted is returned as a response.
* Sort_Order - the ordering for sorted requests.
* Sort_Target - the key-value field to sort.
* Serializable - sets the range request to use serializable member-local reads. By default, Range is linearizable; it reflects the current consensus of the cluster. For better performance and availability, in exchange for possible stale reads, a serializable range request is served locally without needing to reach consensus with other nodes in the cluster.
* Keys_Only - return only the keys and not the values.
* Count_Only - return only the count of the keys in the range.
* Min_Mod_Revision - the lower bound for key mod revisions; filters out lesser mod revisions.
* Max_Mod_Revision - the upper bound for key mod revisions; filters out greater mod revisions.
* Min_Create_Revision - the lower bound for key create revisions; filters out lesser create revisions.
* Max_Create_Revision - the upper bound for key create revisions; filters out greater create revisions.
The client receives a `RangeResponse` message from the `Range` call:
```protobuf
message RangeResponse {
ResponseHeader header = 1;
repeated mvccpb.KeyValue kvs = 2;
bool more = 3;
int64 count = 4;
}
```
* Kvs - the list of key-value pairs matched by the range request. When `Count_Only` is set, `Kvs` is empty.
* More - indicates if there are more keys to return in the requested range if `limit` is set.
* Count - the total number of keys satisfying the range request.
### Put
Keys are saved into the key-value store by issuing a `Put` call, which takes a `PutRequest`:
```protobuf
message PutRequest {
bytes key = 1;
bytes value = 2;
int64 lease = 3;
bool prev_kv = 4;
bool ignore_value = 5;
bool ignore_lease = 6;
}
```
* Key - the name of the key to put into the key-value store.
* Value - the value, in bytes, to associate with the key in the key-value store.
* Lease - the lease ID to associate with the key in the key-value store. A lease value of 0 indicates no lease.
* Prev_Kv - when set, responds with the key-value pair data before the update from this `Put` request.
* Ignore_Value - when set, update the key without changing its current value. Returns an error if the key does not exist.
* Ignore_Lease - when set, update the key without changing its current lease. Returns an error if the key does not exist.
The client receives a `PutResponse` message from the `Put` call:
```protobuf
message PutResponse {
ResponseHeader header = 1;
mvccpb.KeyValue prev_kv = 2;
}
```
* Prev_Kv - the key-value pair overwritten by the `Put`, if `Prev_Kv` was set in the `PutRequest`.
### Delete Range
Ranges of keys are deleted using the `DeleteRange` call, which takes a `DeleteRangeRequest`:
```protobuf
message DeleteRangeRequest {
bytes key = 1;
bytes range_end = 2;
bool prev_kv = 3;
}
```
* Key, Range_End - The key range to delete.
* Prev_Kv - when set, return the contents of the deleted key-value pairs.
The client receives a `DeleteRangeResponse` message from the `DeleteRange` call:
```protobuf
message DeleteRangeResponse {
ResponseHeader header = 1;
int64 deleted = 2;
repeated mvccpb.KeyValue prev_kvs = 3;
}
```
* Deleted - number of keys deleted.
* Prev_Kv - a list of all key-value pairs deleted by the DeleteRange operation.
### Transaction
A transaction is an atomic If/Then/Else construct over the key-value store. It provides a primitive for grouping requests together in atomic blocks (i.e., then/else) whose execution is guarded (i.e., if) based on the contents of the key-value store. Transactions can be used for protecting keys from unintended concurrent updates, building compare-and-swap operations, and developing higher-level concurrency control.
A transaction can atomically process multiple requests in a single request. For modifications to the key-value store, this means the store's revision is incremented only once for the transaction and all events generated by the transaction will have the same revision. However, modifications to the same key multiple times within a single transaction are forbidden.
All transactions are guarded by a conjunction of comparisons, similar to an "If" statement. Each comparison checks a single key in the store. It may check for the absence or presence of a value, compare with a given value, or check a key's revision or version. Two different comparisons may apply to the same or different keys. All comparisons are applied atomically; if all comparisons are true, the transaction is said to succeed and etcd applies the transaction's then / `success` request block, otherwise it is said to fail and applies the else / `failure` request block.
Each comparison is encoded as a `Compare` message:
```protobuf
message Compare {
enum CompareResult {
EQUAL = 0;
GREATER = 1;
LESS = 2;
NOT_EQUAL = 3;
}
enum CompareTarget {
VERSION = 0;
CREATE = 1;
MOD = 2;
VALUE= 3;
}
CompareResult result = 1;
// target is the key-value field to inspect for the comparison.
CompareTarget target = 2;
// key is the subject key for the comparison operation.
bytes key = 3;
oneof target_union {
int64 version = 4;
int64 create_revision = 5;
int64 mod_revision = 6;
bytes value = 7;
}
}
```
* Result - the kind of logical comparison operation (e.g., equal, less than, etc).
* Target - the key-value field to be compared. Either the key's version, create revision, modification revision, or value.
* Key - the key for the comparison.
* Target_Union - the user-specified data for the comparison.
After processing the comparison block, the transaction applies a block of requests. A block is a list of `RequestOp` messages:
```protobuf
message RequestOp {
// request is a union of request types accepted by a transaction.
oneof request {
RangeRequest request_range = 1;
PutRequest request_put = 2;
DeleteRangeRequest request_delete_range = 3;
}
}
```
* Request_Range - a `RangeRequest`.
* Request_Put - a `PutRequest`. The keys must be unique. It may not share keys with any other Puts or Deletes.
* Request_Delete_Range - a `DeleteRangeRequest`. It may not share keys with any Puts or Deletes requests.
All together, a transaction is issued with a `Txn` API call, which takes a `TxnRequest`:
```protobuf
message TxnRequest {
repeated Compare compare = 1;
repeated RequestOp success = 2;
repeated RequestOp failure = 3;
}
```
* Compare - A list of predicates representing a conjunction of terms for guarding the transaction.
* Success - A list of requests to process if all compare tests evaluate to true.
* Failure - A list of requests to process if any compare test evaluates to false.
The client receives a `TxnResponse` message from the `Txn` call:
```protobuf
message TxnResponse {
ResponseHeader header = 1;
bool succeeded = 2;
repeated ResponseOp responses = 3;
}
```
* Succeeded - Whether `Compare` evaluated to true or false.
* Responses - A list of responses corresponding to the results from applying the `Success` block if succeeded is true or the `Failure` if succeeded is false.
The `Responses` list corresponds to the results from the applied `RequestOp` list, with each response encoded as a `ResponseOp`:
```protobuf
message ResponseOp {
oneof response {
RangeResponse response_range = 1;
PutResponse response_put = 2;
DeleteRangeResponse response_delete_range = 3;
}
}
```
## Watch API
The Watch API provides an event-based interface for asynchronously monitoring changes to keys. An etcd3 watch waits for changes to keys by continuously watching from a given revision, either current or historical, and streams key updates back to the client.
### Events
Every change to every key is represented with `Event` messages. An `Event` message provides both the update's data and the type of update:
```protobuf
message Event {
enum EventType {
PUT = 0;
DELETE = 1;
}
EventType type = 1;
KeyValue kv = 2;
KeyValue prev_kv = 3;
}
```
* Type - The kind of event. A PUT type indicates new data has been stored to the key. A DELETE indicates the key was deleted.
* KV - The KeyValue associated with the event. A PUT event contains current kv pair. A PUT event with kv.Version=1 indicates the creation of a key. A DELETE event contains the deleted key with its modification revision set to the revision of deletion.
* Prev_KV - The key-value pair for the key from the revision immediately before the event. To save bandwidth, it is only filled out if the watch has explicitly enabled it.
### Watch streams
Watches are long-running requests and use gRPC streams to stream event data. A watch stream is bi-directional; the client writes to the stream to establish watches and reads to receive watch event. A single watch stream can multiplex many distinct watches by tagging events with per-watch identifiers. This multiplexing helps reducing the memory footprint and connection overhead on the core etcd cluster.
Watches make three guarantees about events:
* Ordered - events are ordered by revision; an event will never appear on a watch if it precedes an event in time that has already been posted.
* Reliable - a sequence of events will never drop any subsequence of events; if there are events ordered in time as a < b < c, then if the watch receives events a and c, it is guaranteed to receive b.
* Atomic - a list of events is guaranteed to encompass complete revisions; updates in the same revision over multiple keys will not be split over several lists of events.
A client creates a watch by sending a `WatchCreateRequest` over a stream returned by `Watch`:
```protobuf
message WatchCreateRequest {
bytes key = 1;
bytes range_end = 2;
int64 start_revision = 3;
bool progress_notify = 4;
enum FilterType {
NOPUT = 0;
NODELETE = 1;
}
repeated FilterType filters = 5;
bool prev_kv = 6;
}
```
* Key, Range_End - The key range to watch.
* Start_Revision - An optional revision for where to inclusively begin watching. If not given, it will stream events following the revision of the watch creation response header revision. The entire available event history can be watched starting from the last compaction revision.
* Progress_Notify - When set, the watch will periodically receive a WatchResponse with no events, if there are no recent events. It is useful when clients wish to recover a disconnected watcher starting from a recent known revision. The etcd server decides how often to send notifications based on current server load.
* Filters - A list of event types to filter away at server side.
* Prev_Kv - When set, the watch receives the key-value data from before the event happens. This is useful for knowing what data has been overwritten.
In response to a `WatchCreateRequest` or if there is a new event for some established watch, the client receives a `WatchResponse`:
```protobuf
message WatchResponse {
ResponseHeader header = 1;
int64 watch_id = 2;
bool created = 3;
bool canceled = 4;
int64 compact_revision = 5;
repeated mvccpb.Event events = 11;
}
```
* Watch_ID - the ID of the watch that corresponds to the response.
* Created - set to true if the response is for a create watch request. The client should record ID and expect to receive events for the watch on the stream. All events sent to the created watcher will have the same watch_id.
* Canceled - set to true if the response is for a cancel watch request. No further events will be sent to the canceled watcher.
* Compact_Revision - set to the minimum historical revision available to etcd if a watcher tries watching at a compacted revision. This happens when creating a watcher at a compacted revision or the watcher cannot catch up with the progress of the key-value store. The watcher will be canceled; creating new watches with the same start_revision will fail.
* Events - a list of new events in sequence corresponding to the given watch ID.
If the client wishes to stop receiving events for a watch, it issues a `WatchCancelRequest`:
```protobuf
message WatchCancelRequest {
int64 watch_id = 1;
}
```
* Watch_ID - the ID of the watch to cancel so that no more events are transmitted.
## Lease API
Leases are a mechanism for detecting client liveness. The cluster grants leases with a time-to-live. A lease expires if the etcd cluster does not receive a keepAlive within a given TTL period.
To tie leases into the key-value store, each key may be attached to at most one lease. When a lease expires or is revoked, all keys attached to that lease will be deleted. Each expired key generates a delete event in the event history.
### Obtaining leases
Leases are obtained through the `LeaseGrant` API call, which takes a `LeaseGrantRequest`:
```protobuf
message LeaseGrantRequest {
int64 TTL = 1;
int64 ID = 2;
}
```
* TTL - the advisory time-to-live, in seconds.
* ID - the requested ID for the lease. If ID is set to 0, etcd will choose an ID.
The client receives a `LeaseGrantResponse` from the `LeaseGrant` call:
```protobuf
message LeaseGrantResponse {
ResponseHeader header = 1;
int64 ID = 2;
int64 TTL = 3;
}
```
* ID - the lease ID for the granted lease.
* TTL - is the server selected time-to-live, in seconds, for the lease.
```protobuf
message LeaseRevokeRequest {
int64 ID = 1;
}
```
* ID - the lease ID to revoke. When the lease is revoked, all attached keys are deleted.
### Keep alives
Leases are refreshed using a bi-directional stream created with the `LeaseKeepAlive` API call. When the client wishes to refresh a lease, it sends a `LeaseGrantRequest` over the stream:
```protobuf
message LeaseKeepAliveRequest {
int64 ID = 1;
}
```
* ID - the lease ID for the lease to keep alive.
The keep alive stream responds with a `LeaseKeepAliveResponse`:
```protobuf
message LeaseKeepAliveResponse {
ResponseHeader header = 1;
int64 ID = 2;
int64 TTL = 3;
}
```
* ID - the lease that was refreshed with a new TTL.
* TTL - the new time-to-live, in seconds, that the lease has remaining.
[elections]: https://github.com/coreos/etcd/blob/master/clientv3/concurrency/election.go
[kv-proto]: https://github.com/coreos/etcd/blob/master/mvcc/mvccpb/kv.proto
[kv-service]: https://github.com/coreos/etcd/blob/master/etcdserver/etcdserverpb/rpc.proto
[response_header]: https://github.com/coreos/etcd/blob/master/etcdserver/etcdserverpb/rpc.proto
[grpc-api]: ../dev-guide/api_reference_v3.md
[grpc-service]: https://github.com/coreos/etcd/blob/master/etcdserver/etcdserverpb/rpc.proto
[locks]: https://github.com/coreos/etcd/blob/master/clientv3/concurrency/mutex.go
[mvcc]: https://en.wikipedia.org/wiki/Multiversion_concurrency_control
[stm]: https://github.com/coreos/etcd/blob/master/clientv3/concurrency/stm.go

View File

@ -1,6 +1,6 @@
# KV API guarantees
etcd is a consistent and durable key value store with mini-transaction(TODO: link to txn doc when we have it) support. The key value store is exposed through the KV APIs. etcd tries to ensure the strongest consistency and durability guarantees for a distributed system. This specification enumerates the KV API guarantees made by etcd.
etcd is a consistent and durable key value store with [mini-transaction][txn] support. The key value store is exposed through the KV APIs. etcd tries to ensure the strongest consistency and durability guarantees for a distributed system. This specification enumerates the KV API guarantees made by etcd.
### APIs to consider
@ -21,7 +21,7 @@ An etcd operation is considered complete when it is committed through consensus,
#### Revision
An etcd operation that modifies the key value store is assigned with a single increasing revision. A transaction operation might modifies the key value store multiple times, but only one revision is assigned. The revision attribute of a key value pair that modified by the operation has the same value as the revision of the operation. The revision can be used as a logical clock for key value store. A key value pair that has a larger revision is modified after a key value pair with a smaller revision. Two key value pairs that have the same revision are modified by an operation "concurrently".
An etcd operation that modifies the key value store is assigned a single increasing revision. A transaction operation might modify the key value store multiple times, but only one revision is assigned. The revision attribute of a key value pair that was modified by the operation has the same value as the revision of the operation. The revision can be used as a logical clock for key value store. A key value pair that has a larger revision is modified after a key value pair with a smaller revision. Two key value pairs that have the same revision are modified by an operation "concurrently".
### Guarantees provided
@ -61,3 +61,4 @@ etcd ensures linearizability for all other operations by default. Linearizabilit
[strict_consistency]: https://en.wikipedia.org/wiki/Consistency_model#Strict_consistency
[serializable_isolation]: https://en.wikipedia.org/wiki/Isolation_(database_systems)#Serializable
[Linearizability]: #Linearizability
[txn]: api.md#transactions

View File

@ -0,0 +1,77 @@
# etcd v3 authentication design
## Why not reuse the v2 auth system?
The v3 protocol uses gRPC as its transport instead of a RESTful interface like v2. This new protocol provides an opportunity to iterate on and improve the v2 design. For example, v3 auth has connection based authentication, rather than v2's slower per-request authentication. Additionally, v2 auth's semantics tend to be unwieldy in practice with respect to reasoning about consistency, which will be described in the next sections. For v3, there is a well-defined description and implementation of the authentication mechanism which fixes the deficiencies in the v2 auth system.
### Functionality requirements
* Per connection authentication, not per request
* User ID + password based authentication implemented for the gRPC API
* Authentication must be refreshed after auth policy changes
* Its functionality should be as simple and useful as v2
* v3 provides a flat key space, unlike the directory structure of v2. Permission checking will be provided as interval matching.
* It should have stronger consistency guarantees than v2 auth
### Main required changes
* A client must create a dedicated connection only for authentication before sending authenticated requests
* Add permission information (user ID and authorized revision) to the Raft commands (`etcdserverpb.InternalRaftRequest`)
* Every request is permission checked in the state machine layer, rather than API layer
### Permission metadata consistency
The metadata for auth should also be stored and managed in the storage controlled by etcd's Raft protocol like other data stored in etcd. It is required for not sacrificing availability and consistency of the entire etcd cluster. If reading or writing the metadata (e.g. permission information) needs an agreement of every node (more than quorum), single node failure can stop the entire cluster. Requiring all nodes to agree at once means that checking ordinary read/write requests cannot be completed if any cluster member is down, even if the cluster has an available quorum. This unanimous scheme ultimately degrades cluster availability; quorum based consensus from raft should suffice since agreement follows from consistent ordering.
The authentication mechanism in the etcd v2 protocol has a tricky part because the metadata consistency should work as in the above, but does not: each permission check is processed by the etcd member that receives the client request (etcdserver/api/v2http/client.go), including follower members. Therefore, it's possible the check may be based on stale metadata.
This staleness means that auth configuration cannot be reflected as soon as operators execute etcdctl. Therefore there is no way to know how long the stale metadata is active. Practically, the configuration change is reflected immediately after the command execution. However, in some cases of heavy load, the inconsistent state can be prolonged and it might result in counter-intuitive situations for users and developers. It requires a workaround like this: https://github.com/coreos/etcd/pull/4317#issuecomment-179037582
### Inconsistent permissions are unsafe for linearized requests
Inconsistent authentication state is most serious for writes. Even if an operator disables write on a user, if the write is only ordered with respect to the key value store but not the authentication system, it's possible the write will complete successfully. Without ordering on both the auth store and the key-value store, the system will be susceptible to stale permission attacks.
Therefore, the permission checking logic should be added to the state machine of etcd. Each state machine should check the requests based on its permission information in the apply phase (so the auth information must not be stale).
## Design and implementation
### Authentication
At first, a client must create a gRPC connection only to authenticate its user ID and password. An etcd server will respond with an authentication reply. The reponse will be an authentication token on success or an error on failure. The client can use its authentication token to present its credentials to etcd when making API requests.
The client connection used to request the authentication token is typically thrown away; it cannot carry the new token's credentials. This is because gRPC doesn't provide a way for adding per RPC credential after creation of the connection (calling `grpc.Dial()`). Therefore, a client cannot assign a token to its connection that is obtained through the connection. The client needs a new connection for using the token.
#### Notes on the implementation of `Authenticate()` RPC
`Authenticate()` RPC generates an authentication token based on a given user name and password. etcd saves and checks a configured password and a given password using Go's `bcrypt` package. By design, `bcrypt`'s password checking mechanism is computationally expensive, taking nearly 100ms on an ordinary x64 server. Therefore, performing this check in the state machine apply phase would cause performance trouble: the entire etcd cluster can only serve almost 10 `Authenticate()` requests per second.
For good performance, the v3 auth mechanism checks passwords in etcd's API layer, where it can be parallelized outside of raft. However, this can lead to potential time-of-check/time-of-use (TOCTOU) permission lapses:
1. client A sends a request `Authenticate()`
1. the API layer processes the password checking part of `Authenticate()`
1. another client B sends a request of `ChangePassword()` and the server completes it
1. the state machine layer processes the part of getting a revision number for the `Authenticate()` from A
1. the server returns a success to A
1. now A is authenticated on an obsolete password
For avoiding such a situation, the API layer performs *version number validation* based on the revision number of the auth store. During password checking, the API layer saves the revision number of auth store. After successful password checking, the API layer compares the saved revision number and the latest revision number. If the numbers differ, it means someone else updated the auth metadata. So it retries the checking. With this mechanism, the successful password checking based on the obsolete password can be avoided.
### Resolving a token in the API layer
After authenticating with `Authenticate()`, a client can create a gRPC connection as it would without auth. In addition to the existing initialization process, the client must associate the token with the newly created connection. `grpc.WithPerRPCCredentials()` provides the functionality for this purpose.
Every authenticated request from the client has a token. The token can be obtained with `grpc.metadata.FromContext()` in the server side. The server can obtain who is issuing the request and when the user was authorized. The information will be filled by the API layer in the header (`etcdserverpb.RequestHeader.Username` and `etcdserverpb.RequestHeader.AuthRevision`) of a raft log entry (`etcdserverpb.InternalRaftRequest`).
### Checking permission in the state machine
The auth info in `etcdserverpb.RequestHeader` is checked in the apply phase of the state machine. This step checks the user is granted permission to requested keys on the latest revision of auth store.
### Two types of tokens: simple and JWT
There are two kinds of token types: simple and JWT. The simple token isn't designed for production use cases. Its tokens aren't cryptographically signed and servers must statefully track token-user correspondence; it is meant for development testing. JWT tokens should be used for production deployments since it is cryptographically signed and verified. From the implementation perspective, JWT is stateless. Its token can include metadata including username and revision, so servers don't need to remember correspondence between tokens and the metadata.
## Notes on the difference between KVS models and file system models
etcd v3 is a KVS, not a file system. So the permissions can be granted to the users in form of an exact key name or a key range like `["start key", "end key")`. It means that granting a permission of a nonexistent key is possible. Users should care about unintended permission granting. In a case of file system like system (e.g. Chubby or ZooKeeper), an inode like data structure can include the permission information. So granting permission to a nonexist key won't be possible (except the case of sticky bits).
The etcd v3 model requires multiple lookup of the metadata unlike the file system like systems. The worst case lookup cost will be sum the user's total granted keys and intervals. The cost cannot be avoided because v3's flat key space is completely different from Unix's file system model (every inode includes permission metadata). Practically the cost wont be a serious problem because the metadata is small enough to benefit from caching.

View File

@ -2,19 +2,114 @@
The name "etcd" originated from two ideas, the unix "/etc" folder and "d"istibuted systems. The "/etc" folder is a place to store configuration data for a single system whereas etcd stores configuration information for large scale distributed systems. Hence, a "d"istributed "/etc" is "etcd".
etcd stores metadata in a consistent and fault-tolerant way. Distributed systems use etcd as a consistent key-value store for configuration management, service discovery, and coordinating distributed work. Common distributed patterns using etcd include leader election, [distributed locks][etcd-concurrency], and monitoring machine liveness.
etcd stores metadata in a consistent and fault-tolerant way. Distributed systems use etcd as a consistent key-value store for configuration management, service discovery, and coordinating distributed work. Common distributed patterns using etcd include [leader election][etcd-etcdctl-elect], [distributed locks][etcd-etcdctl-lock], and monitoring machine liveness.
## Use cases
- Container Linux by CoreOS: Application running on [Container Linux][container-linux] gets automatic, zero-downtime Linux kernel updates. Container Linux uses [locksmith] to coordinate updates. locksmith implements a distributed semaphore over etcd to ensure only a subset of a cluster is rebooting at any given time.
- [Kubernetes][kubernetes] stores configuration data into etcd for service discovery and cluster management; etcd's consistency is crucial for correctly scheduling and operating services. The Kubernetes API server persists cluster state into etcd. It uses etcd's watch API to monitor the cluster and roll out critical configuration changes.
## etcd versus other key-value stores
## Features and system comparisons
When deciding whether to use etcd as a key-value store, its worth keeping in mind etcds main goal. Namely, etcd is designed as a general substrate for large scale distributed systems. These are systems that will never tolerate split-brain operation and are willing to sacrifice availability to achieve this end. An etcd cluster is meant to provide consistent key-value storage with best of class stability, reliability, scalability and performance. The upshot of this focus is many [organizations][production-users] already use etcd to implement production systems such as container schedulers, service discovery services, distributed data storage, and more.
TODO
Perhaps etcd already seems like a good fit, but as with all technological decisions, proceed with caution. Please note this documentation is written by the etcd team. Although the ideal is a disinterested comparison of technology and features, the authors expertise and biases obviously favor etcd. Use only as directed.
[etcd-concurrency]: https://godoc.org/github.com/coreos/etcd/clientv3/concurrency
The table below is a handy quick reference for spotting the differences among etcd and its most popular alternatives at a glance. Further commentary and details for each column are in the sections following the table.
| | etcd | ZooKeeper | Consul | NewSQL (Cloud Spanner, CockroachDB, TiDB) |
| --- | --- | --- | --- | --- |
| Concurrency Primitives | [Lock RPCs][etcd-v3lock], [Election RPCs][etcd-v3election], [command line locks][etcd-etcdctl-lock], [command line elections][etcd-etcdctl-elect], [recipes][etcd-recipe] in go | External [curator recipes][curator] in Java | [Native lock API][consul-lock] | [Rare][newsql-leader], if any |
| Linearizable Reads | [Yes][etcd-linread] | No | [Yes][consul-linread] | Sometimes |
| Multi-version Concurrency Control | [Yes][etcd-mvcc] | No | No | Sometimes |
| Transactions | [Field compares, Read, Write][etcd-txn] | [Version checks, Write][zk-txn] | [Field compare, Lock, Read, Write][consul-txn] | SQL-style |
| Change Notification | [Historical and current key intervals][etcd-watch] | [Current keys and directories][zk-watch] | [Current keys and prefixes][consul-watch] | Triggers (sometimes) |
| User permissions | [Role based][etcd-rbac] | [ACLs][zk-acl] | [ACLs][consul-acl] | Varies (per-table [GRANT][cockroach-grant], per-database [roles][spanner-roles]) |
| HTTP/JSON API | [Yes][etcd-json] | No | [Yes][consul-json] | Rarely |
| Membership Reconfiguration | [Yes][etcd-reconfig] | [>3.5.0][zk-reconfig] | [Yes][consul-reconfig] | Yes |
| Maximum reliable database size | Several gigabytes | Hundreds of megabytes (sometimes several gigabytes) | Hundreds of MBs | Terabytes+ |
| Minimum read linearization latency | Network RTT | No read linearization | RTT + fsync | Clock barriers (atomic, NTP) |
### ZooKeeper
ZooKeeper solves the same problem as etcd: distributed system coordination and metadata storage. However, etcd has the luxury of hindsight taken from engineering and operational experience with ZooKeepers design and implementation. The lessons learned from Zookeeper certainly informed etcds design, helping it support large scale systems like Kubernetes. The improvements etcd made over Zookeeper include:
* Dynamic cluster membership reconfiguration
* Stable read/write under high load
* A multi-version concurrency control data model
* Reliable key monitoring which never silently drop events
* Lease primitives decoupling connections from sessions
* APIs for safe distributed shared locks
Furthermore, etcd supports a wide range of languages and frameworks out of the box. Whereas Zookeeper has its own custom Jute RPC protocol, which is totally unique to Zookeeper and limits its [supported language bindings][zk-bindings], etcds client protocol is built from [gRPC][grpc], a popular RPC framework with language bindings for go, C++, Java, and more. Likewise, gRPC can be serialized into JSON over HTTP, so even general command line utilities like `curl` can talk to it. Since systems can select from a variety of choices, they are built on etcd with native tooling rather than around etcd with a single fixed set of technologies.
When considering features, support, and stability, new applications planning to use Zookeeper for a consistent key value store would do well to choose etcd instead.
### Consul
Consul bills itself as an end-to-end service discovery framework. To wit, it includes services such as health checking, failure detection, and DNS. Incidentally, Consul also exposes a key value store with mediocre performance and an intricate API. As it stands in Consul 0.7, the storage system does not scales well; systems requiring millions of keys will suffer from high latencies and memory pressure. The key value API is missing, most notably, multi-version keys, conditional transactions, and reliable streaming watches.
etcd and Consul solve different problems. If looking for a distributed consistent key value store, etcd is a better choice over Consul. If looking for end-to-end cluster service discovery, etcd will not have enough features; choose Kubernetes, Consul, or SmartStack.
### NewSQL (Cloud Spanner, CockroachDB, TiDB)
Both etcd and NewSQL databases (e.g., [Cockroach][cockroach], [TiDB][tidb], [Google Spanner][spanner]) provide strong data consistency guarantees with high availability. However, the significantly different system design parameters lead to significantly different client APIs and performance characteristics.
NewSQL databases are meant to horizontally scale across data centers. These systems typically partition data across multiple consistent replication groups (shards), potentially distant, storing data sets on the order of terabytes and above. This sort of scaling makes them poor candidates for distributed coordination as they have long latencies from waiting on clocks and expect updates with mostly localized dependency graphs. The data is organized into tables, including SQL-style query facilities with richer semantics than etcd, but at the cost of additional complexity for processing, planning, and optimizing queries.
In short, choose etcd for storing metadata or coordinating distributed applications. If storing more than a few GB of data or if full SQL queries are needed, choose a NewSQL database.
## Using etcd for metadata
etcd replicates all data within a single consistent replication group. For storing up to a few GB of data with consistent ordering, this is the most efficient approach. Each modification of cluster state, which may change multiple keys, is assigned a global unique ID, called a revision in etcd, from a monotonically increasing counter for reasoning over ordering. Since theres only a single replication group, the modification request only needs to go through the raft protocol to commit. By limiting consensus to one replication group, etcd gets distributed consistency with a simple protocol while achieving low latency and high throughput.
The replication behind etcd cannot horizontally scale because it lacks data sharding. In contrast, NewSQL databases usually shard data across multiple consistent replication groups, storing data sets on the order of terabytes and above. However, to assign each modification a global unique and increasing ID, each request must go through an additional coordination protocol among replication groups. This extra coordination step may potentially conflict on the global ID, forcing ordered requests to retry. The result is a more complicated approach with typically worse performance than etcd for strict ordering.
If an application reasons primarily about metadata or metadata ordering, such as to coordinate processes, choose etcd. If the application needs a large data store spanning multiple data centers and does not heavily depend on strong global ordering properties, choose a NewSQL database.
## Using etcd for distributed coordination
etcd has distributed coordination primitives such as event watches, leases, elections, and distributed shared locks out of the box. These primitives are both maintained and supported by the etcd developers; leaving these primitives to external libraries shirks the responsibility of developing foundational distributed software, essentially leaving the system incomplete. NewSQL databases usually expect these distributed coordination primitives to be authored by third parties. Likewise, ZooKeeper famously has a separate and independent [library][curator] of coordination recipes. Consul, which provides a native locking API, goes so far as to apologize that its “[not a bulletproof method][consul-bulletproof]”.
In theory, its possible to build these primitives atop any storage systems providing strong consistency. However, the algorithms tend to be subtle; it is easy to develop a locking algorithm that appears to work, only to suddenly break due to thundering herd and timing skew. Furthermore, other primitives supported by etcd, such as transactional memory depend on etcds MVCC data model; simple strong consistency is not enough.
For distributed coordination, choosing etcd can help prevent operational headaches and save engineering effort.
[production-users]: ../production-users.md
[grpc]: http://www.grpc.io
[consul-bulletproof]: https://www.consul.io/docs/internals/sessions.html
[curator]: http://curator.apache.org/
[cockroach]: https://github.com/cockroachdb/cockroach
[spanner]: https://cloud.google.com/spanner/
[tidb]: https://github.com/pingcap/tidb
[etcd-v3lock]: https://godoc.org/github.com/coreos/etcd/etcdserver/api/v3lock/v3lockpb
[etcd-v3election]: https://godoc.org/github.com/coreos/etcd/etcdserver/api/v3election/v3electionpb
[etcd-etcdctl-lock]: ../../etcdctl/README.md#lock-lockname
[etcd-etcdctl-elect]: ../../etcdctl/README.md#elect-options-election-name-proposal
[etcd-mvcc]: data_model.md
[etcd-recipe]: https://godoc.org/github.com/coreos/etcd/contrib/recipes
[consul-lock]: https://www.consul.io/docs/commands/lock.html
[newsql-leader]: http://dl.acm.org/citation.cfm?id=2960999
[etcd-reconfig]: ../op-guide/runtime-configuration.md
[zk-reconfig]: https://zookeeper.apache.org/doc/trunk/zookeeperReconfig.html
[consul-reconfig]: https://www.consul.io/docs/guides/servers.html
[etcd-linread]: api_guarantees.md#linearizability
[consul-linread]: https://www.consul.io/docs/agent/http.html#consistency
[etcd-json]: ../dev-guide/api_grpc_gateway.md
[consul-json]: https://www.consul.io/docs/agent/http.html#formatted-json-output
[etcd-txn]: api.md#transaction
[zk-txn]: https://zookeeper.apache.org/doc/r3.4.3/api/org/apache/zookeeper/ZooKeeper.html#multi(java.lang.Iterable)
[consul-txn]: https://www.consul.io/docs/agent/http/kv.html#txn
[etcd-watch]: api.md#watch-streams
[zk-watch]: https://zookeeper.apache.org/doc/trunk/zookeeperProgrammers.html#ch_zkWatches
[consul-watch]: https://www.consul.io/docs/agent/watches.html
[etcd-commonname]: ../op-guide/authentication.md#using-tls-common-name
[etcd-rbac]: ../op-guide/authentication.md#working-with-roles
[zk-acl]: https://zookeeper.apache.org/doc/r3.1.2/zookeeperProgrammers.html#sc_ZooKeeperAccessControl
[consul-acl]: https://www.consul.io/docs/internals/acl.html
[cockroach-grant]: https://www.cockroachlabs.com/docs/grant.html
[spanner-roles]: https://cloud.google.com/spanner/docs/iam#roles
[zk-bindings]: https://zookeeper.apache.org/doc/r3.1.2/zookeeperProgrammers.html#ch_bindings
[container-linux]: https://coreos.com/why
[locksmith]: https://github.com/coreos/locksmith
[kubernetes]: http://kubernetes.io/docs/whatisk8s

View File

@ -0,0 +1,164 @@
# Authentication Guide
## Overview
Authentication was added in etcd 2.1. The etcd v3 API slightly modified the authentication feature's API and user interface to better fit the new data model. This guide is intended to help users set up basic authentication in etcd v3.
## Special users and roles
There is one special user, `root`, and one special role, `root`.
### User `root`
The `root` user, which has full access to etcd, must be created before activating authentication. The idea behind the `root` user is for administrative purposes: managing roles and ordinary users. The `root` user must have the `root` role and is allowed to change anything inside etcd.
### Role `root`
The role `root` may be granted to any user, in addition to the root user. A user with the `root` role has both global read-write access and permission to update the cluster's authentication configuration. Furthermore, the `root` role grants privileges for general cluster maintenance, including modifying cluster membership, defragmenting the store, and taking snapshots.
## Working with users
The `user` subcommand for `etcdctl` handles all things having to do with user accounts.
A listing of users can be found with:
```
$ etcdctl user list
```
Creating a user is as easy as
```
$ etcdctl user add myusername
```
Creating a new user will prompt for a new password. The password can be supplied from standard input when an option `--interactive=false` is given.
Roles can be granted and revoked for a user with:
```
$ etcdctl user grant-role myusername foo
$ etcdctl user revoke-role myusername bar
```
The user's settings can be inspected with:
```
$ etcdctl user get myusername
```
And the password for a user can be changed with
```
$ etcdctl user passwd myusername
```
Changing the password will prompt again for a new password. The password can be supplied from standard input when an option `--interactive=false` is given.
Delete an account with:
```
$ etcdctl user delete myusername
```
## Working with roles
The `role` subcommand for `etcdctl` handles all things having to do with access controls for particular roles, as were granted to individual users.
List roles with:
```
$ etcdctl role list
```
Create a new role with:
```
$ etcdctl role add myrolename
```
A role has no password; it merely defines a new set of access rights.
Roles are granted access to a single key or a range of keys.
The range can be specified as an interval [start-key, end-key) where start-key should be lexically less than end-key in an alphabetical manner.
Access can be granted as either read, write, or both, as in the following examples:
```
# Give read access to a key /foo
$ etcdctl role grant-permission myrolename read /foo
# Give read access to keys with a prefix /foo/. The prefix is equal to the range [/foo/, /foo0)
$ etcdctl role grant-permission myrolename --prefix=true read /foo/
# Give write-only access to the key at /foo/bar
$ etcdctl role grant-permission myrolename write /foo/bar
# Give full access to keys in a range of [key1, key5)
$ etcdctl role grant-permission myrolename readwrite key1 key5
# Give full access to keys with a prefix /pub/
$ etcdctl role grant-permission myrolename --prefix=true readwrite /pub/
```
To see what's granted, we can look at the role at any time:
```
$ etcdctl role get myrolename
```
Revocation of permissions is done the same logical way:
```
$ etcdctl role revoke-permission myrolename /foo/bar
```
As is removing a role entirely:
```
$ etcdctl role remove myrolename
```
## Enabling authentication
The minimal steps to enabling auth are as follows. The administrator can set up users and roles before or after enabling authentication, as a matter of preference.
Make sure the root user is created:
```
$ etcdctl user add root
Password of root:
```
Enable authentication:
```
$ etcdctl auth enable
```
After this, etcd is running with authentication enabled. To disable it for any reason, use the reciprocal command:
```
$ etcdctl --user root:rootpw auth disable
```
## Using `etcdctl` to authenticate
`etcdctl` supports a similar flag as `curl` for authentication.
```
$ etcdctl --user user:password get foo
```
The password can be taken from a prompt:
```
$ etcdctl --user user get foo
```
Otherwise, all `etcdctl` commands remain the same. Users and roles can still be created and modified, but require authentication by a user with the root role.
## Using TLS Common Name
If an etcd server is launched with the option `--client-cert-auth=true`, the field of Common Name (CN) in the client's TLS cert will be used as an etcd user. In this case, the common name authenticates the user and the client does not need a password.

View File

@ -458,7 +458,7 @@ $ etcd --name infra2 \
### Gateway
etcd gateway is a simple TCP proxy that forwards network data to the etcd cluster. Please read [gateway guide] for more information.
etcd gateway is a simple TCP proxy that forwards network data to the etcd cluster. Please read [gateway guide][gateway] for more information.
### Proxy
@ -475,5 +475,5 @@ To setup an etcd cluster with proxies of v2 API, please read the the [clustering
[proxy]: https://github.com/coreos/etcd/blob/release-2.3/Documentation/proxy.md
[clustering_etcd2]: https://github.com/coreos/etcd/blob/release-2.3/Documentation/clustering.md
[security-guide]: security.md
[tls-setup]: /hack/tls-setup
[tls-setup]: ../../hack/tls-setup
[gateway]: gateway.md

View File

@ -28,7 +28,7 @@ To start etcd automatically using custom settings at startup in Linux, using a [
### --snapshot-count
+ Number of committed transactions to trigger a snapshot to disk.
+ default: "10000"
+ default: "100000"
+ env variable: ETCD_SNAPSHOT_COUNT
### --heartbeat-interval
@ -140,6 +140,12 @@ To start etcd automatically using custom settings at startup in Linux, using a [
+ default: 0
+ env variable: ETCD_AUTO_COMPACTION_RETENTION
### --enable-v2
+ Accept etcd V2 client requests
+ default: true
+ env variable: ETCD_ENABLE_V2
## Proxy flags
`--proxy` prefix flags configures etcd to run in [proxy mode][proxy]. "proxy" supports v2 API only.
@ -179,7 +185,10 @@ To start etcd automatically using custom settings at startup in Linux, using a [
The security flags help to [build a secure etcd cluster][security].
### --ca-file [DEPRECATED]
### --ca-file
**DEPRECATED**
+ Path to the client server TLS CA file. `--ca-file ca.crt` could be replaced by `--trusted-ca-file ca.crt --client-cert-auth` and etcd will perform the same.
+ default: none
+ env variable: ETCD_CA_FILE
@ -209,7 +218,10 @@ The security flags help to [build a secure etcd cluster][security].
+ default: false
+ env variable: ETCD_AUTO_TLS
### --peer-ca-file [DEPRECATED]
### --peer-ca-file
**DEPRECATED**
+ Path to the peer server TLS CA file. `--peer-ca-file ca.crt` could be replaced by `--peer-trusted-ca-file ca.crt --peer-client-cert-auth` and etcd will perform the same.
+ default: none
+ env variable: ETCD_PEER_CA_FILE
@ -283,10 +295,17 @@ Follow the instructions when using these flags.
+ Set level of detail for exported metrics, specify 'extensive' to include histogram metrics.
+ default: basic
## Auth flags
### --auth-token
+ Specify a token type and token specific options, especially for JWT. Its format is "type,var1=val1,var2=val2,...". Possible type is 'simple' or 'jwt'. Possible variables are 'sign-method' for specifying a sign method of jwt (its possible values are 'ES256', 'ES384', 'ES512', 'HS256', 'HS384', 'HS512', 'RS256', 'RS384', 'RS512', 'PS256', 'PS384', or 'PS512'), 'pub-key' for specifying a path to a public key for verifying jwt, and 'priv-key' for specifying a path to a private key for signing jwt.
+ Example option of JWT: '--auth-token jwt,pub-key=app.rsa.pub,priv-key=app.rsa,sign-method=RS512'
+ default: "simple"
[build-cluster]: clustering.md#static
[reconfig]: runtime-configuration.md
[discovery]: clustering.md#discovery
[iana-ports]: https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=etcd
[iana-ports]: http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.txt
[proxy]: ../v2/proxy.md
[restore]: ../v2/admin_guide.md#restoring-a-backup
[security]: security.md

View File

@ -21,10 +21,10 @@ sudo rkt trust --prefix coreos.com/etcd
# gpg key fingerprint is: 18AD 5014 C99E F7E3 BA5F 6CE9 50BD D3E0 FC8A 365E
```
Run the `v3.0.6` version of etcd or specify another release version.
Run the `v3.1.2` version of etcd or specify another release version.
```
sudo rkt run --net=default:IP=${NODE1} coreos.com/etcd:v3.0.6 -- -name=node1 -advertise-client-urls=http://${NODE1}:2379 -initial-advertise-peer-urls=http://${NODE1}:2380 -listen-client-urls=http://0.0.0.0:2379 -listen-peer-urls=http://${NODE1}:2380 -initial-cluster=node1=http://${NODE1}:2380
sudo rkt run --net=default:IP=${NODE1} coreos.com/etcd:v3.1.2 -- -name=node1 -advertise-client-urls=http://${NODE1}:2379 -initial-advertise-peer-urls=http://${NODE1}:2380 -listen-client-urls=http://0.0.0.0:2379 -listen-peer-urls=http://${NODE1}:2380 -initial-cluster=node1=http://${NODE1}:2380
```
List the cluster member.
@ -45,19 +45,19 @@ export NODE3=172.16.28.23
```
# node 1
sudo rkt run --net=default:IP=${NODE1} coreos.com/etcd:v3.0.6 -- -name=node1 -advertise-client-urls=http://${NODE1}:2379 -initial-advertise-peer-urls=http://${NODE1}:2380 -listen-client-urls=http://0.0.0.0:2379 -listen-peer-urls=http://${NODE1}:2380 -initial-cluster=node1=http://${NODE1}:2380,node2=http://${NODE2}:2380,node3=http://${NODE3}:2380
sudo rkt run --net=default:IP=${NODE1} coreos.com/etcd:v3.1.2 -- -name=node1 -advertise-client-urls=http://${NODE1}:2379 -initial-advertise-peer-urls=http://${NODE1}:2380 -listen-client-urls=http://0.0.0.0:2379 -listen-peer-urls=http://${NODE1}:2380 -initial-cluster=node1=http://${NODE1}:2380,node2=http://${NODE2}:2380,node3=http://${NODE3}:2380
# node 2
sudo rkt run --net=default:IP=${NODE2} coreos.com/etcd:v3.0.6 -- -name=node2 -advertise-client-urls=http://${NODE2}:2379 -initial-advertise-peer-urls=http://${NODE2}:2380 -listen-client-urls=http://0.0.0.0:2379 -listen-peer-urls=http://${NODE2}:2380 -initial-cluster=node1=http://${NODE1}:2380,node2=http://${NODE2}:2380,node3=http://${NODE3}:2380
sudo rkt run --net=default:IP=${NODE2} coreos.com/etcd:v3.1.2 -- -name=node2 -advertise-client-urls=http://${NODE2}:2379 -initial-advertise-peer-urls=http://${NODE2}:2380 -listen-client-urls=http://0.0.0.0:2379 -listen-peer-urls=http://${NODE2}:2380 -initial-cluster=node1=http://${NODE1}:2380,node2=http://${NODE2}:2380,node3=http://${NODE3}:2380
# node 3
sudo rkt run --net=default:IP=${NODE3} coreos.com/etcd:v3.0.6 -- -name=node3 -advertise-client-urls=http://${NODE3}:2379 -initial-advertise-peer-urls=http://${NODE3}:2380 -listen-client-urls=http://0.0.0.0:2379 -listen-peer-urls=http://${NODE3}:2380 -initial-cluster=node1=http://${NODE1}:2380,node2=http://${NODE2}:2380,node3=http://${NODE3}:2380
sudo rkt run --net=default:IP=${NODE3} coreos.com/etcd:v3.1.2 -- -name=node3 -advertise-client-urls=http://${NODE3}:2379 -initial-advertise-peer-urls=http://${NODE3}:2380 -listen-client-urls=http://0.0.0.0:2379 -listen-peer-urls=http://${NODE3}:2380 -initial-cluster=node1=http://${NODE1}:2380,node2=http://${NODE2}:2380,node3=http://${NODE3}:2380
```
Verify the cluster is healthy and can be reached.
```
ETCDCTL_API=3 etcdctl --endpoints=http://172.16.28.21:2379,http://172.16.28.22:2379,http://172.16.28.23:2379 endpoint-health
ETCDCTL_API=3 etcdctl --endpoints=http://172.16.28.21:2379,http://172.16.28.22:2379,http://172.16.28.23:2379 endpoint health
```
### DNS
@ -68,9 +68,40 @@ Production clusters which refer to peers by DNS name known to the local resolver
In order to expose the etcd API to clients outside of Docker host, use the host IP address of the container. Please see [`docker inspect`](https://docs.docker.com/engine/reference/commandline/inspect) for more detail on how to get the IP address. Alternatively, specify `--net=host` flag to `docker run` command to skip placing the container inside of a separate network stack.
### Running a single node etcd
Use the host IP address when configuring etcd:
```
export NODE1=192.168.1.21
```
Run the latest version of etcd:
```
docker run \
-p 2379:2379 \
-p 2380:2380 \
--volume=${DATA_DIR}:/etcd-data \
--name etcd quay.io/coreos/etcd:latest \
/usr/local/bin/etcd \
--data-dir=/etcd-data --name node1 \
--initial-advertise-peer-urls http://${NODE1}:2380 --listen-peer-urls http://${NODE1}:2380 \
--advertise-client-urls http://${NODE1}:2379 --listen-client-urls http://${NODE1}:2379 \
--initial-cluster node1=http://${NODE1}:2380
```
List the cluster member:
```
etcdctl --endpoints=http://${NODE1}:2379 member list
```
### Running a 3 node etcd cluster
```
# For each machine
ETCD_VERSION=v3.0.0
ETCD_VERSION=latest
TOKEN=my-etcd-token
CLUSTER_STATE=new
NAME_1=etcd-node-0
@ -80,39 +111,52 @@ HOST_1=10.20.30.1
HOST_2=10.20.30.2
HOST_3=10.20.30.3
CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_3}=http://${HOST_3}:2380
DATA_DIR=/var/lib/etcd
# For node 1
THIS_NAME=${NAME_1}
THIS_IP=${HOST_1}
sudo docker run --net=host --name etcd quay.io/coreos/etcd:${ETCD_VERSION} \
/usr/local/bin/etcd \
--data-dir=data.etcd --name ${THIS_NAME} \
--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
--initial-cluster ${CLUSTER} \
--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}
docker run \
-p 2379:2379 \
-p 2380:2380 \
--volume=${DATA_DIR}:/etcd-data \
--name etcd quay.io/coreos/etcd:${ETCD_VERSION} \
/usr/local/bin/etcd \
--data-dir=/etcd-data --name ${THIS_NAME} \
--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
--initial-cluster ${CLUSTER} \
--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}
# For node 2
THIS_NAME=${NAME_2}
THIS_IP=${HOST_2}
sudo docker run --net=host --name etcd quay.io/coreos/etcd:${ETCD_VERSION} \
/usr/local/bin/etcd \
--data-dir=data.etcd --name ${THIS_NAME} \
--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
--initial-cluster ${CLUSTER} \
--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}
docker run \
-p 2379:2379 \
-p 2380:2380 \
--volume=${DATA_DIR}:/etcd-data \
--name etcd quay.io/coreos/etcd:${ETCD_VERSION} \
/usr/local/bin/etcd \
--data-dir=/etcd-data --name ${THIS_NAME} \
--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
--initial-cluster ${CLUSTER} \
--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}
# For node 3
THIS_NAME=${NAME_3}
THIS_IP=${HOST_3}
sudo docker run --net=host --name etcd quay.io/coreos/etcd:${ETCD_VERSION} \
/usr/local/bin/etcd \
--data-dir=data.etcd --name ${THIS_NAME} \
--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
--initial-cluster ${CLUSTER} \
--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}
docker run \
-p 2379:2379 \
-p 2380:2380 \
--volume=${DATA_DIR}:/etcd-data \
--name etcd quay.io/coreos/etcd:${ETCD_VERSION} \
/usr/local/bin/etcd \
--data-dir=/etcd-data --name ${THIS_NAME} \
--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
--initial-cluster ${CLUSTER} \
--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}
```
To run `etcdctl` using API version 3:
@ -123,5 +167,30 @@ docker exec etcd /bin/sh -c "export ETCDCTL_API=3 && /usr/local/bin/etcdctl put
## Bare Metal
To provision a 3 node etcd cluster on bare-metal, you might find the examples in the [baremetal repo](https://github.com/coreos/coreos-baremetal/tree/master/examples) useful.
To provision a 3 node etcd cluster on bare-metal, the examples in the [baremetal repo](https://github.com/coreos/coreos-baremetal/tree/master/examples) may be useful.
## Mounting a certificate volume
The etcd release container does not include default root certificates. To use HTTPS with certificates trusted by a root authority (e.g., for discovery), mount a certificate directory into the etcd container:
```
rkt run \
--volume etcd-ssl-certs-bundle,kind=host,source=/etc/ssl/certs/ca-certificates.crt \
--mount volume=etcd-ssl-certs-bundle,target=/etc/ssl/certs/ca-certificates.crt \
quay.io/coreos/etcd:latest -- --name my-name \
--initial-advertise-peer-urls http://localhost:2380 --listen-peer-urls http://localhost:2380 \
--advertise-client-urls http://localhost:2379 --listen-client-urls http://localhost:2379 \
--discovery https://discovery.etcd.io/c11fbcdc16972e45253491a24fcf45e1
```
```
docker run \
-p 2379:2379 \
-p 2380:2380 \
--volume=/etc/ssl/certs/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt \
quay.io/coreos/etcd:latest \
/usr/local/bin/etcd --name my-name \
--initial-advertise-peer-urls http://localhost:2380 --listen-peer-urls http://localhost:2380 \
--advertise-client-urls http://localhost:2379 --listen-client-urls http://localhost:2379 \
--discovery https://discovery.etcd.io/86a9ff6c8cb8b4c4544c1a2f88f8b801
```

View File

@ -0,0 +1,206 @@
# general cluster availability
# alert if another failed member will result in an unavailable cluster
ALERT InsufficientMembers
IF count(up{job="etcd"} == 0) > (count(up{job="etcd"}) / 2 - 1)
FOR 3m
LABELS {
severity = "critical"
}
ANNOTATIONS {
summary = "etcd cluster insufficient members",
description = "If one more etcd member goes down the cluster will be unavailable",
}
# etcd leader alerts
# ==================
# alert if any etcd instance has no leader
ALERT NoLeader
IF etcd_server_has_leader{job="etcd"} == 0
FOR 1m
LABELS {
severity = "critical"
}
ANNOTATIONS {
summary = "etcd member has no leader",
description = "etcd member {{ $labels.instance }} has no leader",
}
# alert if there are lots of leader changes
ALERT HighNumberOfLeaderChanges
IF increase(etcd_server_leader_changes_seen_total{job="etcd"}[1h]) > 3
LABELS {
severity = "warning"
}
ANNOTATIONS {
summary = "a high number of leader changes within the etcd cluster are happening",
description = "etcd instance {{ $labels.instance }} has seen {{ $value }} leader changes within the last hour",
}
# gRPC request alerts
# ===================
# alert if more than 1% of gRPC method calls have failed within the last 5 minutes
ALERT HighNumberOfFailedGRPCRequests
IF sum by(grpc_method) (rate(etcd_grpc_requests_failed_total{job="etcd"}[5m]))
/ sum by(grpc_method) (rate(etcd_grpc_total{job="etcd"}[5m])) > 0.01
FOR 10m
LABELS {
severity = "warning"
}
ANNOTATIONS {
summary = "a high number of gRPC requests are failing",
description = "{{ $value }}% of requests for {{ $labels.grpc_method }} failed on etcd instance {{ $labels.instance }}",
}
# alert if more than 5% of gRPC method calls have failed within the last 5 minutes
ALERT HighNumberOfFailedGRPCRequests
IF sum by(grpc_method) (rate(etcd_grpc_requests_failed_total{job="etcd"}[5m]))
/ sum by(grpc_method) (rate(etcd_grpc_total{job="etcd"}[5m])) > 0.05
FOR 5m
LABELS {
severity = "critical"
}
ANNOTATIONS {
summary = "a high number of gRPC requests are failing",
description = "{{ $value }}% of requests for {{ $labels.grpc_method }} failed on etcd instance {{ $labels.instance }}",
}
# alert if the 99th percentile of gRPC method calls take more than 150ms
ALERT GRPCRequestsSlow
IF histogram_quantile(0.99, rate(etcd_grpc_unary_requests_duration_seconds_bucket[5m])) > 0.15
FOR 10m
LABELS {
severity = "critical"
}
ANNOTATIONS {
summary = "slow gRPC requests",
description = "on etcd instance {{ $labels.instance }} gRPC requests to {{ $label.grpc_method }} are slow",
}
# HTTP requests alerts
# ====================
# alert if more than 1% of requests to an HTTP endpoint have failed within the last 5 minutes
ALERT HighNumberOfFailedHTTPRequests
IF sum by(method) (rate(etcd_http_failed_total{job="etcd"}[5m]))
/ sum by(method) (rate(etcd_http_received_total{job="etcd"}[5m])) > 0.01
FOR 10m
LABELS {
severity = "warning"
}
ANNOTATIONS {
summary = "a high number of HTTP requests are failing",
description = "{{ $value }}% of requests for {{ $labels.method }} failed on etcd instance {{ $labels.instance }}",
}
# alert if more than 5% of requests to an HTTP endpoint have failed within the last 5 minutes
ALERT HighNumberOfFailedHTTPRequests
IF sum by(method) (rate(etcd_http_failed_total{job="etcd"}[5m]))
/ sum by(method) (rate(etcd_http_received_total{job="etcd"}[5m])) > 0.05
FOR 5m
LABELS {
severity = "critical"
}
ANNOTATIONS {
summary = "a high number of HTTP requests are failing",
description = "{{ $value }}% of requests for {{ $labels.method }} failed on etcd instance {{ $labels.instance }}",
}
# alert if the 99th percentile of HTTP requests take more than 150ms
ALERT HTTPRequestsSlow
IF histogram_quantile(0.99, rate(etcd_http_successful_duration_seconds_bucket[5m])) > 0.15
FOR 10m
LABELS {
severity = "warning"
}
ANNOTATIONS {
summary = "slow HTTP requests",
description = "on etcd instance {{ $labels.instance }} HTTP requests to {{ $label.method }} are slow",
}
# file descriptor alerts
# ======================
instance:fd_utilization = process_open_fds / process_max_fds
# alert if file descriptors are likely to exhaust within the next 4 hours
ALERT FdExhaustionClose
IF predict_linear(instance:fd_utilization[1h], 3600 * 4) > 1
FOR 10m
LABELS {
severity = "warning"
}
ANNOTATIONS {
summary = "file descriptors soon exhausted",
description = "{{ $labels.job }} instance {{ $labels.instance }} will exhaust its file descriptors soon",
}
# alert if file descriptors are likely to exhaust within the next hour
ALERT FdExhaustionClose
IF predict_linear(instance:fd_utilization[10m], 3600) > 1
FOR 10m
LABELS {
severity = "critical"
}
ANNOTATIONS {
summary = "file descriptors soon exhausted",
description = "{{ $labels.job }} instance {{ $labels.instance }} will exhaust its file descriptors soon",
}
# etcd member communication alerts
# ================================
# alert if 99th percentile of round trips take 150ms
ALERT EtcdMemberCommunicationSlow
IF histogram_quantile(0.99, rate(etcd_network_member_round_trip_time_seconds_bucket[5m])) > 0.15
FOR 10m
LABELS {
severity = "warning"
}
ANNOTATIONS {
summary = "etcd member communication is slow",
description = "etcd instance {{ $labels.instance }} member communication with {{ $label.To }} is slow",
}
# etcd proposal alerts
# ====================
# alert if there are several failed proposals within an hour
ALERT HighNumberOfFailedProposals
IF increase(etcd_server_proposals_failed_total{job="etcd"}[1h]) > 5
LABELS {
severity = "warning"
}
ANNOTATIONS {
summary = "a high number of proposals within the etcd cluster are failing",
description = "etcd instance {{ $labels.instance }} has seen {{ $value }} proposal failures within the last hour",
}
# etcd disk io latency alerts
# ===========================
# alert if 99th percentile of fsync durations is higher than 500ms
ALERT HighFsyncDurations
IF histogram_quantile(0.99, rate(etcd_disk_wal_fsync_duration_seconds_bucket[5m])) > 0.5
FOR 10m
LABELS {
severity = "warning"
}
ANNOTATIONS {
summary = "high fsync durations",
description = "etcd instance {{ $labels.instance }} fync durations are high",
}
# alert if 99th percentile of commit durations is higher than 250ms
ALERT HighCommitDurations
IF histogram_quantile(0.99, rate(etcd_disk_backend_commit_duration_seconds_bucket[5m])) > 0.25
FOR 10m
LABELS {
severity = "warning"
}
ANNOTATIONS {
summary = "high commit durations",
description = "etcd instance {{ $labels.instance }} commit durations are high",
}

View File

@ -4,16 +4,15 @@
etcd gateway is a simple TCP proxy that forwards network data to the etcd cluster. The gateway is stateless and transparent; it neither inspects client requests nor interferes with cluster responses.
The gateway supports multiple etcd server endpoints. When the gateway starts, it randomly picks one etcd server endpoint and forwards all requests to that endpoint. This endpoint serves all requests until the gateway detects a network failure. If the gateway detects an endpoint failure, it will switch to a different endpoint, if available, to hide failures from its clients. Other retry policies, such as weighted round-robin, may be supported in the future.
The gateway supports multiple etcd server endpoints and works on a simple round-robin policy. It only routes to available enpoints and hides failures from its clients. Other retry policies, such as weighted round-robin, may be supported in the future.
## When to use etcd gateway
Every application that accesses etcd must first have the address of an etcd cluster client endpoint. If multiple applications on the same server access the same etcd cluster, every application still needs to know the advertised client endpoints of the etcd cluster. If the etcd cluster is reconfigured to have different endpoints, every application may also need to update its endpoint list. This wide-scale reconfiguration is both tedious and error prone.
etcd gateway solves this problem by serving as a stable local endpoint. A typical etcd gateway configuration has
each machine running a gateway listening on a local address and every etcd application connecting to its local gateway. The upshot is only the gateway needs to update its endpoints instead of updating each and every application.
etcd gateway solves this problem by serving as a stable local endpoint. A typical etcd gateway configuration has each machine running a gateway listening on a local address and every etcd application connecting to its local gateway. The upshot is only the gateway needs to update its endpoints instead of updating each and every application.
In summary, to automatically propagate cluster endpoint changes, the etcd gateway runs on every machine serving multiple applications accessing same etcd cluster.
In summary, to automatically propagate cluster endpoint changes, the etcd gateway runs on every machine serving multiple applications accessing the same etcd cluster.
## When not to use etcd gateway
@ -63,4 +62,44 @@ Start the etcd gateway to fetch the endpoints from the DNS SRV entries with the
```bash
$ etcd gateway --discovery-srv=example.com
2016-08-16 11:21:18.867350 I | tcpproxy: ready to proxy client requests to [...]
```
```
## Configuration flags
### etcd cluster
#### --endpoints
* Comma-separated list of etcd server targets for forwarding client connections.
* Default: `127.0.0.1:2379`
* Invalid example: `https://127.0.0.1:2379` (gateway does not terminate TLS)
#### --discovery-srv
* DNS domain used to bootstrap cluster endpoints through SRV recrods.
* Default: (not set)
### Network
#### --listen-addr
* Interface and port to bind for accepting client requests.
* Default: `127.0.0.1:23790`
#### --retry-delay
* Duration of delay before retrying to connect to failed endpoints.
* Default: 1m0s
* Invalid example: "123" (expects time unit in format)
### Security
#### --insecure-discovery
* Accept SRV records that are insecure or susceptible to man-in-the-middle attacks.
* Default: `false`
#### --trusted-ca-file
* Path to the client TLS CA file for the etcd cluster. Used to authenticate endpoints.
* Default: (not set)

View File

@ -115,7 +115,7 @@
"stack": false,
"steppedLine": false,
"targets": [{
"expr": "sum(rate({grpc_type=\"unary\",grpc_code!=\"OK\"} [1m]))",
"expr": "sum(rate(grpc_server_started_total{grpc_type=\"unary\"} [1m]))",
"intervalFactor": 2,
"legendFormat": "{{instance}} RPC Rate",
"metric": "grpc_server_started_total",
@ -123,7 +123,7 @@
"step": 2
},
{
"expr": "sum(rate(grpc_server_started_total{grpc_type=\"unary\",grpc_code!=\"OK\"} [1m])) - sum(rate(grpc_server_handled_total{grpc_type=\"unary\"} [1m]))",
"expr": "sum(rate(grpc_server_started_total{grpc_type=\"unary\"} [1m])) - sum(rate(grpc_server_handled_total{grpc_type=\"unary\",grpc_code!=\"OK\"} [1m]))",
"intervalFactor": 2,
"legendFormat": "{{instance}} RPC Failed Rate",
"metric": "grpc_server_handled_total",
@ -197,7 +197,7 @@
"stack": true,
"steppedLine": false,
"targets": [{
"expr": "sum(grpc_server_started_total {grpc_service=\"etcdserverpb.Watch\",grpc_type=\"bidi_stream\",grpc_code!=\"OK\"}) - sum(grpc_server_handled_total {grpc_service=\"etcdserverpb.Watch\",grpc_type=\"bidi_stream\"})",
"expr": "sum(grpc_server_started_total{grpc_service=\"etcdserverpb.Watch\",grpc_type=\"bidi_stream\"}) - sum(grpc_server_handled_total{grpc_service=\"etcdserverpb.Watch\",grpc_type=\"bidi_stream\"})",
"intervalFactor": 2,
"legendFormat": "Watch Streams",
"metric": "grpc_server_handled_total",
@ -205,7 +205,7 @@
"step": 4
},
{
"expr": "sum(grpc_server_started_total {grpc_service=\"etcdserverpb.Lease\",grpc_type=\"bidi_stream\"}) - sum(grpc_server_handled_total {grpc_service=\"etcdserverpb.Lease\",grpc_type=\"bidi_stream\"})",
"expr": "sum(grpc_server_started_total{grpc_service=\"etcdserverpb.Lease\",grpc_type=\"bidi_stream\"}) - sum(grpc_server_handled_total{grpc_service=\"etcdserverpb.Lease\",grpc_type=\"bidi_stream\"})",
"intervalFactor": 2,
"legendFormat": "Lease Streams",
"metric": "grpc_server_handled_total",

View File

@ -1,7 +1,5 @@
# gRPC proxy
*This is a pre-alpha feature, we are looking for early feedback.*
The gRPC proxy is a stateless etcd reverse proxy operating at the gRPC layer (L7). The proxy is designed to reduce the total processing load on the core etcd cluster. For horizontal scalability, it coalesces watch and lease API requests. To protect the cluster against abusive clients, it caches key range requests.
The gRPC proxy supports multiple etcd server endpoints. When the proxy starts, it randomly picks one etcd server endpoint to use. This endpoint serves all requests until the proxy detects an endpoint failure. If the gRPC proxy detects an endpoint failure, it switches to a different endpoint, if available, to hide failures from its clients. Other retry policies, such as weighted round-robin, may be supported in the future.
@ -36,13 +34,36 @@ watch key A ^ ^ watch key A |
To effectively coalesce multiple client watchers into a single watcher, the gRPC proxy coalesces new `c-watchers` into an existing `s-watcher` when possible. This coalesced `s-watcher` may be out of sync with the etcd server due to network delays or buffered undelivered events. When the watch revision is unspecified, the gRPC proxy will not guarantee the `c-watcher` will start watching from the most recent store revision. For example, if a client watches from an etcd server with revision 1000, that watcher will begin at revision 1000. If a client watches from the gRPC proxy, may begin watching from revision 990.
Similar limitations apply to cancellation. When the watcher is cancelled, the etcd servers revision may be greater than the cancellation response revision.
Similar limitations apply to cancellation. When the watcher is cancelled, the etcd servers revision may be greater than the cancellation response revision.
These two limitations should not cause problems for most use cases. In the future, there may be additional options to force the watcher to bypass the gRPC proxy for more accurate revision responses.
These two limitations should not cause problems for most use cases. In the future, there may be additional options to force the watcher to bypass the gRPC proxy for more accurate revision responses.
## Scalable lease API
TODO
To keep its leases alive, a client must establish at least one gRPC stream to an etcd server for sending periodic heartbeats. If an etcd workload involves heavy lease activity spread over many clients, these streams may contribute to excessive CPU utilization. To reduce the total number of streams on the core cluster, the proxy supports lease stream coalescing.
Assuming N clients are updating leases, a single gRPC proxy reduces the stream load on the etcd server from N to 1. Deployments may have additional gRPC proxies to further distribute streams across multiple proxies.
In the following example, three clients update three independent leases (`L1`, `L2`, and `L3`). The gRPC proxy coalesces the three client lease streams (`c-streams`) into a single lease keep alive stream (`s-stream`) attached to an etcd server. The proxy forwards client-side lease heartbeats from the c-streams to the s-stream, then returns the responses to the corresponding c-streams.
```
+-------------+
| etcd server |
+------+------+
^
| heartbeat L1, L2, L3
| (s-stream)
v
+-------+-----+
| gRPC proxy +<-----------+
+---+------+--+ | heartbeat L3
^ ^ | (c-stream)
heartbeat L1 | | heartbeat L2 |
(c-stream) v v (c-stream) v
+------+-+ +-+------+ +-----+--+
| client | | client | | client |
+--------+ +--------+ +--------+
```
## Abusive clients protection
@ -75,3 +96,98 @@ $ ETCDCTL_API=3 ./etcdctl --endpoints=127.0.0.1:2379 get foo
foo
bar
```
## Client endpoint synchronization and name resolution
The proxy supports registering its endpoints for discovery by writing to a user-defined endpoint. This serves two purposes. First, it allows clients to synchronize their endpoints against a set of proxy endpoints for high availability. Second, it is an endpoint provider for etcd [gRPC naming](../dev-guide/grpc_naming.md).
Register proxy(s) by providing a user-defined prefix:
```bash
$ etcd grpc-proxy start --endpoints=localhost:2379 \
--listen-addr=127.0.0.1:23790 \
--advertise-client-url=127.0.0.1:23790 \
--resolver-prefix="___grpc_proxy_endpoint" \
--resolver-ttl=60
$ etcd grpc-proxy start --endpoints=localhost:2379 \
--listen-addr=127.0.0.1:23791 \
--advertise-client-url=127.0.0.1:23791 \
--resolver-prefix="___grpc_proxy_endpoint" \
--resolver-ttl=60
```
The proxy will list all its members for member list:
```bash
ETCDCTL_API=3 ./bin/etcdctl --endpoints=http://localhost:23790 member list --write-out table
+----+---------+--------------------------------+------------+-----------------+
| ID | STATUS | NAME | PEER ADDRS | CLIENT ADDRS |
+----+---------+--------------------------------+------------+-----------------+
| 0 | started | Gyu-Hos-MBP.sfo.coreos.systems | | 127.0.0.1:23791 |
| 0 | started | Gyu-Hos-MBP.sfo.coreos.systems | | 127.0.0.1:23790 |
+----+---------+--------------------------------+------------+-----------------+
```
This lets clients automatically discover proxy endpoints through Sync:
```go
cli, err := clientv3.New(clientv3.Config{
Endpoints: []string{"http://localhost:23790"},
})
if err != nil {
log.Fatal(err)
}
defer cli.Close()
// fetch registered grpc-proxy endpoints
if err := cli.Sync(context.Background()); err != nil {
log.Fatal(err)
}
```
Note that if a proxy is configured without a resolver prefix,
```bash
$ etcd grpc-proxy start --endpoints=localhost:2379 \
--listen-addr=127.0.0.1:23792 \
--advertise-client-url=127.0.0.1:23792
```
the member list API to the grpc-proxy returns its own `advertise-client-url`:
```bash
ETCDCTL_API=3 ./bin/etcdctl --endpoints=http://localhost:23792 member list --write-out table
+----+---------+--------------------------------+------------+-----------------+
| ID | STATUS | NAME | PEER ADDRS | CLIENT ADDRS |
+----+---------+--------------------------------+------------+-----------------+
| 0 | started | Gyu-Hos-MBP.sfo.coreos.systems | | 127.0.0.1:23792 |
+----+---------+--------------------------------+------------+-----------------+
```
## Namespacing
Suppose an application expects full control over the entire key space, but the etcd cluster is shared with other applications. To let all appications run without interfering with each other, the proxy can partition the etcd keyspace so clients appear to have access to the complete keyspace. When the proxy is given the flag `--namespace`, all client requests going into the proxy are translated to have a user-defined prefix on the keys. Accesses to the etcd cluster will be under the prefix and responses from the proxy will strip away the prefix; to the client, it appears as if there is no prefix at all.
To namespace a proxy, start it with `--namespace`:
```bash
$ etcd grpc-proxy start --endpoints=localhost:2379 \
--listen-addr=127.0.0.1:23790 \
--namespace=my-prefix/
```
Accesses to the proxy are now transparently prefixed on the etcd cluster:
```bash
$ ETCDCTL_API=3 ./bin/etcdctl --endpoints=localhost:23790 put my-key abc
# OK
$ ETCDCTL_API=3 ./bin/etcdctl --endpoints=localhost:23790 get my-key
# my-key
# abc
$ ETCDCTL_API=3 ./bin/etcdctl --endpoints=localhost:2379 get my-prefix/my-key
# my-prefix/my-key
# abc
```

View File

@ -56,6 +56,12 @@ nohup /tmp/prometheus \
Now Prometheus will scrape etcd metrics every 10 seconds.
## Alerting
There is a [set of default alerts for etcd v3 clusters](./etcd3_alert.rules).
> Note: `job` labels may need to be adjusted to fit a particular need. The rules were written to apply to a single cluster so it is recommended to choose labels unique to a cluster.
## Grafana
[Grafana][grafana] has built-in Prometheus support; just add a Prometheus data source:

View File

@ -17,58 +17,54 @@ For some baseline performance numbers, we consider a three member etcd cluster w
- Google Cloud Compute Engine
- 3 machines of 8 vCPUs + 16GB Memory + 50GB SSD
- 1 machine(client) of 16 vCPUs + 30GB Memory + 50GB SSD
- Ubuntu 15.10
- etcd v3 master branch (commit SHA d8f325d), Go 1.6.2
- Ubuntu 17.04
- etcd 3.2.0, go 1.8.3
With this configuration, etcd can approximately write:
| Number of keys | Key size in bytes | Value size in bytes | Number of connections | Number of clients | Target etcd server | Average write QPS | Average latency per request | Memory |
|----------------|-------------------|---------------------|-----------------------|-------------------|--------------------|-------------------|-----------------------------|--------|
| 10,000 | 8 | 256 | 1 | 1 | leader only | 525 | 2ms | 35 MB |
| 100,000 | 8 | 256 | 100 | 1000 | leader only | 25,000 | 30ms | 35 MB |
| 100,000 | 8 | 256 | 100 | 1000 | all members | 33,000 | 25ms | 35 MB |
| Number of keys | Key size in bytes | Value size in bytes | Number of connections | Number of clients | Target etcd server | Average write QPS | Average latency per request | Average server RSS |
|---------------:|------------------:|--------------------:|----------------------:|------------------:|--------------------|------------------:|----------------------------:|-------------------:|
| 10,000 | 8 | 256 | 1 | 1 | leader only | 583 | 1.6ms | 48 MB |
| 100,000 | 8 | 256 | 100 | 1000 | leader only | 44,341 | 22ms | 124MB |
| 100,000 | 8 | 256 | 100 | 1000 | all members | 50,104 | 20ms | 126MB |
Sample commands are:
```
# assuming IP_1 is leader, write requests to the leader
benchmark --endpoints={IP_1} --conns=1 --clients=1 \
```sh
# write to leader
benchmark --endpoints=${HOST_1} --target-leader --conns=1 --clients=1 \
put --key-size=8 --sequential-keys --total=10000 --val-size=256
benchmark --endpoints={IP_1} --conns=100 --clients=1000 \
benchmark --endpoints=${HOST_1} --target-leader --conns=100 --clients=1000 \
put --key-size=8 --sequential-keys --total=100000 --val-size=256
# write to all members
benchmark --endpoints={IP_1},{IP_2},{IP_3} --conns=100 --clients=1000 \
benchmark --endpoints=${HOST_1},${HOST_2},${HOST_3} --conns=100 --clients=1000 \
put --key-size=8 --sequential-keys --total=100000 --val-size=256
```
Linearizable read requests go through a quorum of cluster members for consensus to fetch the most recent data. Serializable read requests are cheaper than linearizable reads since they are served by any single etcd member, instead of a quorum of members, in exchange for possibly serving stale data. etcd can read:
| Number of requests | Key size in bytes | Value size in bytes | Number of connections | Number of clients | Consistency | Average latency per request | Average read QPS |
|--------------------|-------------------|---------------------|-----------------------|-------------------|-------------|-----------------------------|------------------|
| 10,000 | 8 | 256 | 1 | 1 | Linearizable | 2ms | 560 |
| 10,000 | 8 | 256 | 1 | 1 | Serializable | 0.4ms | 7,500 |
| 100,000 | 8 | 256 | 100 | 1000 | Linearizable | 15ms | 43,000 |
| 100,000 | 8 | 256 | 100 | 1000 | Serializable | 9ms | 93,000 |
| Number of requests | Key size in bytes | Value size in bytes | Number of connections | Number of clients | Consistency | Average read QPS | Average latency per request |
|-------------------:|------------------:|--------------------:|----------------------:|------------------:|-------------|-----------------:|----------------------------:|
| 10,000 | 8 | 256 | 1 | 1 | Linearizable | 1,353 | 0.7ms |
| 10,000 | 8 | 256 | 1 | 1 | Serializable | 2,909 | 0.3ms |
| 100,000 | 8 | 256 | 100 | 1000 | Linearizable | 141,578 | 5.5ms |
| 100,000 | 8 | 256 | 100 | 1000 | Serializable | 185,758 | 2.2ms |
Sample commands are:
```
# Linearizable read requests
benchmark --endpoints={IP_1},{IP_2},{IP_3} --conns=1 --clients=1 \
```sh
# Single connection read requests
benchmark --endpoints=${HOST_1},${HOST_2},${HOST_3} --conns=1 --clients=1 \
range YOUR_KEY --consistency=l --total=10000
benchmark --endpoints={IP_1},{IP_2},{IP_3} --conns=100 --clients=1000 \
range YOUR_KEY --consistency=l --total=100000
benchmark --endpoints=${HOST_1},${HOST_2},${HOST_3} --conns=1 --clients=1 \
range YOUR_KEY --consistency=s --total=10000
# Serializable read requests for each member and sum up the numbers
for endpoint in {IP_1} {IP_2} {IP_3}; do
benchmark --endpoints=$endpoint --conns=1 --clients=1 \
range YOUR_KEY --consistency=s --total=10000
done
for endpoint in {IP_1} {IP_2} {IP_3}; do
benchmark --endpoints=$endpoint --conns=100 --clients=1000 \
range YOUR_KEY --consistency=s --total=100000
done
# Many concurrent read requests
benchmark --endpoints=${HOST_1},${HOST_2},${HOST_3} --conns=100 --clients=1000 \
range YOUR_KEY --consistency=l --total=100000
benchmark --endpoints=${HOST_1},${HOST_2},${HOST_3} --conns=100 --clients=1000 \
range YOUR_KEY --consistency=s --total=100000
```
We encourage running the benchmark test when setting up an etcd cluster for the first time in a new environment to ensure the cluster achieves adequate performance; cluster latency and throughput can be sensitive to minor environment differences.
We encourage running the benchmark test when setting up an etcd cluster for the first time in a new environment to ensure the cluster achieves adequate performance; cluster latency and throughput can be sensitive to minor environment differences.

View File

@ -2,23 +2,23 @@
etcd comes with support for incremental runtime reconfiguration, which allows users to update the membership of the cluster at run time.
Reconfiguration requests can only be processed when the majority of the cluster members are functioning. It is **highly recommended** to always have a cluster size greater than two in production. It is unsafe to remove a member from a two member cluster. The majority of a two member cluster is also two. If there is a failure during the removal process, the cluster might not able to make progress and need to [restart from majority failure][majority failure].
Reconfiguration requests can only be processed when a majority of cluster members are functioning. It is **highly recommended** to always have a cluster size greater than two in production. It is unsafe to remove a member from a two member cluster. The majority of a two member cluster is also two. If there is a failure during the removal process, the cluster might not able to make progress and need to [restart from majority failure][majority failure].
To better understand the design behind runtime reconfiguration, we suggest reading [the runtime reconfiguration document][runtime-reconf].
To better understand the design behind runtime reconfiguration, please read [the runtime reconfiguration document][runtime-reconf].
## Reconfiguration use cases
Let's walk through some common reasons for reconfiguring a cluster. Most of these just involve combinations of adding or removing a member, which are explained below under [Cluster Reconfiguration Operations][cluster-reconf].
This section will walk through some common reasons for reconfiguring a cluster. Most of these reasons just involve combinations of adding or removing a member, which are explained below under [Cluster Reconfiguration Operations][cluster-reconf].
### Cycle or upgrade multiple machines
If multiple cluster members need to move due to planned maintenance (hardware upgrades, network downtime, etc.), it is recommended to modify members one at a time.
It is safe to remove the leader, however there is a brief period of downtime while the election process takes place. If the cluster holds more than 50MB, it is recommended to [migrate the member's data directory][member migration].
It is safe to remove the leader, however there is a brief period of downtime while the election process takes place. If the cluster holds more than 50MB of v2 data, it is recommended to [migrate the member's data directory][member migration].
### Change the cluster size
Increasing the cluster size can enhance [failure tolerance][fault tolerance table] and provide better read performance. Since clients can read from any member, increasing the number of members increases the overall read throughput.
Increasing the cluster size can enhance [failure tolerance][fault tolerance table] and provide better read performance. Since clients can read from any member, increasing the number of members increases the overall serialized read throughput.
Decreasing the cluster size can improve the write performance of a cluster, with a trade-off of decreased resilience. Writes into the cluster are replicated to a majority of members of the cluster before considered committed. Decreasing the cluster size lowers the majority, and each write is committed more quickly.
@ -30,42 +30,34 @@ To replace the machine, follow the instructions for [removing the member][remove
### Restart cluster from majority failure
If the majority of the cluster is lost or all of the nodes have changed IP addresses, then manual action is necessary to recover safely.
The basic steps in the recovery process include [creating a new cluster using the old data][disaster recovery], forcing a single member to act as the leader, and finally using runtime configuration to [add new members][add member] to this new cluster one at a time.
If the majority of the cluster is lost or all of the nodes have changed IP addresses, then manual action is necessary to recover safely. The basic steps in the recovery process include [creating a new cluster using the old data][disaster recovery], forcing a single member to act as the leader, and finally using runtime configuration to [add new members][add member] to this new cluster one at a time.
## Cluster reconfiguration operations
Now that we have the use cases in mind, let us lay out the operations involved in each.
With these use cases in mind, the involved operations can be described for each.
Before making any change, the simple majority (quorum) of etcd members must be available.
This is essentially the same requirement as for any other write to etcd.
Before making any change, a simple majority (quorum) of etcd members must be available. This is essentially the same requirement for any kind of write to etcd.
All changes to the cluster are done one at a time:
All changes to the cluster must be done sequentially:
* To update a single member peerURLs, make an update operation
* To replace a single member, make an add then a remove operation
* To increase from 3 to 5 members, make two add operations
* To decrease from 5 to 3, make two remove operations
* To update a single member peerURLs, issue an update operation
* To replace a healthy single member, add a new member then remove the old member
* To increase from 3 to 5 members, issue two add operations
* To decrease from 5 to 3, issue two remove operations
All of these examples will use the `etcdctl` command line tool that ships with etcd.
To change membership without `etcdctl`, use the [v2 HTTP members API][member-api] or the [v3 gRPC members API][member-api-grpc].
All of these examples use the `etcdctl` command line tool that ships with etcd. To change membership without `etcdctl`, use the [v2 HTTP members API][member-api] or the [v3 gRPC members API][member-api-grpc].
### Update a member
#### Update advertise client URLs
To update the advertise client URLs of a member, simply restart
that member with updated client urls flag (`--advertise-client-urls`) or environment variable
(`ETCD_ADVERTISE_CLIENT_URLS`). The restarted member will self publish the updated URLs.
A wrongly updated client URL will not affect the health of the etcd cluster.
To update the advertise client URLs of a member, simply restart that member with updated client urls flag (`--advertise-client-urls`) or environment variable (`ETCD_ADVERTISE_CLIENT_URLS`). The restarted member will self publish the updated URLs. A wrongly updated client URL will not affect the health of the etcd cluster.
#### Update advertise peer URLs
To update the advertise peer URLs of a member, first update
it explicitly via member command and then restart the member. The additional action is required
since updating peer URLs changes the cluster wide configuration and can affect the health of the etcd cluster.
To update the advertise peer URLs of a member, first update it explicitly via member command and then restart the member. The additional action is required since updating peer URLs changes the cluster wide configuration and can affect the health of the etcd cluster.
To update the peer URLs, first, we need to find the target member's ID. To list all members with `etcdctl`:
To update the peer URLs, first find the target member's ID. To list all members with `etcdctl`:
```sh
$ etcdctl member list
@ -74,7 +66,7 @@ $ etcdctl member list
a8266ecf031671f3: name=node1 peerURLs=http://localhost:23801 clientURLs=http://127.0.0.1:23791
```
In this example let's `update` a8266ecf031671f3 member ID and change its peerURLs value to http://10.0.1.10:2380
This example will `update` a8266ecf031671f3 member ID and change its peerURLs value to `http://10.0.1.10:2380`:
```sh
$ etcdctl member update a8266ecf031671f3 http://10.0.1.10:2380
@ -83,8 +75,7 @@ Updated member with ID a8266ecf031671f3 in cluster
### Remove a member
Let us say the member ID we want to remove is a8266ecf031671f3.
We then use the `remove` command to perform the removal:
Suppose the member ID to remove is a8266ecf031671f3. Use the `remove` command to perform the removal:
```sh
$ etcdctl member remove a8266ecf031671f3
@ -106,7 +97,7 @@ Adding a member is a two step process:
* Add the new member to the cluster via the [HTTP members API][member-api], the [gRPC members API][member-api-grpc], or the `etcdctl member add` command.
* Start the new member with the new cluster configuration, including a list of the updated members (existing members + the new member).
Using `etcdctl` let's add the new member to the cluster by specifying its [name][conf-name] and [advertised peer URLs][conf-adv-peer]:
`etcdctl` adds a new member to the cluster by specifying the member's [name][conf-name] and [advertised peer URLs][conf-adv-peer]:
```sh
$ etcdctl member add infra3 http://10.0.1.13:2380
@ -117,8 +108,7 @@ ETCD_INITIAL_CLUSTER="infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,
ETCD_INITIAL_CLUSTER_STATE=existing
```
`etcdctl` has informed the cluster about the new member and printed out the environment variables needed to successfully start it.
Now start the new etcd process with the relevant flags for the new member:
`etcdctl` has informed the cluster about the new member and printed out the environment variables needed to successfully start it. Now start the new etcd process with the relevant flags for the new member:
```sh
$ export ETCD_NAME="infra3"
@ -129,13 +119,11 @@ $ etcd --listen-client-urls http://10.0.1.13:2379 --advertise-client-urls http:/
The new member will run as a part of the cluster and immediately begin catching up with the rest of the cluster.
If adding multiple members the best practice is to configure a single member at a time and verify it starts correctly before adding more new members.
If adding a new member to a 1-node cluster, the cluster cannot make progress before the new member starts because it needs two members as majority to agree on the consensus. This behavior only happens between the time `etcdctl member add` informs the cluster about the new member and the new member successfully establishing a connection to the existing one.
If adding multiple members the best practice is to configure a single member at a time and verify it starts correctly before adding more new members. If adding a new member to a 1-node cluster, the cluster cannot make progress before the new member starts because it needs two members as majority to agree on the consensus. This behavior only happens between the time `etcdctl member add` informs the cluster about the new member and the new member successfully establishing a connection to the existing one.
#### Error cases when adding members
In the following case we have not included our new host in the list of enumerated nodes.
If this is a new cluster, the node must be added to the list of initial cluster members.
In the following case a new host is not included in the list of enumerated nodes. If this is a new cluster, the node must be added to the list of initial cluster members.
```sh
$ etcd --name infra3 \
@ -145,7 +133,7 @@ etcdserver: assign ids error: the member count is unequal
exit 1
```
In this case we give a different address (10.0.1.14:2380) to the one that we used to join the cluster (10.0.1.13:2380).
In this case, give a different address (10.0.1.14:2380) from the one used to join the cluster (10.0.1.13:2380):
```sh
$ etcd --name infra4 \
@ -155,7 +143,7 @@ etcdserver: assign ids error: unmatched member while checking PeerURLs
exit 1
```
When we start etcd using the data directory of a removed member, etcd will exit automatically if it connects to any active member in the cluster:
If etcd starts using the data directory of a removed member, etcd automatically exits if it connects to any active member in the cluster:
```sh
$ etcd

View File

@ -16,7 +16,7 @@ etcd takes several certificate related configuration options, either through com
`--key-file=<path>`: Key for the certificate. Must be unencrypted.
`--client-cert-auth`: When this is set etcd will check all incoming HTTPS requests for a client certificate signed by the trusted CA, requests that don't supply a valid client certificate will fail.
`--client-cert-auth`: When this is set etcd will check all incoming HTTPS requests for a client certificate signed by the trusted CA, requests that don't supply a valid client certificate will fail. If [authentication][auth] is enabled, the certificate provides credentials for the user name given by the Common Name field.
`--trusted-ca-file=<path>`: Trusted certificate authority.
@ -219,6 +219,7 @@ Make sure to sign the certificates with a Subject Name the member's public IP ad
The certificate needs to be signed for the member's FQDN in its Subject Name, use Subject Alternative Names (short IP SANs) to add the IP address. The `etcd-ca` tool provides `--domain=` option for its `new-cert` command, and openssl can make [it][alt-name] too.
[cfssl]: https://github.com/cloudflare/cfssl
[tls-setup]: /hack/tls-setup
[tls-setup]: ../../hack/tls-setup
[tls-guide]: https://github.com/coreos/docs/blob/master/os/generate-self-signed-certificates.md
[alt-name]: http://wiki.cacert.org/FAQ/subjectAltName
[auth]: authentication.md

View File

@ -4,14 +4,15 @@
The following table lists etcd support status for common architectures and operating systems,
| Architecture | Operating System | Status | Maintainers |
| ------------ | ---------------- | ------------ | ---------------- |
| amd64 | Darwin | Experimental | etcd maintainers |
| amd64 | Linux | Stable | etcd maintainers |
| amd64 | Windows | Experimental | |
| arm64 | Linux | Experimental | @glevand |
| arm | Linux | Unstable | |
| 386 | Linux | Unstable | |
| Architecture | Operating System | Status | Maintainers |
| ------------ | ---------------- | ------------ | --------------------------- |
| amd64 | Darwin | Experimental | etcd maintainers |
| amd64 | Linux | Stable | etcd maintainers |
| amd64 | Windows | Experimental | |
| arm64 | Linux | Experimental | @glevand |
| arm | Linux | Unstable | |
| 386 | Linux | Unstable | |
| ppc64le | Linux | Stable | etcd maintainers, @mkumatag |
* etcd-maintainers are listed in https://github.com/coreos/etcd/blob/master/MAINTAINERS.
@ -33,7 +34,7 @@ etcd has known issues on 32-bit systems due to a bug in the Go runtime. See the
To avoid inadvertently running a possibly unstable etcd server, `etcd` on unstable or unsupported architectures will print a warning message and immediately exit if the environment variable `ETCD_UNSUPPORTED_ARCH` is not set to the target architecture.
Currently only the amd64 architecture is officially supported by `etcd`.
Currently amd64 and ppc64le architectures are officially supported by `etcd`.
[go-issue]: https://github.com/golang/go/issues/599
[go-atomic]: https://golang.org/pkg/sync/atomic/#pkg-note-BUG

View File

@ -22,6 +22,12 @@ There are some notable differences between API v2 and API v3:
Application data can be migrated either offline or online. Offline migration is much simpler than online migration and is recommended.
Sometimes an etcd cluster will possibly have v3 data which should not be overwritten. In this case, the migration process may want to confirm no v3 data is committed before proceeding. One way to check the cluster has no v3 keys is to issue the following `etcdctl` command, which scans the entire v3 keyspace for any key, expecting `0` as output:
```sh
ETCDCTL_API=3 etcdctl get "" --from-key --keys-only --limit 1 | wc -l
```
### Offline migration
Offline migration is very simple but requires etcd downtime. If an etcd downtime window spanning from seconds to minutes is acceptable, offline migration is a good choice and is easy to automate.

View File

@ -0,0 +1,77 @@
## Introduction
This guide assumes operational knowledge of Amazon Web Services (AWS), specifically Amazon Elastic Compute Cloud (EC2). This guide provides an introduction to design considerations when designing an etcd deployment on AWS EC2 and how AWS specific features may be utilized in that context.
## Capacity planning
As a critical building block for distributed systems it is crucial to perform adequate capacity planning in order to support the intended cluster workload. As a highly available and strongly consistent data store increasing the number of nodes in an etcd cluster will generally affect performance adversely. This makes sense intuitively, as more nodes means more members for the leader to coordinate state across. The most direct way to increase throughput and decrease latency of an etcd cluster is allocate more disk I/O, network I/O, CPU, and memory to cluster members. In the event it is impossible to temporarily divert incoming requests to the cluster, scaling the EC2 instances which comprise the etcd cluster members one at a time may improve performance. It is, however, best to avoid bottlenecks through capacity planning.
The etcd team has produced a [hardware recommendation guide]( ../op-guide/hardware.md) which is very useful for “ballparking” how many nodes and what instance type are necessary for a cluster.
AWS provides a service for creating groups of EC2 instances which are dynamically sized to match load on the instances. Using an Auto Scaling Group ([ASG](http://docs.aws.amazon.com/autoscaling/latest/userguide/AutoScalingGroup.html)) to dynamically scale an etcd cluster is not recommended for several reasons including:
* etcd performance is generally inversely proportional to the number of members in a cluster due to the synchronous replication which provides strong consistency of data stored in etcd
* the operational complexity of adding [lifecycle hooks](http://docs.aws.amazon.com/autoscaling/latest/userguide/lifecycle-hooks.html) to properly add and remove members from an etcd cluster by modifying the [runtime configuration](../op-guide/runtime-configuration.md)
Auto Scaling Groups do provide a number of benefits besides cluster scaling which include:
* distribution of EC2 instances across Availability Zones (AZs)
* EC2 instance fail over across AZs
* consolidated monitoring and life cycle control of instances within an ASG
The use of an ASG to create a [self healing etcd cluster](#self-healing) is one of the design considerations when deploying an etcd cluster to AWS.
## Cluster design
The purpose of this section is to provide foundational guidance for deploying etcd on AWS. The discussion will be framed by the following three critical design criteria about the etcd cluster itself:
* block device provider: limited to the tradeoffs between EBS or instance storage (InstanceStore)
* cluster topology: how many nodes should make up an etcd cluster; should these nodes be distributed over multiple AZs
* managing etcd members: creating a static cluster of EC2 instances or using an ASG.
The intended cluster workload should dictate the cluster design. A configuration store for microservices may require different design considerations than a distributed lock service, a secrets store, or a Kubernetes control plane. Cluster design tradeoffs include considerations such as:
* availability
* data durability after member failure
* performance/throughput
* self healing
### Availability
Instance availability on AWS is ultimately determined by the Amazon EC2 Region Service Level Agreement ([SLA](https://aws.amazon.com/ec2/sla/)) which is the policy by which Amazon describes their precise definition of a regional outage.
In the context of an etcd cluster this means a cluster must contain a minimum of three members where EC2 instances are spread across at least two AZs in order for an etcd cluster to be considered highly available at a Regional level.
For most use cases the additional latency associated with a cluster spanning across Availability Zones will introduce a negligible performance impact.
Availability considerations apply to all components of an application; if the application which accesses the etcd cluster will only be deployed to a single Availability Zone it may not make sense to make the etcd cluster highly available across zones.
### Data durability after member failure
A highly available etcd cluster is resilient to member loss, however, it is important to consider data durability in the event of disaster when designing an etcd deployment. Deploying etcd on AWS supports multiple mechanisms for data durability.
* replication: etcd replicates all data to all members of the etcd cluster. Therefore, given more members in the cluster and more independent failure domains, the less likely that data stored in an etcd cluster will be permanently lost in the event of disaster.
* Point in time etcd snapshotting: the etcd v3 API introduced support for snapshotting clusters. The operation is cheap enough (completing in the order of minutes) to run quite frequently and the resulting archives can be archived in a storage service like Amazon Simple Storage Service (S3).
* Amazon Elastic Block Storage (EBS): an EBS volume is a replicated network attached block device which have stronger storage safety guarantees than InstanceStore which has a life cycle associated with the life cycle of the attached EC2 instance. The life cycle of an EBS volume is not necessarily tied to an EC2 instance and can be detached and snapshotted independently which means that a single node etcd cluster backed by an EBS volume can provide a fairly reasonable level of data durability.
### Performance/Throughput
The performance of an etcd cluster is roughly quantifiable through latency and throughput metrics which are primarily affected by disk and network performance. Detailed performance planning information is provided in the [performance section](../op-guide/performance.md) of the etcd operations guide.
#### Network
AWS offers EC2 Placement Groups which allow the collocation of EC2 instances within a single Availability Zone which can be utilized in order to minimize network latency between etcd members in the cluster. It is important to remember that collocation of etcd nodes within a single AZ will provide weaker fault tolerance than distributing members across multiple AZs. [Enhanced networking for EC2 instances](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enhanced-networking.html) may also improve network performance of individual EC2 instances.
#### Disk
AWS provides two basic types of block storage: [EBS volumes](https://aws.amazon.com/ebs/) and [EC2 Instance Store](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/InstanceStorage.html). As mentioned, an EBS volume is a network attached block device while instance storage is directly attached to the hypervisor of the EC2 host. EBS volumes will generally have higher latency, lower throughput, and greater performance variance than Instance Store volumes. If performance, rather than data safety, is the primary concern it is highly recommended that instance storage on the EC2 instances be utilized. Remember that the amount of available instance storage varies by EC2 [instance types](https://aws.amazon.com/ec2/instance-types/) which may impose additional performance considerations.
Inconsistent EBS volume performance can introduce etcd cluster instability. [Provisioned IOPS](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSVolumeTypes.html#EBSVolumeTypes_piops) can provide more consistent performance than general purpose SSD EBS volumes. More information about EBS volume performance is available [from AWS](https://aws.amazon.com/ebs/details/) and Datadog has shared their experience with [getting optimal performance with AWS EBS Provisioned IOPS](https://www.datadoghq.com/blog/aws-ebs-provisioned-iops-getting-optimal-performance/) in their engineering blog.
### Self healing
While using an ASG to scale the size of an etcd cluster is not recommended, an ASG can be used effectively to maintain the desired number of nodes in the event of node failure. The maintenance of a stable number of etcd nodes will provide the etcd cluster with a measure of self healing.
### Next steps
The operational life cycle of an etcd cluster can be greatly simplified through the use of the etcd-operator. The open source etcd operator is a Kubernetes control plane operator which deploys and manages etcd clusters atop Kubernetes. While still in its early stages the etcd-operator already offers periodic backups to S3, detection and replacement of failed nodes, and automated disaster recovery from backups in the event of permanent quorum loss.

View File

@ -0,0 +1,203 @@
# Run etcd on Container Linux with systemd
The following guide shows how to run etcd with [systemd][systemd-docs] under [Container Linux][container-linux-docs].
## Provisioning an etcd cluster
Cluster bootstrapping in Container Linux is simplest with [Ignition][container-linux-ignition]; `coreos-metadata.service` dynamically fetches the machine's IP for discovery. Note that etcd's discovery service protocol is only meant for bootstrapping, and cannot be used with runtime reconfiguration or cluster monitoring.
The [Container Linux Config Transpiler][container-linux-ct] compiles etcd configuration files into Ignition configuration files:
```yaml container-linux-config:norender
etcd:
version: 3.2.0
name: s1
data_dir: /var/lib/etcd
advertise_client_urls: http://{PUBLIC_IPV4}:2379
initial_advertise_peer_urls: http://{PRIVATE_IPV4}:2380
listen_client_urls: http://0.0.0.0:2379
listen_peer_urls: http://{PRIVATE_IPV4}:2380
discovery: https://discovery.etcd.io/<token>
```
`ct` would produce the following Ignition Config:
```
$ ct --platform=gce --in-file /tmp/ct-etcd.cnf
{"ignition":{"version":"2.0.0","config"...
```
```json ignition-config
{
"ignition":{"version":"2.0.0","config":{}},
"storage":{},
"systemd":{
"units":[{
"name":"etcd-member.service",
"enable":true,
"dropins":[{
"name":"20-clct-etcd-member.conf",
"contents":"[Unit]\nRequires=coreos-metadata.service\nAfter=coreos-metadata.service\n\n[Service]\nEnvironmentFile=/run/metadata/coreos\nEnvironment=\"ETCD_IMAGE_TAG=v3.1.8\"\nExecStart=\nExecStart=/usr/lib/coreos/etcd-wrapper $ETCD_OPTS \\\n --name=\"s1\" \\\n --data-dir=\"/var/lib/etcd\" \\\n --listen-peer-urls=\"http://${COREOS_GCE_IP_LOCAL_0}:2380\" \\\n --listen-client-urls=\"http://0.0.0.0:2379\" \\\n --initial-advertise-peer-urls=\"http://${COREOS_GCE_IP_LOCAL_0}:2380\" \\\n --advertise-client-urls=\"http://${COREOS_GCE_IP_EXTERNAL_0}:2379\" \\\n --discovery=\"https://discovery.etcd.io/\u003ctoken\u003e\""}]}]},
"networkd":{},
"passwd":{}}
```
To avoid accidental misconfiguration, the transpiler helpfully verifies etcd configurations when generating Ignition files:
```yaml container-linux-config:norender
etcd:
version: 3.2.0
name: s1
data_dir_x: /var/lib/etcd
advertise_client_urls: http://{PUBLIC_IPV4}:2379
initial_advertise_peer_urls: http://{PRIVATE_IPV4}:2380
listen_client_urls: http://0.0.0.0:2379
listen_peer_urls: http://{PRIVATE_IPV4}:2380
discovery: https://discovery.etcd.io/<token>
```
```
$ ct --platform=gce --in-file /tmp/ct-etcd.cnf
warning at line 3, column 2
Config has unrecognized key: data_dir_x
```
See [Container Linux Provisioning][container-linux-provision] for more details.
## etcd 3.x service
[Container Linux][container-linux-docs] does not include etcd 3.x binaries by default. Different versions of etcd 3.x can be fetched via `etcd-member.service`.
Confirm unit file exists:
```
systemctl cat etcd-member.service
```
Check if the etcd service is running:
```
systemctl status etcd-member.service
```
Example systemd drop-in unit to override the default service settings:
```bash
cat > /tmp/20-cl-etcd-member.conf <<EOF
[Service]
Environment="ETCD_IMAGE_TAG=v3.2.0"
Environment="ETCD_DATA_DIR=/var/lib/etcd"
Environment="ETCD_SSL_DIR=/etc/ssl/certs"
Environment="ETCD_OPTS=--name s1 \
--listen-client-urls https://10.240.0.1:2379 \
--advertise-client-urls https://10.240.0.1:2379 \
--listen-peer-urls https://10.240.0.1:2380 \
--initial-advertise-peer-urls https://10.240.0.1:2380 \
--initial-cluster s1=https://10.240.0.1:2380,s2=https://10.240.0.2:2380,s3=https://10.240.0.3:2380 \
--initial-cluster-token mytoken \
--initial-cluster-state new \
--client-cert-auth \
--trusted-ca-file /etc/ssl/certs/etcd-root-ca.pem \
--cert-file /etc/ssl/certs/s1.pem \
--key-file /etc/ssl/certs/s1-key.pem \
--peer-client-cert-auth \
--peer-trusted-ca-file /etc/ssl/certs/etcd-root-ca.pem \
--peer-cert-file /etc/ssl/certs/s1.pem \
--peer-key-file /etc/ssl/certs/s1-key.pem \
--auto-compaction-retention 1"
EOF
mv /tmp/20-cl-etcd-member.conf /etc/systemd/system/etcd-member.service.d/20-cl-etcd-member.conf
```
Or use a Container Linux Config:
```yaml container-linux-config:norender
systemd:
units:
- name: etcd-member.service
dropins:
- name: conf1.conf
contents: |
[Service]
Environment="ETCD_SSL_DIR=/etc/ssl/certs"
etcd:
version: 3.2.0
name: s1
data_dir: /var/lib/etcd
listen_client_urls: https://0.0.0.0:2379
advertise_client_urls: https://{PUBLIC_IPV4}:2379
listen_peer_urls: https://{PRIVATE_IPV4}:2380
initial_advertise_peer_urls: https://{PRIVATE_IPV4}:2380
initial_cluster: s1=https://{PRIVATE_IPV4}:2380,s2=https://10.240.0.2:2380,s3=https://10.240.0.3:2380
initial_cluster_token: mytoken
initial_cluster_state: new
client_cert_auth: true
trusted_ca_file: /etc/ssl/certs/etcd-root-ca.pem
cert-file: /etc/ssl/certs/s1.pem
key-file: /etc/ssl/certs/s1-key.pem
peer-client-cert-auth: true
peer-trusted-ca-file: /etc/ssl/certs/etcd-root-ca.pem
peer-cert-file: /etc/ssl/certs/s1.pem
peer-key-file: /etc/ssl/certs/s1-key.pem
auto-compaction-retention: 1
```
```
$ ct --platform=gce --in-file /tmp/ct-etcd.cnf
{"ignition":{"version":"2.0.0","config"...
```
To see all runtime drop-in changes for system units:
```
systemd-delta --type=extended
```
To enable and start:
```
systemctl daemon-reload
systemctl enable --now etcd-member.service
```
To see the logs:
```
journalctl --unit etcd-member.service --lines 10
```
To stop and disable the service:
```
systemctl disable --now etcd-member.service
```
## etcd 2.x service
[Container Linux][container-linux-docs] includes a unit file `etcd2.service` for etcd 2.x, which will be removed in the near future. See [Container Linux FAQ][container-linux-faq] for more details.
Confirm unit file is installed:
```
systemctl cat etcd2.service
```
Check if the etcd service is running:
```
systemctl status etcd2.service
```
To stop and disable:
```
systemctl disable --now etcd2.service
```
[systemd-docs]: https://github.com/systemd/systemd
[container-linux-docs]: https://coreos.com/os/docs/latest
[container-linux-faq]: https://github.com/coreos/docs/blob/master/etcd/os-faq.md
[container-linux-provision]: https://github.com/coreos/docs/blob/master/os/provisioning.md
[container-linux-ignition]: https://github.com/coreos/docs/blob/master/ignition/what-is-ignition.md
[container-linux-ct]: https://github.com/coreos/container-linux-config-transpiler

View File

@ -1,23 +1,18 @@
# FreeBSD
Starting with version 0.1.2 both etcd and etcdctl have been ported to FreeBSD and can
be installed either via packages or ports system. Their versions have been recently
updated to 0.2.0 so now you can enjoy using etcd and etcdctl on FreeBSD 10.0 (RC4 as
of now) and 9.x where they have been tested. They might also work when installed from
ports on earlier versions of FreeBSD, but your mileage may vary.
Starting with version 0.1.2 both etcd and etcdctl have been ported to FreeBSD and can be installed either via packages or ports system. Their versions have been recently updated to 0.2.0 so now etcd and etcdctl can be enjoyed on FreeBSD 10.0 (RC4 as of now) and 9.x, where they have been tested. They might also work when installed from ports on earlier versions of FreeBSD, but it is untested; caveat emptor.
## Installation
### Using pkgng package system
1. If you do not have pkg­ng installed, install it with command `pkg` and answering 'Y'
when asked
1. If pkg­ng is not installed, install it with command `pkg` and answering 'Y' when asked.
2. Update your repository data with `pkg update`
2. Update the repository data with `pkg update`.
3. Install etcd with `pkg install coreos-etcd coreos-etcdctl`
3. Install etcd with `pkg install coreos-etcd coreos-etcdctl`.
4. Verify successful installation with `pkg info | grep etcd` and you should get:
4. Verify successful installation by confirming `pkg info | grep etcd` matches:
```
r@fbsd­10:/ # pkg info | grep etcd
@ -26,21 +21,17 @@ coreos­etcdctl­0.2.0           Simple commandline client for et
r@fbsd­10:/ #
```
5. Youre ready to use etcd and etcdctl! For more information about using pkgng, please
see: http://www.freebsd.org/doc/handbook/pkgng­intro.html
5. etcd and etcdctl are ready to use! For more information about using pkgng, please see: http://www.freebsd.org/doc/handbook/pkgng­intro.html
 
### Using ports system
1. If you do not have ports installed, install with with `portsnap fetch extract` (it
may take some time depending on your hardware and network connection)
1. If ports is not installed, install with `portsnap fetch extract` (it may take some time depending on hardware and network connection).
2. Build etcd with `cd /usr/ports/devel/etcd && make install clean`, you
will get an option to build and install documentation and etcdctl with it.
2. Build etcd with `cd /usr/ports/devel/etcd && make install clean`. There will be an option to build and install documentation and etcdctl with it.
3. If you haven't installed it with etcdctl, and you would like to install it later, you can build it
with `cd /usr/ports/devel/etcdctl && make install clean`
3. If etcd wasn't installed with etcdctl, it can be built later with `cd /usr/ports/devel/etcdctl && make install clean`.
4. Verify successful installation with `pkg info | grep etcd` and you should get:
4. Verify successful installation by confirming `pkg info | grep etcd` matches:
 
```
@ -50,13 +41,8 @@ coreos­etcdctl­0.2.0           Simple commandline client for et
r@fbsd­10:/ #
```
5. Youre ready to use etcd and etcdctl! For more information about using ports system,
please see: https://www.freebsd.org/doc/handbook/ports­using.html
5. etcd and etcdctl are ready to use! For more information about using ports system, please see: https://www.freebsd.org/doc/handbook/ports­using.html
## Issues
If you find any issues with the build/install procedure or you've found a problem that
you've verified is local to FreeBSD version only (for example, by not being able to
reproduce it on any other platform, like OSX or Linux), please sent a
problem report using this page for more
information: http://www.freebsd.org/send­pr.html
If there are any issues with the build/install procedure or there's a problem that is local to FreeBSD only (for example, by not being able to reproduce it on any other platform, like OSX or Linux), please send a problem report using this page for more information: http://www.freebsd.org/send­pr.html

View File

@ -2,6 +2,15 @@
This document tracks people and use cases for etcd in production. By creating a list of production use cases we hope to build a community of advisors that we can reach out to with experience using various etcd applications, operation environments, and cluster sizes. The etcd development team may reach out periodically to check-in on how etcd is working in the field and update this list.
## All Kubernetes Users
- *Application*: https://kubernetes.io/
- *Environments*: AWS, OpenStack, Azure, Google Cloud, Huawei Cloud, Bare Metal, etc
**This is a meta user; please feel free to document specific Kubernetes clusters!**
All Kubernetes clusters use etcd as their primary data store. This means etcd's users include such companies as [Niantic, Inc Pokemon Go](https://cloudplatform.googleblog.com/2016/09/bringing-Pokemon-GO-to-life-on-Google-Cloud.html), [Box](https://blog.box.com/blog/kubernetes-box-microservices-maximum-velocity/), [CoreOS](https://coreos.com/tectonic), [Ticketmaster](https://www.youtube.com/watch?v=wqXVKneP0Hg), [Salesforce](https://www.salesforce.com) and many many more.
## discovery.etcd.io
- *Application*: https://github.com/coreos/discovery.etcd.io
@ -50,7 +59,7 @@ Radius Intelligence uses Kubernetes running CoreOS to containerize and scale int
## Vonage
- *Application*: system configuration for microservices, scheduling, locks (future - service discovery)
- *Application*: kubernetes, vault backend, system configuration for microservices, scheduling, locks (future - service discovery)
- *Launched*: August 2015
- *Cluster Size*: 2 clusters of 5 members in 2 DCs, n local proxies 1-to-1 with microservice, (ssl and SRV look up)
- *Order of Data Size*: kilobytes
@ -58,5 +67,173 @@ Radius Intelligence uses Kubernetes running CoreOS to containerize and scale int
- *Environment*: VMWare, AWS
- *Backups*: Daily snapshots on VMs. Backups done for upgrades.
## PD
- *Application*: embed etcd
- *Launched*: Mar 2016
- *Cluster Size*: 3 or 5 members
- *Order of Data Size*: megabytes
- *Operator*: PingCAP, Inc.
- *Environment*: Bare Metal, AWS, etc.
- *Backups*: None.
PD(Placement Driver) is the central controller in the TiDB cluster. It saves the cluster meta information, schedule the data, allocate the global unique timestamp for the distributed transaction, etc. It embeds etcd to supply high availability and auto failover.
## Canal
- *Application*: system configuration for overlay network
- *Launched*: June 2016
- *Cluster Size*: 3 members for each cluster
- *Order of Data Size*: kilobytes
- *Operator*: Huawei Euler Department
- *Environment*: [Huawei Cloud](http://www.hwclouds.com/product/cce.html)
- *Backups*: None, all data can be recreated if necessary.
[teamcity]: https://www.jetbrains.com/teamcity/
[raoofm]:https://github.com/raoofm
## Qiniu Cloud
- *Application*: system configuration for microservices, distributed locks
- *Launched*: Jan. 2016
- *Cluster Size*: 3 members each with several clusters
- *Order of Data Size*: kilobytes
- *Operator*: Pandora, chenchao@qiniu.com
- *Environment*: Baremetal
- *Backups*: None, all data can be recreated if necessary
## QingCloud
- *Application*: [QingCloud][qingcloud] appcenter cluster for service discovery as [metad][metad] backend.
- *Launched*: December 2016
- *Cluster Size*: 1 cluster of 3 members per user.
- *Order of Data Size*: kilobytes
- *Operator*: [yunify][yunify]
- *Environment*: QingCloud IaaS
- *Backups*: None, all data can be recreated if necessary.
[metad]:https://github.com/yunify/metad
[yunify]:https://github.com/yunify
[qingcloud]:https://qingcloud.com/
## Yandex
- *Application*: system configuration for services, service discovery
- *Launched*: March 2016
- *Cluster Size*: 3 clusters of 5 members
- *Order of Data Size*: several gigabytes
- *Operator*: Yandex; [nekto0n][nekto0n]
- *Environment*: Bare Metal
- *Backups*: None
[nekto0n]:https://github.com/nekto0n
## Tencent Games
- *Application*: Meta data and configuration data for service discovery, Kubernetes, etc.
- *Launched*: Jan. 2015
- *Cluster Size*: 3 members each with 10s of clusters
- *Order of Data Size*: 10s of Megabytes
- *Operator*: Tencent Game Operations Department
- *Environment*: Baremetal
- *Backups*: Periodic sync to backup server
In Tencent games, we use Docker and Kubernetes to deploy and run our applications, and use etcd to save meta data for service discovery, Kubernetes, etc.
## Hyper.sh
- *Application*: Kubernetes, distributed locks, etc.
- *Launched*: April 2016
- *Cluster Size*: 1 cluster of 3 members
- *Order of Data Size*: 10s of MB
- *Operator*: Hyper.sh
- *Environment*: Baremetal
- *Backups*: None, all data can be recreated if necessary.
In [hyper.sh][hyper.sh], the container service is backed by [hypernetes][hypernetes], a multi-tenant kubernetes distro. Moreover, we use etcd to coordinate the multiple manage services and store global meta data.
[hypernetes]:https://github.com/hyperhq/hypernetes
[Hyper.sh]:https://www.hyper.sh
## Meitu
- *Application*: system configuration for services, service discovery, kubernetes in test environment
- *Launched*: October 2015
- *Cluster Size*: 1 cluster of 3 members
- *Order of Data Size*: megabytes
- *Operator*: Meitu, hxj@meitu.com, [shafreeck][shafreeck]
- *Environment*: Bare Metal
- *Backups*: None, all data can be recreated if necessary.
[shafreeck]:https://github.com/shafreeck
## Grab
- *Application*: system configuration for services, service discovery
- *Launched*: June 2016
- *Cluster Size*: 1 cluster of 7 members
- *Order of Data Size*: megabytes
- *Operator*: Grab, [taxitan][taxitan], [reterVision][reterVision]
- *Environment*: AWS
- *Backups*: None, all data can be recreated if necessary.
[taxitan]:https://github.com/taxitan
[reterVision]:https://github.com/reterVision
## DaoCloud.io
- *Application*: container management
- *Launched*: Sep. 2015
- *Cluster Size*: 1000+ deployments, each deployment contains a 3 node cluster.
- *Order of Data Size*: 100s of Megabytes
- *Operator*: daocloud.io
- *Environment*: Baremetal and virtual machines
- *Backups*: None, all data can be recreated if necessary.
In [DaoCloud][DaoCloud], we use Docker and Swarm to deploy and run our applications, and we use etcd to save metadata for service discovery.
[DaoCloud]:https://www.daocloud.io
## Branch.io
- *Application*: Kubernetes
- *Launched*: April 2016
- *Cluster Size*: Multiple clusters, multiple sizes
- *Order of Data Size*: 100s of Megabytes
- *Operator*: branch.io
- *Environment*: AWS, Kubernetes
- *Backups*: EBS volume backups
At [Branch][branch], we use kubernetes heavily as our core microservice platform for staging and production.
[branch]: https://branch.io
## Baidu Waimai
- *Application*: SkyDNS, Kubernetes, UDC, CMDB and other distributed systems
- *Launched*: April. 2016
- *Cluster Size*: 3 clusters of 5 members
- *Order of Data Size*: several gigabytes
- *Operator*: Baidu Waimai Operations Department
- *Environment*: CentOS 6.5
- *Backups*: backup scripts
## Salesforce.com
- *Application*: Kubernetes
- *Launched*: Jan 2017
- *Cluster Size*: Multiple clusters of 3 members
- *Order of Data Size*: 100s of Megabytes
- *Operator*: Salesforce.com (krmayankk@github)
- *Environment*: BareMetal
- *Backups*: None, all data can be recreated
## Hosted Graphite
- *Application*: Service discovery, locking, ephemeral application data
- *Launched*: January 2017
- *Cluster Size*: 2 clusters of 7 members
- *Order of Data Size*: Megabytes
- *Operator*: Hosted Graphite (sre@hostedgraphite.com)
- *Environment*: Bare Metal
- *Backups*: None, all data is considered ephemeral.

View File

@ -1,6 +1,6 @@
# Reporting bugs
If any part of the etcd project has bugs or documentation mistakes, please let us know by [opening an issue][issue]. We treat bugs and mistakes very seriously and believe no issue is too small. Before creating a bug report, please check that an issue reporting the same problem does not already exist.
If any part of the etcd project has bugs or documentation mistakes, please let us know by [opening an issue][etcd-issue]. We treat bugs and mistakes very seriously and believe no issue is too small. Before creating a bug report, please check that an issue reporting the same problem does not already exist.
To make the bug report accurate and easy to understand, please try to create bug reports that are:

View File

@ -6,33 +6,16 @@ The network isn't the only source of latency. Each request and response may be i
## Time parameters
The underlying distributed consensus protocol relies on two separate time parameters to ensure that nodes can handoff leadership if one stalls or goes offline.
The first parameter is called the *Heartbeat Interval*.
This is the frequency with which the leader will notify followers that it is still the leader.
For best practices, the parameter should be set around round-trip time between members.
By default, etcd uses a `100ms` heartbeat interval.
The underlying distributed consensus protocol relies on two separate time parameters to ensure that nodes can handoff leadership if one stalls or goes offline. The first parameter is called the *Heartbeat Interval*. This is the frequency with which the leader will notify followers that it is still the leader.
For best practices, the parameter should be set around round-trip time between members. By default, etcd uses a `100ms` heartbeat interval.
The second parameter is the *Election Timeout*.
This timeout is how long a follower node will go without hearing a heartbeat before attempting to become leader itself.
By default, etcd uses a `1000ms` election timeout.
The second parameter is the *Election Timeout*. This timeout is how long a follower node will go without hearing a heartbeat before attempting to become leader itself. By default, etcd uses a `1000ms` election timeout.
Adjusting these values is a trade off.
The value of heartbeat interval is recommended to be around the maximum of average round-trip time (RTT) between members, normally around 0.5-1.5x the round-trip time.
If heartbeat interval is too low, etcd will send unnecessary messages that increase the usage of CPU and network resources.
On the other side, a too high heartbeat interval leads to high election timeout. Higher election timeout takes longer time to detect a leader failure.
The easiest way to measure round-trip time (RTT) is to use [PING utility][ping].
Adjusting these values is a trade off. The value of heartbeat interval is recommended to be around the maximum of average round-trip time (RTT) between members, normally around 0.5-1.5x the round-trip time. If heartbeat interval is too low, etcd will send unnecessary messages that increase the usage of CPU and network resources. On the other side, a too high heartbeat interval leads to high election timeout. Higher election timeout takes longer time to detect a leader failure. The easiest way to measure round-trip time (RTT) is to use [PING utility][ping].
The election timeout should be set based on the heartbeat interval and average round-trip time between members.
Election timeouts must be at least 10 times the round-trip time so it can account for variance in the network.
For example, if the round-trip time between members is 10ms then the election timeout should be at least 100ms.
The election timeout should be set based on the heartbeat interval and average round-trip time between members. Election timeouts must be at least 10 times the round-trip time so it can account for variance in the network. For example, if the round-trip time between members is 10ms then the election timeout should be at least 100ms.
The election timeout should be set to at least 5 to 10 times the heartbeat interval to account for variance in leader replication.
For a heartbeat interval of 50ms, set the election timeout to at least 250ms - 500ms.
The upper limit of election timeout is 50000ms (50s), which should only be used when deploying a globally-distributed etcd cluster.
A reasonable round-trip time for the continental United States is 130ms, and the time between US and Japan is around 350-400ms.
If the network has uneven performance or regular packet delays/loss then it is possible that a couple of retries may be necessary to successfully send a packet. So 5s is a safe upper limit of global round-trip time.
As the election timeout should be an order of magnitude bigger than broadcast time, in the case of ~5s for a globally distributed cluster, then 50 seconds becomes a reasonable maximum.
The upper limit of election timeout is 50000ms (50s), which should only be used when deploying a globally-distributed etcd cluster. A reasonable round-trip time for the continental United States is 130ms, and the time between US and Japan is around 350-400ms. If the network has uneven performance or regular packet delays/loss then it is possible that a couple of retries may be necessary to successfully send a packet. So 5s is a safe upper limit of global round-trip time. As the election timeout should be an order of magnitude bigger than broadcast time, in the case of ~5s for a globally distributed cluster, then 50 seconds becomes a reasonable maximum.
The heartbeat interval and election timeout value should be the same for all members in one cluster. Setting different values for etcd members may disrupt cluster stability.
@ -50,18 +33,13 @@ The values are specified in milliseconds.
## Snapshots
etcd appends all key changes to a log file.
This log grows forever and is a complete linear history of every change made to the keys.
A complete history works well for lightly used clusters but clusters that are heavily used would carry around a large log.
etcd appends all key changes to a log file. This log grows forever and is a complete linear history of every change made to the keys. A complete history works well for lightly used clusters but clusters that are heavily used would carry around a large log.
To avoid having a huge log etcd makes periodic snapshots.
These snapshots provide a way for etcd to compact the log by saving the current state of the system and removing old logs.
To avoid having a huge log etcd makes periodic snapshots. These snapshots provide a way for etcd to compact the log by saving the current state of the system and removing old logs.
### Snapshot tuning
Creating snapshots can be expensive so they're only created after a given number of changes to etcd.
By default, snapshots will be made after every 10,000 changes.
If etcd's memory usage and disk usage are too high, try lowering the snapshot threshold by setting the following on the command line:
Creating snapshots with the V2 backend can be expensive, so snapshots are only created after a given number of changes to etcd. By default, snapshots will be made after every 10,000 changes. If etcd's memory usage and disk usage are too high, try lowering the snapshot threshold by setting the following on the command line:
```sh
# Command line arguments:
@ -71,6 +49,17 @@ $ etcd --snapshot-count=5000
$ ETCD_SNAPSHOT_COUNT=5000 etcd
```
## Disk
An etcd cluster is very sensitive to disk latencies. Since etcd must persist proposals to its log, disk activity from other processes may cause long `fsync` latencies. The upshot is etcd may miss heartbeats, causing request timeouts and temporary leader loss. An etcd server can sometimes stably run alongside these processes when given a high disk priority.
On Linux, etcd's disk priority can be configured with `ionice`:
```sh
# best effort, highest priority
$ sudo ionice -c2 -n0 -p `pgrep etcd`
```
## Network
If the etcd leader serves a large number of concurrent client requests, it may delay processing follower peer requests due to network congestion. This manifests as send buffer error messages on the follower nodes:

View File

@ -6,27 +6,27 @@ In the general case, upgrading from etcd 2.3 to 3.0 can be a zero-downtime, roll
Before [starting an upgrade](#upgrade-procedure), read through the rest of this guide to prepare.
### Upgrade Checklists
### Upgrade checklists
#### Upgrade Requirements
#### Upgrade requirements
To upgrade an existing etcd deployment to 3.0, the running cluster must be 2.3 or greater. If it's before 2.3, please upgrade to [2.3](https://github.com/coreos/etcd/releases/tag/v2.3.0) before upgrading to 3.0.
Also, to ensure a smooth rolling upgrade, the running cluster must be healthy. You can check the health of the cluster by using the `etcdctl cluster-health` command.
Also, to ensure a smooth rolling upgrade, the running cluster must be healthy. Check the health of the cluster by using the `etcdctl cluster-health` command before proceeding.
#### Preparation
Before upgrading etcd, always test the services relying on etcd in a staging environment before deploying the upgrade to the production environment.
Before beginning, [backup the etcd data directory](../v2/admin_guide.md#backing-up-the-datastore). Should something go wrong with the upgrade, it is possible to use this backup to [downgrade](#downgrade) back to existing etcd version.
Before beginning, [backup the etcd data directory](../v2/admin_guide.md#backing-up-the-datastore). Should something go wrong with the upgrade, it is possible to use this backup to [downgrade](#downgrade) back to existing etcd version.
#### Mixed Versions
#### Mixed versions
While upgrading, an etcd cluster supports mixed versions of etcd members, and operates with the protocol of the lowest common version. The cluster is only considered upgraded once all of its members are upgraded to version 3.0. Internally, etcd members negotiate with each other to determine the overall cluster version, which controls the reported version and the supported features.
#### Limitations
It might take up to 2 minutes for the newly upgraded member to catch up with the existing cluster when the total data size is larger than 50MB. Check the size of a recent snapshot to estimate the total data size. In other words, it is safest to wait for 2 minutes between upgrading each member.
It might take up to 2 minutes for the newly upgraded member to catch up with the existing cluster when the total data size is larger than 50MB. Check the size of a recent snapshot to estimate the total data size. In other words, it is safest to wait for 2 minutes between upgrading each member.
For a much larger total data size, 100MB or more , this one-time process might take even more time. Administrators of very large etcd clusters of this magnitude can feel free to contact the [etcd team][etcd-contact] before upgrading, and well be happy to provide advice on the procedure.
@ -36,13 +36,13 @@ If all members have been upgraded to v3.0, the cluster will be upgraded to v3.0,
Please [backup the data directory](../v2/admin_guide.md#backing-up-the-datastore) of all etcd members to make downgrading the cluster possible even after it has been completely upgraded.
### Upgrade Procedure
### Upgrade procedure
This example details the upgrade of a three-member v2.3 ectd cluster running on a local machine.
This example details the upgrade of a three-member v2.3 ectd cluster running on a local machine.
#### 1. Check upgrade requirements.
Is the the cluster healthy and running v.2.3.x?
Is the cluster healthy and running v.2.3.x?
```
$ etcdctl cluster-health
@ -64,7 +64,7 @@ When each etcd process is stopped, expected errors will be logged by other clust
2016-06-27 15:21:48.624175 I | rafthttp: the connection with 8211f1d0f64f3269 became inactive
```
Its a good idea at this point to [backup the etcd data directory](../v2/admin_guide.md#backing-up-the-datastore) to provide a downgrade path should any problems occur:
Its a good idea at this point to [backup the etcd data directory](../v2/admin_guide.md#backing-up-the-datastore) to provide a downgrade path should any problems occur:
```
$ etcdctl backup \
@ -102,7 +102,7 @@ Upgraded members will log warnings like the following until the entire cluster i
#### 5. Finish
When all members are upgraded, the cluster will report upgrading to 3.0 successfully:
When all members are upgraded, the cluster will report upgrading to 3.0 successfully:
```
2016-06-27 15:22:19.873751 N | membership: updated the cluster version from 2.3 to 3.0
@ -116,4 +116,14 @@ $ ETCDCTL_API=3 etcdctl endpoint health
127.0.0.1:22379 is healthy: successfully committed proposal: took = 18.513301ms
```
## Further considerations
- etcdctl environment variables have been updated. If `ETCDCTL_API=2 etcdctl cluster-health` works properly but `ETCDCTL_API=3 etcdctl endpoints health` responds with `Error: grpc: timed out when dialing`, be sure to use the [new variable names](https://github.com/coreos/etcd/tree/master/etcdctl#etcdctl).
## Known Issues
- etcd &lt; v3.1 does not work properly if built with Go &gt; v1.7. See [Issue 6951](https://github.com/coreos/etcd/issues/6951) for additional information.
- If an error such as `transport: http2Client.notifyError got notified that the client transport was broken unexpected EOF.` shows up in the etcd server logs, be sure etcd is a pre-built release or built with (etcd v3.1+ &amp; go v1.7+) or (etcd &lt;v3.1 &amp; go v1.6.x).
- Adding a v3 node to v2.3 cluster during upgrades is not supported and could trigger panics. See [Issue 7249](https://github.com/coreos/etcd/issues/7429) for additional information. Mixed versions of etcd members are only allowed during v3 migration. Finish upgrades before making any membership changes.
[etcd-contact]: https://groups.google.com/forum/#!forum/etcd-dev

View File

@ -0,0 +1,123 @@
## Upgrade etcd from 3.0 to 3.1
In the general case, upgrading from etcd 3.0 to 3.1 can be a zero-downtime, rolling upgrade:
- one by one, stop the etcd v3.0 processes and replace them with etcd v3.1 processes
- after running all v3.1 processes, new features in v3.1 are available to the cluster
Before [starting an upgrade](#upgrade-procedure), read through the rest of this guide to prepare.
### Upgrade checklists
#### Upgrade requirements
To upgrade an existing etcd deployment to 3.1, the running cluster must be 3.0 or greater. If it's before 3.0, please upgrade to [3.0](https://github.com/coreos/etcd/releases/tag/v3.0.16) before upgrading to 3.1.
Also, to ensure a smooth rolling upgrade, the running cluster must be healthy. Check the health of the cluster by using the `etcdctl endpoint health` command before proceeding.
#### Preparation
Before upgrading etcd, always test the services relying on etcd in a staging environment before deploying the upgrade to the production environment.
Before beginning, [backup the etcd data](../op-guide/maintenance.md#snapshot-backup). Should something go wrong with the upgrade, it is possible to use this backup to [downgrade](#downgrade) back to existing etcd version. Please note that the `snapshot` command only backs up the v3 data. For v2 data, see [backing up v2 datastore](../v2/admin_guide.md#backing-up-the-datastore).
#### Mixed versions
While upgrading, an etcd cluster supports mixed versions of etcd members, and operates with the protocol of the lowest common version. The cluster is only considered upgraded once all of its members are upgraded to version 3.1. Internally, etcd members negotiate with each other to determine the overall cluster version, which controls the reported version and the supported features.
#### Limitations
Note: If the cluster only has v3 data and no v2 data, it is not subject to this limitation.
If the cluster is serving a v2 data set larger than 50MB, each newly upgraded member may take up to two minutes to catch up with the existing cluster. Check the size of a recent snapshot to estimate the total data size. In other words, it is safest to wait for 2 minutes between upgrading each member.
For a much larger total data size, 100MB or more , this one-time process might take even more time. Administrators of very large etcd clusters of this magnitude can feel free to contact the [etcd team][etcd-contact] before upgrading, and we'll be happy to provide advice on the procedure.
#### Downgrade
If all members have been upgraded to v3.1, the cluster will be upgraded to v3.1, and downgrade from this completed state is **not possible**. If any single member is still v3.0, however, the cluster and its operations remains "v3.0", and it is possible from this mixed cluster state to return to using a v3.0 etcd binary on all members.
Please [backup the data directory](../op-guide/maintenance.md#snapshot-backup) of all etcd members to make downgrading the cluster possible even after it has been completely upgraded.
### Upgrade procedure
This example shows how to upgrade a 3-member v3.0 ectd cluster running on a local machine.
#### 1. Check upgrade requirements
Is the cluster healthy and running v3.0.x?
```
$ ETCDCTL_API=3 etcdctl endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379
localhost:2379 is healthy: successfully committed proposal: took = 6.600684ms
localhost:22379 is healthy: successfully committed proposal: took = 8.540064ms
localhost:32379 is healthy: successfully committed proposal: took = 8.763432ms
$ curl http://localhost:2379/version
{"etcdserver":"3.0.16","etcdcluster":"3.0.0"}
```
#### 2. Stop the existing etcd process
When each etcd process is stopped, expected errors will be logged by other cluster members. This is normal since a cluster member connection has been (temporarily) broken:
```
2017-01-17 09:34:18.352662 I | raft: raft.node: 1640829d9eea5cfb elected leader 1640829d9eea5cfb at term 5
2017-01-17 09:34:18.359630 W | etcdserver: failed to reach the peerURL(http://localhost:2380) of member fd32987dcd0511e0 (Get http://localhost:2380/version: dial tcp 127.0.0.1:2380: getsockopt: connection refused)
2017-01-17 09:34:18.359679 W | etcdserver: cannot get the version of member fd32987dcd0511e0 (Get http://localhost:2380/version: dial tcp 127.0.0.1:2380: getsockopt: connection refused)
2017-01-17 09:34:18.548116 W | rafthttp: lost the TCP streaming connection with peer fd32987dcd0511e0 (stream Message writer)
2017-01-17 09:34:19.147816 W | rafthttp: lost the TCP streaming connection with peer fd32987dcd0511e0 (stream MsgApp v2 writer)
2017-01-17 09:34:34.364907 W | etcdserver: failed to reach the peerURL(http://localhost:2380) of member fd32987dcd0511e0 (Get http://localhost:2380/version: dial tcp 127.0.0.1:2380: getsockopt: connection refused)
```
It's a good idea at this point to [backup the etcd data](../op-guide/maintenance.md#snapshot-backup) to provide a downgrade path should any problems occur:
```
$ etcdctl snapshot save backup.db
```
#### 3. Drop-in etcd v3.1 binary and start the new etcd process
The new v3.1 etcd will publish its information to the cluster:
```
2017-01-17 09:36:00.996590 I | etcdserver: published {Name:my-etcd-1 ClientURLs:[http://localhost:2379]} to cluster 46bc3ce73049e678
```
Verify that each member, and then the entire cluster, becomes healthy with the new v3.1 etcd binary:
```
$ ETCDCTL_API=3 /etcdctl endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379
localhost:22379 is healthy: successfully committed proposal: took = 5.540129ms
localhost:32379 is healthy: successfully committed proposal: took = 7.321671ms
localhost:2379 is healthy: successfully committed proposal: took = 10.629901ms
```
Upgraded members will log warnings like the following until the entire cluster is upgraded. This is expected and will cease after all etcd cluster members are upgraded to v3.1:
```
2017-01-17 09:36:38.406268 W | etcdserver: the local etcd version 3.0.16 is not up-to-date
2017-01-17 09:36:38.406295 W | etcdserver: member fd32987dcd0511e0 has a higher version 3.1.0
2017-01-17 09:36:42.407695 W | etcdserver: the local etcd version 3.0.16 is not up-to-date
2017-01-17 09:36:42.407730 W | etcdserver: member fd32987dcd0511e0 has a higher version 3.1.0
```
#### 4. Repeat step 2 to step 3 for all other members
#### 5. Finish
When all members are upgraded, the cluster will report upgrading to 3.1 successfully:
```
2017-01-17 09:37:03.100015 I | etcdserver: updating the cluster version from 3.0 to 3.1
2017-01-17 09:37:03.104263 N | etcdserver/membership: updated the cluster version from 3.0 to 3.1
2017-01-17 09:37:03.104374 I | etcdserver/api: enabled capabilities for version 3.1
```
```
$ ETCDCTL_API=3 /etcdctl endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379
localhost:2379 is healthy: successfully committed proposal: took = 2.312897ms
localhost:22379 is healthy: successfully committed proposal: took = 2.553476ms
localhost:32379 is healthy: successfully committed proposal: took = 2.516902ms
```
[etcd-contact]: https://groups.google.com/forum/#!forum/etcd-dev

View File

@ -0,0 +1,172 @@
## Upgrade etcd from 3.1 to 3.2
In the general case, upgrading from etcd 3.1 to 3.2 can be a zero-downtime, rolling upgrade:
- one by one, stop the etcd v3.1 processes and replace them with etcd v3.2 processes
- after running all v3.2 processes, new features in v3.2 are available to the cluster
Before [starting an upgrade](#upgrade-procedure), read through the rest of this guide to prepare.
### Client upgrade checklists
3.2 introduces two breaking changes.
Previously, `clientv3.Lease.TimeToLive` API returned `lease.ErrLeaseNotFound` on non-existent lease ID. 3.2 instead returns TTL=-1 in its response and no error (see [#7305](https://github.com/coreos/etcd/pull/7305)).
Before
```go
// when leaseID does not exist
resp, err := TimeToLive(ctx, leaseID)
resp == nil
err == lease.ErrLeaseNotFound
```
After
```go
// when leaseID does not exist
resp, err := TimeToLive(ctx, leaseID)
resp.TTL == -1
err == nil
```
`clientv3.NewFromConfigFile` is moved to `yaml.NewConfig`.
Before
```go
import "github.com/coreos/etcd/clientv3"
clientv3.NewFromConfigFile
```
After
```go
import clientv3yaml "github.com/coreos/etcd/clientv3/yaml"
clientv3yaml.NewConfig
```
### Server upgrade checklists
#### Upgrade requirements
To upgrade an existing etcd deployment to 3.2, the running cluster must be 3.1 or greater. If it's before 3.1, please upgrade to [3.1](https://github.com/coreos/etcd/releases/tag/v3.1.7) before upgrading to 3.2.
Also, to ensure a smooth rolling upgrade, the running cluster must be healthy. Check the health of the cluster by using the `etcdctl endpoint health` command before proceeding.
#### Preparation
Before upgrading etcd, always test the services relying on etcd in a staging environment before deploying the upgrade to the production environment.
Before beginning, [backup the etcd data](../op-guide/maintenance.md#snapshot-backup). Should something go wrong with the upgrade, it is possible to use this backup to [downgrade](#downgrade) back to existing etcd version. Please note that the `snapshot` command only backs up the v3 data. For v2 data, see [backing up v2 datastore](../v2/admin_guide.md#backing-up-the-datastore).
#### Mixed versions
While upgrading, an etcd cluster supports mixed versions of etcd members, and operates with the protocol of the lowest common version. The cluster is only considered upgraded once all of its members are upgraded to version 3.2. Internally, etcd members negotiate with each other to determine the overall cluster version, which controls the reported version and the supported features.
#### Limitations
Note: If the cluster only has v3 data and no v2 data, it is not subject to this limitation.
If the cluster is serving a v2 data set larger than 50MB, each newly upgraded member may take up to two minutes to catch up with the existing cluster. Check the size of a recent snapshot to estimate the total data size. In other words, it is safest to wait for 2 minutes between upgrading each member.
For a much larger total data size, 100MB or more , this one-time process might take even more time. Administrators of very large etcd clusters of this magnitude can feel free to contact the [etcd team][etcd-contact] before upgrading, and we'll be happy to provide advice on the procedure.
#### Downgrade
If all members have been upgraded to v3.2, the cluster will be upgraded to v3.2, and downgrade from this completed state is **not possible**. If any single member is still v3.1, however, the cluster and its operations remains "v3.1", and it is possible from this mixed cluster state to return to using a v3.1 etcd binary on all members.
Please [backup the data directory](../op-guide/maintenance.md#snapshot-backup) of all etcd members to make downgrading the cluster possible even after it has been completely upgraded.
### Upgrade procedure
This example shows how to upgrade a 3-member v3.1 ectd cluster running on a local machine.
#### 1. Check upgrade requirements
Is the cluster healthy and running v3.1.x?
```
$ ETCDCTL_API=3 etcdctl endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379
localhost:2379 is healthy: successfully committed proposal: took = 6.600684ms
localhost:22379 is healthy: successfully committed proposal: took = 8.540064ms
localhost:32379 is healthy: successfully committed proposal: took = 8.763432ms
$ curl http://localhost:2379/version
{"etcdserver":"3.1.7","etcdcluster":"3.1.0"}
```
#### 2. Stop the existing etcd process
When each etcd process is stopped, expected errors will be logged by other cluster members. This is normal since a cluster member connection has been (temporarily) broken:
```
2017-04-27 14:13:31.491746 I | raft: c89feb932daef420 [term 3] received MsgTimeoutNow from 6d4f535bae3ab960 and starts an election to get leadership.
2017-04-27 14:13:31.491769 I | raft: c89feb932daef420 became candidate at term 4
2017-04-27 14:13:31.491788 I | raft: c89feb932daef420 received MsgVoteResp from c89feb932daef420 at term 4
2017-04-27 14:13:31.491797 I | raft: c89feb932daef420 [logterm: 3, index: 9] sent MsgVote request to 6d4f535bae3ab960 at term 4
2017-04-27 14:13:31.491805 I | raft: c89feb932daef420 [logterm: 3, index: 9] sent MsgVote request to 9eda174c7df8a033 at term 4
2017-04-27 14:13:31.491815 I | raft: raft.node: c89feb932daef420 lost leader 6d4f535bae3ab960 at term 4
2017-04-27 14:13:31.524084 I | raft: c89feb932daef420 received MsgVoteResp from 6d4f535bae3ab960 at term 4
2017-04-27 14:13:31.524108 I | raft: c89feb932daef420 [quorum:2] has received 2 MsgVoteResp votes and 0 vote rejections
2017-04-27 14:13:31.524123 I | raft: c89feb932daef420 became leader at term 4
2017-04-27 14:13:31.524136 I | raft: raft.node: c89feb932daef420 elected leader c89feb932daef420 at term 4
2017-04-27 14:13:31.592650 W | rafthttp: lost the TCP streaming connection with peer 6d4f535bae3ab960 (stream MsgApp v2 reader)
2017-04-27 14:13:31.592825 W | rafthttp: lost the TCP streaming connection with peer 6d4f535bae3ab960 (stream Message reader)
2017-04-27 14:13:31.693275 E | rafthttp: failed to dial 6d4f535bae3ab960 on stream Message (dial tcp [::1]:2380: getsockopt: connection refused)
2017-04-27 14:13:31.693289 I | rafthttp: peer 6d4f535bae3ab960 became inactive
2017-04-27 14:13:31.936678 W | rafthttp: lost the TCP streaming connection with peer 6d4f535bae3ab960 (stream Message writer)
```
It's a good idea at this point to [backup the etcd data](../op-guide/maintenance.md#snapshot-backup) to provide a downgrade path should any problems occur:
```
$ etcdctl snapshot save backup.db
```
#### 3. Drop-in etcd v3.2 binary and start the new etcd process
The new v3.2 etcd will publish its information to the cluster:
```
2017-04-27 14:14:25.363225 I | etcdserver: published {Name:s1 ClientURLs:[http://localhost:2379]} to cluster a9ededbffcb1b1f1
```
Verify that each member, and then the entire cluster, becomes healthy with the new v3.2 etcd binary:
```
$ ETCDCTL_API=3 /etcdctl endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379
localhost:22379 is healthy: successfully committed proposal: took = 5.540129ms
localhost:32379 is healthy: successfully committed proposal: took = 7.321771ms
localhost:2379 is healthy: successfully committed proposal: took = 10.629901ms
```
Upgraded members will log warnings like the following until the entire cluster is upgraded. This is expected and will cease after all etcd cluster members are upgraded to v3.2:
```
2017-04-27 14:15:17.071804 W | etcdserver: member c89feb932daef420 has a higher version 3.2.0
2017-04-27 14:15:21.073110 W | etcdserver: the local etcd version 3.1.7 is not up-to-date
2017-04-27 14:15:21.073142 W | etcdserver: member 6d4f535bae3ab960 has a higher version 3.2.0
2017-04-27 14:15:21.073157 W | etcdserver: the local etcd version 3.1.7 is not up-to-date
2017-04-27 14:15:21.073164 W | etcdserver: member c89feb932daef420 has a higher version 3.2.0
```
#### 4. Repeat step 2 to step 3 for all other members
#### 5. Finish
When all members are upgraded, the cluster will report upgrading to 3.2 successfully:
```
2017-04-27 14:15:54.536901 N | etcdserver/membership: updated the cluster version from 3.1 to 3.2
2017-04-27 14:15:54.537035 I | etcdserver/api: enabled capabilities for version 3.2
```
```
$ ETCDCTL_API=3 /etcdctl endpoint health --endpoints=localhost:2379,localhost:22379,localhost:32379
localhost:2379 is healthy: successfully committed proposal: took = 2.312897ms
localhost:22379 is healthy: successfully committed proposal: took = 2.553476ms
localhost:32379 is healthy: successfully committed proposal: took = 2.517902ms
```
[etcd-contact]: https://groups.google.com/forum/#!forum/etcd-dev

View File

@ -67,13 +67,13 @@ You have successfully started an etcd and written a key to the store.
The [official etcd ports][iana-ports] are 2379 for client requests, and 2380 for peer communication. To maintain compatibility, some etcd configuration and documentation continues to refer to the legacy ports 4001 and 7001, but all new etcd use and discussion should adopt the IANA-assigned ports. The legacy ports 4001 and 7001 will be fully deprecated, and support for their use removed, in future etcd releases.
[iana-ports]: https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=etcd
[iana-ports]: http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.txt
### Running local etcd cluster
First install [goreman](https://github.com/mattn/goreman), which manages Procfile-based applications.
Our [Procfile script](./Procfile) will set up a local example cluster. You can start it with:
Our [Procfile script](../../V2Procfile) will set up a local example cluster. You can start it with:
```sh
goreman start
@ -162,4 +162,4 @@ Currently only the amd64 architecture is officially supported by `etcd`.
### License
etcd is under the Apache 2.0 license. See the [LICENSE](LICENSE) file for details.
etcd is under the Apache 2.0 license. See the [LICENSE](../../LICENSE) file for details.

View File

@ -18,7 +18,7 @@ A keys lifetime spans a generation. Each key may have one or multiple generat
### Physical View
etcd stores the physical data as key-value pairs in a persistent [b+tree][b+tree]. Each revision of the stores state only contains the delta from its previous revision to be efficient. A single revision may correspond to multiple keys in the tree.
etcd stores the physical data as key-value pairs in a persistent [b+tree][b+tree]. Each revision of the stores state only contains the delta from its previous revision to be efficient. A single revision may correspond to multiple keys in the tree.
The key of key-value pair is a 3-tuple (major, sub, type). Major is the store revision holding the key. Sub differentiates among keys within the same revision. Type is an optional suffix for special value (e.g., `t` if the value contains a tombstone). The value of the key-value pair contains the modification from previous revision, thus one delta from previous revision. The b+tree is ordered by key in lexical byte-order. Ranged lookups over revision deltas are fast; this enables quickly finding modifications from one specific revision to another. Compaction removes out-of-date keys-value pairs.
@ -47,7 +47,7 @@ An etcd operation is considered complete when it is committed through consensus,
#### revision
An etcd operation that modifies the key value store is assigned with a single increasing revision. A transaction operation might modifies the key value store multiple times, but only one revision is assigned. The revision attribute of a key value pair that modified by the operation has the same value as the revision of the operation. The revision can be used as a logical clock for key value store. A key value pair that has a larger revision is modified after a key value pair with a smaller revision. Two key value pairs that have the same revision are modified by an operation "concurrently".
An etcd operation that modifies the key value store is assigned with a single increasing revision. A transaction operation might modify the key value store multiple times, but only one revision is assigned. The revision attribute of a key value pair that modified by the operation has the same value as the revision of the operation. The revision can be used as a logical clock for key value store. A key value pair that has a larger revision is modified after a key value pair with a smaller revision. Two key value pairs that have the same revision are modified by an operation "concurrently".
### Guarantees Provided
@ -73,7 +73,7 @@ Any completed operations are durable. All accessible data is also durable data.
#### Linearizability
Linearizability (also known as Atomic Consistency or External Consistency) is a consistency level between strict consistency and sequential consistency.
Linearizability (also known as Atomic Consistency or External Consistency) is a consistency level between strict consistency and sequential consistency.
For linearizability, suppose each operation receives a timestamp from a loosely synchronized global clock. Operations are linearized if and only if they always complete as though they were executed in a sequential order and each operation appears to complete in the order specified by the program. Likewise, if an operations timestamp precedes another, that operation must also precede the other operation in the sequence.
@ -83,10 +83,10 @@ etcd does not ensure linearizability for watch operations. Users are expected to
etcd ensures linearizability for all other operations by default. Linearizability comes with a cost, however, because linearized requests must go through the Raft consensus process. To obtain lower latencies and higher throughput for read requests, clients can configure a requests consistency mode to `serializable`, which may access stale data with respect to quorum, but removes the performance penalty of linearized accesses' reliance on live consensus.
[persistent-ds]: [https://en.wikipedia.org/wiki/Persistent_data_structure]
[btree]: [https://en.wikipedia.org/wiki/B-tree]
[b+tree]: [https://en.wikipedia.org/wiki/B%2B_tree]
[seq_consistency]: [https://en.wikipedia.org/wiki/Consistency_model#Sequential_consistency]
[strict_consistency]: [https://en.wikipedia.org/wiki/Consistency_model#Strict_consistency]
[serializable_isolation]: [https://en.wikipedia.org/wiki/Isolation_(database_systems)#Serializable]
[Linearizability]: [#Linearizability]
[persistent-ds]: https://en.wikipedia.org/wiki/Persistent_data_structure
[btree]: https://en.wikipedia.org/wiki/B-tree
[b+tree]: https://en.wikipedia.org/wiki/B%2B_tree
[seq_consistency]: https://en.wikipedia.org/wiki/Consistency_model#Sequential_consistency
[strict_consistency]: https://en.wikipedia.org/wiki/Consistency_model#Strict_consistency
[serializable_isolation]: https://en.wikipedia.org/wiki/Isolation_(database_systems)#Serializable
[Linearizability]: #linearizability

View File

@ -32,7 +32,7 @@ The consistent flag for read operations is removed in etcd 2.0.0. The normal rea
The read consistency guarantees are:
The consistent read guarantees the sequential consistency within one client that talks to one etcd server. Read/Write from one client to one etcd member should be observed in order. If one client write a value to an etcd server successfully, it should be able to get the value out of the server immediately.
The consistent read guarantees the sequential consistency within one client that talks to one etcd server. Read/Write from one client to one etcd member should be observed in order. If one client write a value to an etcd server successfully, it should be able to get the value out of the server immediately.
Each etcd member will proxy the request to leader and only return the result to user after the result is applied on the local member. Thus after the write succeed, the user is guaranteed to see the value on the member it sent the request to.
@ -56,6 +56,7 @@ Proxy mode in 2.0 will provide similar functionality, and with improved control
## Discovery Service
A size key needs to be provided inside a [discovery token][discoverytoken].
[discoverytoken]: clustering.md#custom-etcd-discovery-service
## HTTP Admin API

View File

@ -49,4 +49,4 @@ Bootstrap another machine and use the [boom HTTP benchmark tool][boom] to send r
| 256 | 256 | all servers | 3061 | 119.3 |
[boom]: https://github.com/rakyll/boom
[hack-benchmark]: /hack/benchmark/
[hack-benchmark]: ../../../hack/benchmark/

View File

@ -24,7 +24,7 @@ Go OS/Arch: linux/amd64
## Testing
Bootstrap another machine, outside of the etcd cluster, and run the [`boom` HTTP benchmark tool](https://github.com/rakyll/boom) with a connection reuse patch to send requests to each etcd cluster member. See the [benchmark instructions](../../hack/benchmark/) for the patch and the steps to reproduce our procedures.
Bootstrap another machine, outside of the etcd cluster, and run the [`boom` HTTP benchmark tool][boom] with a connection reuse patch to send requests to each etcd cluster member. See the [benchmark instructions][hack] for the patch and the steps to reproduce our procedures.
The performance is calulated through results of 100 benchmark rounds.
@ -66,4 +66,7 @@ The performance is calulated through results of 100 benchmark rounds.
- Write QPS to cluster leaders seems to be increased by a small margin. This is because the main loop and entry apply loops were decoupled in the etcd raft logic, eliminating several blocks between them.
- Write QPS to all members seems to be increased by a significant margin, because followers now receive the latest commit index sooner, and commit proposals more quickly.
- Write QPS to all members seems to be increased by a significant margin, because followers now receive the latest commit index sooner, and commit proposals more quickly.
[boom]: https://github.com/rakyll/boom
[hack]: ../../../hack/benchmark/

View File

@ -69,4 +69,4 @@ Bootstrap another machine and use the [boom HTTP benchmark tool][boom] to send r
[boom]: https://github.com/rakyll/boom
[c7146bd5]: https://github.com/coreos/etcd/commits/c7146bd5f2c73716091262edc638401bb8229144
[etcd-2.1-benchmark]: etcd-2-1-0-alpha-benchmarks.md
[hack-benchmark]: /hack/benchmark/
[hack-benchmark]: ../../../hack/benchmark/

View File

@ -39,4 +39,4 @@ The performance is nearly the same as the one with empty server handler.
The performance with empty server handler is not affected by one put. So the
performance downgrade should be caused by storage package.
[etcd-v3-benchmark]: /tools/benchmark/
[etcd-v3-benchmark]: ../../../tools/benchmark/

View File

@ -423,7 +423,7 @@ To make understanding this feature easier, we changed the naming of some flags,
|-peers |none |Deprecated. The --initial-cluster flag provides a similar concept with different semantics. Please read this guide on cluster startup.|
|-peers-file |none |Deprecated. The --initial-cluster flag provides a similar concept with different semantics. Please read this guide on cluster startup.|
[client]: /client
[client]: ../../client
[client-discoverer]: https://godoc.org/github.com/coreos/etcd/client#Discoverer
[conf-adv-client]: configuration.md#-advertise-client-urls
[conf-listen-client]: configuration.md#-listen-client-urls

View File

@ -176,7 +176,10 @@ To start etcd automatically using custom settings at startup in Linux, using a [
The security flags help to [build a secure etcd cluster][security].
### --ca-file [DEPRECATED]
### --ca-file
**DEPRECATED**
+ Path to the client server TLS CA file. `--ca-file ca.crt` could be replaced by `--trusted-ca-file ca.crt --client-cert-auth` and etcd will perform the same.
+ default: none
+ env variable: ETCD_CA_FILE
@ -201,7 +204,10 @@ The security flags help to [build a secure etcd cluster][security].
+ default: none
+ env variable: ETCD_TRUSTED_CA_FILE
### --peer-ca-file [DEPRECATED]
### --peer-ca-file
**DEPRECATED**
+ Path to the peer server TLS CA file. `--peer-ca-file ca.crt` could be replaced by `--peer-trusted-ca-file ca.crt --peer-client-cert-auth` and etcd will perform the same.
+ default: none
+ env variable: ETCD_PEER_CA_FILE
@ -234,7 +240,7 @@ The security flags help to [build a secure etcd cluster][security].
+ env variable: ETCD_DEBUG
### --log-package-levels
+ Set individual etcd subpackages to specific log levels. An example being `etcdserver=WARNING,security=DEBUG`
+ Set individual etcd subpackages to specific log levels. An example being `etcdserver=WARNING,security=DEBUG`
+ default: none (INFO for all packages)
+ env variable: ETCD_LOG_PACKAGE_LEVELS
@ -272,7 +278,7 @@ Follow the instructions when using these flags.
[build-cluster]: clustering.md#static
[reconfig]: runtime-configuration.md
[discovery]: clustering.md#discovery
[iana-ports]: https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=etcd
[iana-ports]: http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.txt
[proxy]: proxy.md
[reconfig]: runtime-configuration.md
[restore]: admin_guide.md#restoring-a-backup

View File

@ -70,7 +70,7 @@ cd release
# personal GPG is okay for now
for i in etcd-*{.zip,.tar.gz}; do gpg --sign ${i}; done
# use `CoreOS ACI Builder <release@coreos.com>` secret key
gpg -u 88182190 -a --output etcd-${VERSION}-linux-amd64.aci.asc --detach-sig etcd-${VERSION}-linux-amd64.aci
for aci in etcd-${VERSION}.*.aci; do gpg -u 88182190 -a --output ${aci}.asc --detach-sig ${aci}; done
```
## Publish Release Page in GitHub
@ -88,6 +88,7 @@ gpg -u 88182190 -a --output etcd-${VERSION}-linux-amd64.aci.asc --detach-sig etc
```
docker login quay.io
docker push quay.io/coreos/etcd:${VERSION}
docker push quay.io/coreos/etcd:${VERSION}-${arch}
```
- Add `latest` tag to the new image on [quay.io](https://quay.io/repository/coreos/etcd?tag=latest&tab=tags) if this is a stable release.

View File

@ -16,7 +16,7 @@ This will run the latest release version of etcd. You can specify version if nee
```
docker run -d -v /usr/share/ca-certificates/:/etc/ssl/certs -p 4001:4001 -p 2380:2380 -p 2379:2379 \
--name etcd quay.io/coreos/etcd \
--name etcd quay.io/coreos/etcd:v2.3.8 \
-name etcd0 \
-advertise-client-urls http://${HostIP}:2379,http://${HostIP}:4001 \
-listen-client-urls http://0.0.0.0:2379,http://0.0.0.0:4001 \
@ -42,11 +42,13 @@ etcdctl -C http://192.168.12.50:4001 member list
Using Docker to setup a multi-node cluster is very similar to the standalone mode configuration.
The main difference being the value used for the `-initial-cluster` flag, which must contain the peer urls for each etcd member in the cluster.
**Although the following commands look very similar, note that `-name`, `-advertise-client-urls` and `-initial-advertise-peer-urls` differ for each cluster member**
### etcd0
```
docker run -d -v /usr/share/ca-certificates/:/etc/ssl/certs -p 4001:4001 -p 2380:2380 -p 2379:2379 \
--name etcd quay.io/coreos/etcd \
--name etcd quay.io/coreos/etcd:v2.3.8 \
-name etcd0 \
-advertise-client-urls http://192.168.12.50:2379,http://192.168.12.50:4001 \
-listen-client-urls http://0.0.0.0:2379,http://0.0.0.0:4001 \
@ -61,7 +63,7 @@ docker run -d -v /usr/share/ca-certificates/:/etc/ssl/certs -p 4001:4001 -p 2380
```
docker run -d -v /usr/share/ca-certificates/:/etc/ssl/certs -p 4001:4001 -p 2380:2380 -p 2379:2379 \
--name etcd quay.io/coreos/etcd \
--name etcd quay.io/coreos/etcd:v2.3.8 \
-name etcd1 \
-advertise-client-urls http://192.168.12.51:2379,http://192.168.12.51:4001 \
-listen-client-urls http://0.0.0.0:2379,http://0.0.0.0:4001 \
@ -76,7 +78,7 @@ docker run -d -v /usr/share/ca-certificates/:/etc/ssl/certs -p 4001:4001 -p 2380
```
docker run -d -v /usr/share/ca-certificates/:/etc/ssl/certs -p 4001:4001 -p 2380:2380 -p 2379:2379 \
--name etcd quay.io/coreos/etcd \
--name etcd quay.io/coreos/etcd:v2.3.8 \
-name etcd2 \
-advertise-client-urls http://192.168.12.52:2379,http://192.168.12.52:4001 \
-listen-client-urls http://0.0.0.0:2379,http://0.0.0.0:4001 \

View File

@ -0,0 +1,121 @@
### General cluster availability ###
# alert if another failed member will result in an unavailable cluster
ALERT InsufficientMembers
IF count(up{job="etcd"} == 0) > (count(up{job="etcd"}) / 2 - 1)
FOR 3m
LABELS {
severity = "critical"
}
ANNOTATIONS {
summary = "etcd cluster insufficient members",
description = "If one more etcd member goes down the cluster will be unavailable",
}
### HTTP requests alerts ###
# alert if more than 1% of requests to an HTTP endpoint have failed with a non 4xx response
ALERT HighNumberOfFailedHTTPRequests
IF sum by(method) (rate(etcd_http_failed_total{job="etcd", code!~"4[0-9]{2}"}[5m]))
/ sum by(method) (rate(etcd_http_received_total{job="etcd"}[5m])) > 0.01
FOR 10m
LABELS {
severity = "warning"
}
ANNOTATIONS {
summary = "a high number of HTTP requests are failing",
description = "{{ $value }}% of requests for {{ $labels.method }} failed on etcd instance {{ $labels.instance }}",
}
# alert if more than 5% of requests to an HTTP endpoint have failed with a non 4xx response
ALERT HighNumberOfFailedHTTPRequests
IF sum by(method) (rate(etcd_http_failed_total{job="etcd", code!~"4[0-9]{2}"}[5m]))
/ sum by(method) (rate(etcd_http_received_total{job="etcd"}[5m])) > 0.05
FOR 5m
LABELS {
severity = "critical"
}
ANNOTATIONS {
summary = "a high number of HTTP requests are failing",
description = "{{ $value }}% of requests for {{ $labels.method }} failed on etcd instance {{ $labels.instance }}",
}
# alert if 50% of requests get a 4xx response
ALERT HighNumberOfFailedHTTPRequests
IF sum by(method) (rate(etcd_http_failed_total{job="etcd", code=~"4[0-9]{2}"}[5m]))
/ sum by(method) (rate(etcd_http_received_total{job="etcd"}[5m])) > 0.5
FOR 10m
LABELS {
severity = "critical"
}
ANNOTATIONS {
summary = "a high number of HTTP requests are failing",
description = "{{ $value }}% of requests for {{ $labels.method }} failed with 4xx responses on etcd instance {{ $labels.instance }}",
}
# alert if the 99th percentile of HTTP requests take more than 150ms
ALERT HTTPRequestsSlow
IF histogram_quantile(0.99, rate(etcd_http_successful_duration_second_bucket[5m])) > 0.15
FOR 10m
LABELS {
severity = "warning"
}
ANNOTATIONS {
summary = "slow HTTP requests",
description = "on etcd instance {{ $labels.instance }} HTTP requests to {{ $label.method }} are slow",
}
### File descriptor alerts ###
instance:fd_utilization = process_open_fds / process_max_fds
# alert if file descriptors are likely to exhaust within the next 4 hours
ALERT FdExhaustionClose
IF predict_linear(instance:fd_utilization[1h], 3600 * 4) > 1
FOR 10m
LABELS {
severity = "warning"
}
ANNOTATIONS {
summary = "file descriptors soon exhausted",
description = "{{ $labels.job }} instance {{ $labels.instance }} will exhaust its file descriptors soon",
}
# alert if file descriptors are likely to exhaust within the next hour
ALERT FdExhaustionClose
IF predict_linear(instance:fd_utilization[10m], 3600) > 1
FOR 10m
LABELS {
severity = "critical"
}
ANNOTATIONS {
summary = "file descriptors soon exhausted",
description = "{{ $labels.job }} instance {{ $labels.instance }} will exhaust its file descriptors soon",
}
### etcd proposal alerts ###
# alert if there are several failed proposals within an hour
ALERT HighNumberOfFailedProposals
IF increase(etcd_server_proposal_failed_total{job="etcd"}[1h]) > 5
LABELS {
severity = "warning"
}
ANNOTATIONS {
summary = "a high number of proposals within the etcd cluster are failing",
description = "etcd instance {{ $labels.instance }} has seen {{ $value }} proposal failures within the last hour",
}
### etcd disk io latency alerts ###
# alert if 99th percentile of fsync durations is higher than 500ms
ALERT HighFsyncDurations
IF histogram_quantile(0.99, rate(etcd_wal_fsync_durations_seconds_bucket[5m])) > 0.5
FOR 10m
LABELS {
severity = "warning"
}
ANNOTATIONS {
summary = "high fsync durations",
description = "etcd instance {{ $labels.instance }} fync durations are high",
}

View File

@ -53,8 +53,11 @@
- [shafreeck/cetcd](https://github.com/shafreeck/cetcd) - Supports v2
**C++ libraries**
- [edwardcapriolo/etcdcpp](https://github.com/edwardcapriolo/etcdcpp) - Supports v2
- [suryanathan/etcdcpp](https://github.com/suryanathan/etcdcpp) - Supports v2 (with waits)
- [nokia/etcd-cpp-api](https://github.com/nokia/etcd-cpp-api) - Supports v2
- [nokia/etcd-cpp-apiv3](https://github.com/nokia/etcd-cpp-apiv3)
**Clojure libraries**
@ -112,7 +115,6 @@
- [mattn/etcdenv](https://github.com/mattn/etcdenv) - "env" shebang with etcd integration
- [kelseyhightower/confd](https://github.com/kelseyhightower/confd) - Manage local app config files using templates and data from etcd
- [configdb](https://git.autistici.org/ai/configdb/tree/master) - A REST relational abstraction on top of arbitrary database backends, aimed at storing configs and inventories.
- [scrz](https://github.com/scrz/scrz) - Container manager, stores configuration in etcd.
- [fleet](https://github.com/coreos/fleet) - Distributed init system
- [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes) - Container cluster manager introduced by Google.
- [mailgun/vulcand](https://github.com/mailgun/vulcand) - HTTP proxy that uses etcd as a configuration backend.

View File

@ -108,7 +108,7 @@ ETCD_INITIAL_CLUSTER_STATE=existing
Stop the existing proxy so we can wipe its state on disk and reload it with the new configuration:
``` bash
px aux | grep etcd
ps aux | grep etcd
kill %etcd_proxy_pid%
```

View File

@ -1,6 +1,6 @@
# Reporting Bugs
If you find bugs or documentation mistakes in the etcd project, please let us know by [opening an issue][issue]. We treat bugs and mistakes very seriously and believe no issue is too small. Before creating a bug report, please check that an issue reporting the same problem does not already exist.
If you find bugs or documentation mistakes in the etcd project, please let us know by [opening an issue][etcd-issue]. We treat bugs and mistakes very seriously and believe no issue is too small. Before creating a bug report, please check that an issue reporting the same problem does not already exist.
To make your bug report accurate and easy to understand, please try to create bug reports that are:

View File

@ -7,25 +7,25 @@ To prove out the design of the v3 API the team has also built [a number of examp
# Design
1. Flatten binary key-value space
2. Keep the event history until compaction
- access to old version of keys
- user controlled history compaction
3. Support range query
- Pagination support with limit argument
- Support consistency guarantee across multiple range queries
4. Replace TTL key with Lease
- more efficient/ low cost keep alive
- a logical group of TTL keys
5. Replace CAS/CAD with multi-object Txn
- MUCH MORE powerful and flexible
6. Support efficient watching with multiple ranges
7. RPC API supports the completed set of APIs.
7. RPC API supports the completed set of APIs.
- more efficient than JSON/HTTP
- additional txn/lease support
@ -56,7 +56,7 @@ the size in the future a little bit or make it configurable.
// A put is always successful
Put( PutRequest { key = foo, value = bar } )
PutResponse {
PutResponse {
cluster_id = 0x1000,
member_id = 0x1,
revision = 1,
@ -119,7 +119,7 @@ RangeResponse {
Txn(TxnRequest {
// mod_revision of foo0 is equal to 1, mod_revision of foo1 is greater than 1
compare = {
{compareType = equal, key = foo0, mod_revision = 1},
{compareType = equal, key = foo0, mod_revision = 1},
{compareType = greater, key = foo1, mod_revision = 1}}
},
// if the comparison succeeds, put foo2 = bar2
@ -156,7 +156,7 @@ Watch( WatchRequest{
end_revision = 10000,
// server decided notification frequency
progress_notification = true,
}
}
… // this can be a watch request stream
)
@ -176,7 +176,7 @@ WatchResponse {
},
}
// a notification at 2000
WatchResponse {
cluster_id = 0x1000,
@ -185,9 +185,9 @@ WatchResponse {
raft_term = 0x1,
// nil event as notification
}
// put (foo0=bar3000) event at 3000
WatchResponse {
cluster_id = 0x1000,
@ -204,8 +204,8 @@ WatchResponse {
},
}
```
[api-protobuf]: https://github.com/coreos/etcd/blob/master/etcdserver/etcdserverpb/rpc.proto
[kv-protobuf]: https://github.com/coreos/etcd/blob/master/storage/storagepb/kv.proto
[api-protobuf]: https://github.com/coreos/etcd/blob/release-2.3/etcdserver/etcdserverpb/rpc.proto
[kv-protobuf]: https://github.com/coreos/etcd/blob/release-2.3/storage/storagepb/kv.proto

View File

@ -16,7 +16,7 @@ etcd takes several certificate related configuration options, either through com
`--key-file=<path>`: Key for the certificate. Must be unencrypted.
`--client-cert-auth`: When this is set etcd will check all incoming HTTPS requests for a client certificate signed by the trusted CA, requests that don't supply a valid client certificate will fail.
`--client-cert-auth`: When this is set etcd will check all incoming HTTPS requests for a client certificate signed by the trusted CA, requests that don't supply a valid client certificate will fail. If [authentication][auth] is enabled, the certificate provides credentials for the user name given by the Common Name field.
`--trusted-ca-file=<path>`: Trusted certificate authority.
@ -188,6 +188,7 @@ Make sure that you sign your certificates with a Subject Name your member's publ
If you need your certificate to be signed for your member's FQDN in its Subject Name then you could use Subject Alternative Names (short IP SANs) to add your IP address. The `etcd-ca` tool provides `--domain=` option for its `new-cert` command, and openssl can make [it][alt-name] too.
[cfssl]: https://github.com/cloudflare/cfssl
[tls-setup]: /hack/tls-setup
[tls-setup]: ../../hack/tls-setup
[tls-guide]: https://github.com/coreos/docs/blob/master/os/generate-self-signed-certificates.md
[alt-name]: http://wiki.cacert.org/FAQ/subjectAltName
[auth]: authentication.md

View File

@ -1,5 +1,6 @@
Anthony Romano <anthony.romano@coreos.com> (@heyitsanthony) pkg:*
Brandon Philips <brandon.philips@coreos.com> (@philips) pkg:*
Fanmin Shi <fanmin.shi@coreos.com> (@fanminshi) pkg:*
Gyu-Ho Lee <gyu_ho.lee@coreos.com> (@gyuho) pkg:*
Xiang Li <xiang.li@coreos.com> (@xiang90) pkg:*

27
NEWS
View File

@ -1,4 +1,29 @@
etcd v3.1.0 (2017-01-13)
etcd v3.1.6 (2017-04-19)
- remove auth check in Status API
- fill in Auth API response header
etcd v3.1.5 (2017-03-27)
- add '/etc/nsswitch.conf' file to alpine-based Docker image
- fix raft memory leak issue
- fix Windows file path issues
etcd v3.1.4 (2017-03-22)
etcd v3.1.3 (2017-03-10)
- use machine default host when advertise URLs are default
values(localhost:2379,2380) AND if listen URL is 0.0.0.0
- fix 'etcd gateway' schema handling in DNS discovery
- fix sd_notify behaviors in gateway, grpc-proxy
etcd v3.1.2 (2017-02-24)
- use IPv4 default host, by default (when IPv4 and IPv6 are available)
- fix 'etcd gateway' with multiple endpoints
etcd v3.1.1 (2017-02-17)
etcd v2.3.8 (2017-02-17)
etcd v3.1.0 (2017-01-20)
- faster linearizable reads (implements Raft read-index)
- automatic leadership transfer when leader steps down
- etcd uses default route IP if advertise URL is not given

View File

@ -11,7 +11,7 @@
![etcd Logo](logos/etcd-horizontal-color.png)
etcd is a distributed, consistent key-value store for shared configuration and service discovery, with a focus on being:
etcd is a distributed reliable key-value store for the most critical data of a distributed system, with a focus on being:
* *Simple*: well-defined, user-facing API (gRPC)
* *Secure*: automatic TLS with optional client cert authentication
@ -37,13 +37,11 @@ See [etcdctl][etcdctl] for a simple command line client.
### Getting etcd
The easiest way to get etcd is to use one of the pre-built release binaries which are available for OSX, Linux, Windows, AppC (ACI), and Docker. Instructions for using these binaries are on the [GitHub releases page][github-release].
The easiest way to get etcd is to use one of the pre-built release binaries which are available for OSX, Linux, Windows, [rkt][rkt], and Docker. Instructions for using these binaries are on the [GitHub releases page][github-release].
For those wanting to try the very latest version, you can [build the latest version of etcd][dl-build] from the `master` branch.
You will first need [*Go*](https://golang.org/) installed on your machine (version 1.6+ is required).
All development occurs on `master`, including new features and bug fixes.
Bug fixes are first targeted at `master` and subsequently ported to release branches, as described in the [branch management][branch-management] guide.
For those wanting to try the very latest version, [build the latest version of etcd][dl-build] from the `master` branch. This first needs [*Go*](https://golang.org/) installed (version 1.8+ is required). All development occurs on `master`, including new features and bug fixes. Bug fixes are first targeted at `master` and subsequently ported to release branches, as described in the [branch management][branch-management] guide.
[rkt]: https://github.com/rkt/rkt/releases/
[github-release]: https://github.com/coreos/etcd/releases/
[branch-management]: ./Documentation/branch_management.md
[dl-build]: ./Documentation/dl_build.md#build-the-latest-version
@ -75,9 +73,9 @@ That's it! etcd is now running and serving client requests. For more
### etcd TCP ports
The [official etcd ports][iana-ports] are 2379 for client requests, and 2380 for peer communication.
The [official etcd ports][iana-ports] are 2379 for client requests, and 2380 for peer communication.
[iana-ports]: https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=etcd
[iana-ports]: http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.txt
### Running a local etcd cluster
@ -95,7 +93,7 @@ Every cluster member and proxy accepts key value reads and key value writes.
### Running etcd on Kubernetes
If you want to run etcd cluster on Kubernetes, try [etcd operator](https://github.com/coreos/etcd-operator).
To run an etcd cluster on Kubernetes, try [etcd operator](https://github.com/coreos/etcd-operator).
### Next steps
@ -105,7 +103,7 @@ Now it's time to dig into the full etcd API and other guides.
- Explore the full gRPC [API][api].
- Set up a [multi-machine cluster][clustering].
- Learn the [config format, env variables and flags][configuration].
- Find [language bindings and tools][libraries-and-tools].
- Find [language bindings and tools][integrations].
- Use TLS to [secure an etcd cluster][security].
- [Tune etcd][tuning].
@ -113,7 +111,7 @@ Now it's time to dig into the full etcd API and other guides.
[api]: ./Documentation/dev-guide/api_reference_v3.md
[clustering]: ./Documentation/op-guide/clustering.md
[configuration]: ./Documentation/op-guide/configuration.md
[libraries-and-tools]: ./Documentation/libraries-and-tools.md
[integrations]: ./Documentation/integrations.md
[security]: ./Documentation/op-guide/security.md
[tuning]: ./Documentation/tuning.md
@ -130,10 +128,8 @@ See [CONTRIBUTING](CONTRIBUTING.md) for details on submitting patches and the co
## Reporting bugs
See [reporting bugs](Documentation/reporting_bugs.md) for details about reporting any issue you may encounter.
See [reporting bugs](Documentation/reporting_bugs.md) for details about reporting any issues.
### License
etcd is under the Apache 2.0 license. See the [LICENSE](LICENSE) file for details.

View File

@ -6,25 +6,17 @@ This document defines a high level roadmap for etcd development.
The dates below should not be considered authoritative, but rather indicative of the projected timeline of the project. The [milestones defined in GitHub](https://github.com/coreos/etcd/milestones) represent the most up-to-date and issue-for-issue plans.
etcd 3.0 is our current stable branch. The roadmap below outlines new features that will be added to etcd, and while subject to change, define what future stable will look like.
etcd 3.2 is our current stable branch. The roadmap below outlines new features that will be added to etcd, and while subject to change, define what future stable will look like.
### etcd 3.1 (2016-Oct)
- Stable L4 gateway
- Experimental support for scalable proxy
- Automatic leadership transfer for the rolling upgrade
- V3 API improvements
- Get previous key-value pair
- Get only keys (ignore values)
- Get only key count
### etcd 3.2 (2017-Apr)
### etcd 3.2 (2017-May)
- Stable scalable proxy
- Proxy-as-client interface passthrough
- Lock service
- Namespacing proxy
- JWT token based authentication
- TLS Command Name and JWT token based authentication
- Read-modify-write V3 Put
- Improved watch performance
- Support non-blocking concurrent read
### etcd 3.3 (?)
- TBD

View File

@ -803,7 +803,7 @@ func init() { proto.RegisterFile("auth.proto", fileDescriptorAuth) }
var fileDescriptorAuth = []byte{
// 288 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x6c, 0x90, 0xc1, 0x4a, 0xc3, 0x30,
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x90, 0xc1, 0x4a, 0xc3, 0x30,
0x1c, 0xc6, 0x9b, 0xb6, 0x1b, 0xed, 0x5f, 0x27, 0x25, 0x0c, 0x0c, 0x13, 0x42, 0xe9, 0xa9, 0x78,
0xa8, 0xb0, 0x5d, 0xbc, 0x2a, 0xf6, 0x20, 0x78, 0x90, 0x50, 0xf1, 0x28, 0x1d, 0x0d, 0x75, 0x6c,
0x6d, 0x4a, 0x32, 0x91, 0xbe, 0x89, 0x07, 0x1f, 0x68, 0xc7, 0x3d, 0x82, 0xab, 0x2f, 0x22, 0x4d,

137
auth/jwt.go Normal file
View File

@ -0,0 +1,137 @@
// Copyright 2017 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package auth
import (
"crypto/rsa"
"io/ioutil"
jwt "github.com/dgrijalva/jwt-go"
"golang.org/x/net/context"
)
type tokenJWT struct {
signMethod string
signKey *rsa.PrivateKey
verifyKey *rsa.PublicKey
}
func (t *tokenJWT) enable() {}
func (t *tokenJWT) disable() {}
func (t *tokenJWT) invalidateUser(string) {}
func (t *tokenJWT) genTokenPrefix() (string, error) { return "", nil }
func (t *tokenJWT) info(ctx context.Context, token string, rev uint64) (*AuthInfo, bool) {
// rev isn't used in JWT, it is only used in simple token
var (
username string
revision uint64
)
parsed, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
return t.verifyKey, nil
})
switch err.(type) {
case nil:
if !parsed.Valid {
plog.Warningf("invalid jwt token: %s", token)
return nil, false
}
claims := parsed.Claims.(jwt.MapClaims)
username = claims["username"].(string)
revision = uint64(claims["revision"].(float64))
default:
plog.Warningf("failed to parse jwt token: %s", err)
return nil, false
}
return &AuthInfo{Username: username, Revision: revision}, true
}
func (t *tokenJWT) assign(ctx context.Context, username string, revision uint64) (string, error) {
// Future work: let a jwt token include permission information would be useful for
// permission checking in proxy side.
tk := jwt.NewWithClaims(jwt.GetSigningMethod(t.signMethod),
jwt.MapClaims{
"username": username,
"revision": revision,
})
token, err := tk.SignedString(t.signKey)
if err != nil {
plog.Debugf("failed to sign jwt token: %s", err)
return "", err
}
plog.Debugf("jwt token: %s", token)
return token, err
}
func prepareOpts(opts map[string]string) (jwtSignMethod, jwtPubKeyPath, jwtPrivKeyPath string, err error) {
for k, v := range opts {
switch k {
case "sign-method":
jwtSignMethod = v
case "pub-key":
jwtPubKeyPath = v
case "priv-key":
jwtPrivKeyPath = v
default:
plog.Errorf("unknown token specific option: %s", k)
return "", "", "", ErrInvalidAuthOpts
}
}
return jwtSignMethod, jwtPubKeyPath, jwtPrivKeyPath, nil
}
func newTokenProviderJWT(opts map[string]string) (*tokenJWT, error) {
jwtSignMethod, jwtPubKeyPath, jwtPrivKeyPath, err := prepareOpts(opts)
if err != nil {
return nil, ErrInvalidAuthOpts
}
t := &tokenJWT{}
t.signMethod = jwtSignMethod
verifyBytes, err := ioutil.ReadFile(jwtPubKeyPath)
if err != nil {
plog.Errorf("failed to read public key (%s) for jwt: %s", jwtPubKeyPath, err)
return nil, err
}
t.verifyKey, err = jwt.ParseRSAPublicKeyFromPEM(verifyBytes)
if err != nil {
plog.Errorf("failed to parse public key (%s): %s", jwtPubKeyPath, err)
return nil, err
}
signBytes, err := ioutil.ReadFile(jwtPrivKeyPath)
if err != nil {
plog.Errorf("failed to read private key (%s) for jwt: %s", jwtPrivKeyPath, err)
return nil, err
}
t.signKey, err = jwt.ParseRSAPrivateKeyFromPEM(signBytes)
if err != nil {
plog.Errorf("failed to parse private key (%s): %s", jwtPrivKeyPath, err)
return nil, err
}
return t, nil
}

View File

@ -15,93 +15,11 @@
package auth
import (
"bytes"
"sort"
"github.com/coreos/etcd/auth/authpb"
"github.com/coreos/etcd/mvcc/backend"
"github.com/coreos/etcd/pkg/adt"
)
// isSubset returns true if a is a subset of b.
// If a is a prefix of b, then a is a subset of b.
// Given intervals [a1,a2) and [b1,b2), is
// the a interval a subset of b?
func isSubset(a, b *rangePerm) bool {
switch {
case len(a.end) == 0 && len(b.end) == 0:
// a, b are both keys
return bytes.Equal(a.begin, b.begin)
case len(b.end) == 0:
// b is a key, a is a range
return false
case len(a.end) == 0:
// a is a key, b is a range. need b1 <= a1 and a1 < b2
return bytes.Compare(b.begin, a.begin) <= 0 && bytes.Compare(a.begin, b.end) < 0
default:
// both are ranges. need b1 <= a1 and a2 <= b2
return bytes.Compare(b.begin, a.begin) <= 0 && bytes.Compare(a.end, b.end) <= 0
}
}
func isRangeEqual(a, b *rangePerm) bool {
return bytes.Equal(a.begin, b.begin) && bytes.Equal(a.end, b.end)
}
// removeSubsetRangePerms removes any rangePerms that are subsets of other rangePerms.
// If there are equal ranges, removeSubsetRangePerms only keeps one of them.
// It returns a sorted rangePerm slice.
func removeSubsetRangePerms(perms []*rangePerm) (newp []*rangePerm) {
sort.Sort(RangePermSliceByBegin(perms))
var prev *rangePerm
for i := range perms {
if i == 0 {
prev = perms[i]
newp = append(newp, perms[i])
continue
}
if isRangeEqual(perms[i], prev) {
continue
}
if isSubset(perms[i], prev) {
continue
}
if isSubset(prev, perms[i]) {
prev = perms[i]
newp[len(newp)-1] = perms[i]
continue
}
prev = perms[i]
newp = append(newp, perms[i])
}
return newp
}
// mergeRangePerms merges adjacent rangePerms.
func mergeRangePerms(perms []*rangePerm) []*rangePerm {
var merged []*rangePerm
perms = removeSubsetRangePerms(perms)
i := 0
for i < len(perms) {
begin, next := i, i
for next+1 < len(perms) && bytes.Compare(perms[next].end, perms[next+1].begin) >= 0 {
next++
}
// don't merge ["a", "b") with ["b", ""), because perms[next+1].end is empty.
if next != begin && len(perms[next].end) > 0 {
merged = append(merged, &rangePerm{begin: perms[begin].begin, end: perms[next].end})
} else {
merged = append(merged, perms[begin])
if next != begin {
merged = append(merged, perms[next])
}
}
i = next + 1
}
return merged
}
func getMergedPerms(tx backend.BatchTx, userName string) *unifiedRangePermissions {
user := getUser(tx, userName)
if user == nil {
@ -109,7 +27,8 @@ func getMergedPerms(tx backend.BatchTx, userName string) *unifiedRangePermission
return nil
}
var readPerms, writePerms []*rangePerm
readPerms := &adt.IntervalTree{}
writePerms := &adt.IntervalTree{}
for _, roleName := range user.Roles {
role := getRole(tx, roleName)
@ -118,48 +37,66 @@ func getMergedPerms(tx backend.BatchTx, userName string) *unifiedRangePermission
}
for _, perm := range role.KeyPermission {
rp := &rangePerm{begin: perm.Key, end: perm.RangeEnd}
var ivl adt.Interval
var rangeEnd []byte
if len(perm.RangeEnd) != 1 || perm.RangeEnd[0] != 0 {
rangeEnd = perm.RangeEnd
}
if len(perm.RangeEnd) != 0 {
ivl = adt.NewBytesAffineInterval(perm.Key, rangeEnd)
} else {
ivl = adt.NewBytesAffinePoint(perm.Key)
}
switch perm.PermType {
case authpb.READWRITE:
readPerms = append(readPerms, rp)
writePerms = append(writePerms, rp)
readPerms.Insert(ivl, struct{}{})
writePerms.Insert(ivl, struct{}{})
case authpb.READ:
readPerms = append(readPerms, rp)
readPerms.Insert(ivl, struct{}{})
case authpb.WRITE:
writePerms = append(writePerms, rp)
writePerms.Insert(ivl, struct{}{})
}
}
}
return &unifiedRangePermissions{
readPerms: mergeRangePerms(readPerms),
writePerms: mergeRangePerms(writePerms),
readPerms: readPerms,
writePerms: writePerms,
}
}
func checkKeyPerm(cachedPerms *unifiedRangePermissions, key, rangeEnd []byte, permtyp authpb.Permission_Type) bool {
var tocheck []*rangePerm
func checkKeyInterval(cachedPerms *unifiedRangePermissions, key, rangeEnd []byte, permtyp authpb.Permission_Type) bool {
if len(rangeEnd) == 1 && rangeEnd[0] == 0 {
rangeEnd = nil
}
ivl := adt.NewBytesAffineInterval(key, rangeEnd)
switch permtyp {
case authpb.READ:
tocheck = cachedPerms.readPerms
return cachedPerms.readPerms.Contains(ivl)
case authpb.WRITE:
tocheck = cachedPerms.writePerms
return cachedPerms.writePerms.Contains(ivl)
default:
plog.Panicf("unknown auth type: %v", permtyp)
}
return false
}
requiredPerm := &rangePerm{begin: key, end: rangeEnd}
for _, perm := range tocheck {
if isSubset(requiredPerm, perm) {
return true
}
func checkKeyPoint(cachedPerms *unifiedRangePermissions, key []byte, permtyp authpb.Permission_Type) bool {
pt := adt.NewBytesAffinePoint(key)
switch permtyp {
case authpb.READ:
return cachedPerms.readPerms.Intersects(pt)
case authpb.WRITE:
return cachedPerms.writePerms.Intersects(pt)
default:
plog.Panicf("unknown auth type: %v", permtyp)
}
return false
}
@ -175,7 +112,11 @@ func (as *authStore) isRangeOpPermitted(tx backend.BatchTx, userName string, key
as.rangePermCache[userName] = perms
}
return checkKeyPerm(as.rangePermCache[userName], key, rangeEnd, permtyp)
if len(rangeEnd) == 0 {
return checkKeyPoint(as.rangePermCache[userName], key, permtyp)
}
return checkKeyInterval(as.rangePermCache[userName], key, rangeEnd, permtyp)
}
func (as *authStore) clearCachedPerm() {
@ -187,35 +128,6 @@ func (as *authStore) invalidateCachedPerm(userName string) {
}
type unifiedRangePermissions struct {
// readPerms[i] and readPerms[j] (i != j) don't overlap
readPerms []*rangePerm
// writePerms[i] and writePerms[j] (i != j) don't overlap, too
writePerms []*rangePerm
}
type rangePerm struct {
begin, end []byte
}
type RangePermSliceByBegin []*rangePerm
func (slice RangePermSliceByBegin) Len() int {
return len(slice)
}
func (slice RangePermSliceByBegin) Less(i, j int) bool {
switch bytes.Compare(slice[i].begin, slice[j].begin) {
case 0: // begin(i) == begin(j)
return bytes.Compare(slice[i].end, slice[j].end) == -1
case -1: // begin(i) < begin(j)
return true
default:
return false
}
}
func (slice RangePermSliceByBegin) Swap(i, j int) {
slice[i], slice[j] = slice[j], slice[i]
readPerms *adt.IntervalTree
writePerms *adt.IntervalTree
}

View File

@ -15,165 +15,45 @@
package auth
import (
"bytes"
"fmt"
"reflect"
"testing"
"github.com/coreos/etcd/auth/authpb"
"github.com/coreos/etcd/pkg/adt"
)
func isPermsEqual(a, b []*rangePerm) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if len(b) <= i {
return false
}
if !bytes.Equal(a[i].begin, b[i].begin) || !bytes.Equal(a[i].end, b[i].end) {
return false
}
}
return true
}
func TestGetMergedPerms(t *testing.T) {
func TestRangePermission(t *testing.T) {
tests := []struct {
params []*rangePerm
want []*rangePerm
perms []adt.Interval
begin []byte
end []byte
want bool
}{
{
[]*rangePerm{{[]byte("a"), []byte("b")}},
[]*rangePerm{{[]byte("a"), []byte("b")}},
[]adt.Interval{adt.NewBytesAffineInterval([]byte("a"), []byte("c")), adt.NewBytesAffineInterval([]byte("x"), []byte("z"))},
[]byte("a"), []byte("z"),
false,
},
{
[]*rangePerm{{[]byte("a"), []byte("b")}, {[]byte("b"), []byte("")}},
[]*rangePerm{{[]byte("a"), []byte("b")}, {[]byte("b"), []byte("")}},
[]adt.Interval{adt.NewBytesAffineInterval([]byte("a"), []byte("f")), adt.NewBytesAffineInterval([]byte("c"), []byte("d")), adt.NewBytesAffineInterval([]byte("f"), []byte("z"))},
[]byte("a"), []byte("z"),
true,
},
{
[]*rangePerm{{[]byte("a"), []byte("b")}, {[]byte("b"), []byte("c")}},
[]*rangePerm{{[]byte("a"), []byte("c")}},
},
{
[]*rangePerm{{[]byte("a"), []byte("c")}, {[]byte("b"), []byte("d")}},
[]*rangePerm{{[]byte("a"), []byte("d")}},
},
{
[]*rangePerm{{[]byte("a"), []byte("b")}, {[]byte("b"), []byte("c")}, {[]byte("d"), []byte("e")}},
[]*rangePerm{{[]byte("a"), []byte("c")}, {[]byte("d"), []byte("e")}},
},
{
[]*rangePerm{{[]byte("a"), []byte("b")}, {[]byte("c"), []byte("d")}, {[]byte("e"), []byte("f")}},
[]*rangePerm{{[]byte("a"), []byte("b")}, {[]byte("c"), []byte("d")}, {[]byte("e"), []byte("f")}},
},
{
[]*rangePerm{{[]byte("e"), []byte("f")}, {[]byte("c"), []byte("d")}, {[]byte("a"), []byte("b")}},
[]*rangePerm{{[]byte("a"), []byte("b")}, {[]byte("c"), []byte("d")}, {[]byte("e"), []byte("f")}},
},
{
[]*rangePerm{{[]byte("a"), []byte("b")}, {[]byte("c"), []byte("d")}, {[]byte("a"), []byte("z")}},
[]*rangePerm{{[]byte("a"), []byte("z")}},
},
{
[]*rangePerm{{[]byte("a"), []byte("b")}, {[]byte("c"), []byte("d")}, {[]byte("a"), []byte("z")}, {[]byte("1"), []byte("9")}},
[]*rangePerm{{[]byte("1"), []byte("9")}, {[]byte("a"), []byte("z")}},
},
{
[]*rangePerm{{[]byte("a"), []byte("b")}, {[]byte("c"), []byte("d")}, {[]byte("a"), []byte("z")}, {[]byte("1"), []byte("a")}},
[]*rangePerm{{[]byte("1"), []byte("z")}},
},
{
[]*rangePerm{{[]byte("a"), []byte("b")}, {[]byte("a"), []byte("z")}, {[]byte("5"), []byte("6")}, {[]byte("1"), []byte("9")}},
[]*rangePerm{{[]byte("1"), []byte("9")}, {[]byte("a"), []byte("z")}},
},
{
[]*rangePerm{{[]byte("a"), []byte("b")}, {[]byte("b"), []byte("c")}, {[]byte("c"), []byte("d")}, {[]byte("d"), []byte("f")}, {[]byte("1"), []byte("9")}},
[]*rangePerm{{[]byte("1"), []byte("9")}, {[]byte("a"), []byte("f")}},
},
// overlapping
{
[]*rangePerm{{[]byte("a"), []byte("f")}, {[]byte("b"), []byte("g")}},
[]*rangePerm{{[]byte("a"), []byte("g")}},
},
// keys
{
[]*rangePerm{{[]byte("a"), []byte("")}, {[]byte("b"), []byte("")}},
[]*rangePerm{{[]byte("a"), []byte("")}, {[]byte("b"), []byte("")}},
},
{
[]*rangePerm{{[]byte("a"), []byte("")}, {[]byte("a"), []byte("c")}},
[]*rangePerm{{[]byte("a"), []byte("c")}},
},
{
[]*rangePerm{{[]byte("a"), []byte("")}, {[]byte("a"), []byte("c")}, {[]byte("b"), []byte("")}},
[]*rangePerm{{[]byte("a"), []byte("c")}},
},
{
[]*rangePerm{{[]byte("a"), []byte("")}, {[]byte("b"), []byte("c")}, {[]byte("b"), []byte("")}, {[]byte("c"), []byte("")}, {[]byte("d"), []byte("")}},
[]*rangePerm{{[]byte("a"), []byte("")}, {[]byte("b"), []byte("c")}, {[]byte("c"), []byte("")}, {[]byte("d"), []byte("")}},
},
// duplicate ranges
{
[]*rangePerm{{[]byte("a"), []byte("f")}, {[]byte("a"), []byte("f")}},
[]*rangePerm{{[]byte("a"), []byte("f")}},
},
// duplicate keys
{
[]*rangePerm{{[]byte("a"), []byte("")}, {[]byte("a"), []byte("")}, {[]byte("a"), []byte("")}},
[]*rangePerm{{[]byte("a"), []byte("")}},
[]adt.Interval{adt.NewBytesAffineInterval([]byte("a"), []byte("d")), adt.NewBytesAffineInterval([]byte("a"), []byte("b")), adt.NewBytesAffineInterval([]byte("c"), []byte("f"))},
[]byte("a"), []byte("f"),
true,
},
}
for i, tt := range tests {
result := mergeRangePerms(tt.params)
if !isPermsEqual(result, tt.want) {
t.Errorf("#%d: result=%q, want=%q", i, result, tt.want)
readPerms := &adt.IntervalTree{}
for _, p := range tt.perms {
readPerms.Insert(p, struct{}{})
}
}
}
func TestRemoveSubsetRangePerms(t *testing.T) {
tests := []struct {
perms []*rangePerm
expect []*rangePerm
}{
{ // subsets converge
[]*rangePerm{{[]byte{2}, []byte{3}}, {[]byte{2}, []byte{5}}, {[]byte{1}, []byte{4}}},
[]*rangePerm{{[]byte{1}, []byte{4}}, {[]byte{2}, []byte{5}}},
},
{ // subsets converge
[]*rangePerm{{[]byte{0}, []byte{3}}, {[]byte{0}, []byte{1}}, {[]byte{2}, []byte{4}}, {[]byte{0}, []byte{2}}},
[]*rangePerm{{[]byte{0}, []byte{3}}, {[]byte{2}, []byte{4}}},
},
{ // biggest range at the end
[]*rangePerm{{[]byte{2}, []byte{3}}, {[]byte{0}, []byte{2}}, {[]byte{1}, []byte{4}}, {[]byte{0}, []byte{5}}},
[]*rangePerm{{[]byte{0}, []byte{5}}},
},
{ // biggest range at the beginning
[]*rangePerm{{[]byte{0}, []byte{5}}, {[]byte{2}, []byte{3}}, {[]byte{0}, []byte{2}}, {[]byte{1}, []byte{4}}},
[]*rangePerm{{[]byte{0}, []byte{5}}},
},
{ // no overlapping ranges
[]*rangePerm{{[]byte{2}, []byte{3}}, {[]byte{0}, []byte{1}}, {[]byte{4}, []byte{7}}, {[]byte{8}, []byte{15}}},
[]*rangePerm{{[]byte{0}, []byte{1}}, {[]byte{2}, []byte{3}}, {[]byte{4}, []byte{7}}, {[]byte{8}, []byte{15}}},
},
}
for i, tt := range tests {
rs := removeSubsetRangePerms(tt.perms)
if !reflect.DeepEqual(rs, tt.expect) {
t.Fatalf("#%d: unexpected rangePerms %q, got %q", i, printPerms(rs), printPerms(tt.expect))
result := checkKeyInterval(&unifiedRangePermissions{readPerms: readPerms}, tt.begin, tt.end, authpb.READ)
if result != tt.want {
t.Errorf("#%d: result=%t, want=%t", i, result, tt.want)
}
}
}
func printPerms(rs []*rangePerm) (txt string) {
for i, p := range rs {
if i != 0 {
txt += ","
}
txt += fmt.Sprintf("%+v", *p)
}
return
}

View File

@ -19,88 +19,89 @@ package auth
import (
"crypto/rand"
"fmt"
"math/big"
"strconv"
"strings"
"sync"
"time"
"golang.org/x/net/context"
)
const (
letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
defaultSimpleTokenLength = 16
)
// var for testing purposes
var (
simpleTokenTTL = 5 * time.Minute
simpleTokenTTLResolution = 1 * time.Second
)
type simpleTokenTTLKeeper struct {
tokens map[string]time.Time
addSimpleTokenCh chan string
resetSimpleTokenCh chan string
deleteSimpleTokenCh chan string
stopCh chan chan struct{}
deleteTokenFunc func(string)
}
func NewSimpleTokenTTLKeeper(deletefunc func(string)) *simpleTokenTTLKeeper {
stk := &simpleTokenTTLKeeper{
tokens: make(map[string]time.Time),
addSimpleTokenCh: make(chan string, 1),
resetSimpleTokenCh: make(chan string, 1),
deleteSimpleTokenCh: make(chan string, 1),
stopCh: make(chan chan struct{}),
deleteTokenFunc: deletefunc,
}
go stk.run()
return stk
tokens map[string]time.Time
donec chan struct{}
stopc chan struct{}
deleteTokenFunc func(string)
mu *sync.Mutex
}
func (tm *simpleTokenTTLKeeper) stop() {
waitCh := make(chan struct{})
tm.stopCh <- waitCh
<-waitCh
close(tm.stopCh)
select {
case tm.stopc <- struct{}{}:
case <-tm.donec:
}
<-tm.donec
}
func (tm *simpleTokenTTLKeeper) addSimpleToken(token string) {
tm.addSimpleTokenCh <- token
tm.tokens[token] = time.Now().Add(simpleTokenTTL)
}
func (tm *simpleTokenTTLKeeper) resetSimpleToken(token string) {
tm.resetSimpleTokenCh <- token
if _, ok := tm.tokens[token]; ok {
tm.tokens[token] = time.Now().Add(simpleTokenTTL)
}
}
func (tm *simpleTokenTTLKeeper) deleteSimpleToken(token string) {
tm.deleteSimpleTokenCh <- token
delete(tm.tokens, token)
}
func (tm *simpleTokenTTLKeeper) run() {
tokenTicker := time.NewTicker(simpleTokenTTLResolution)
defer tokenTicker.Stop()
defer func() {
tokenTicker.Stop()
close(tm.donec)
}()
for {
select {
case t := <-tm.addSimpleTokenCh:
tm.tokens[t] = time.Now().Add(simpleTokenTTL)
case t := <-tm.resetSimpleTokenCh:
if _, ok := tm.tokens[t]; ok {
tm.tokens[t] = time.Now().Add(simpleTokenTTL)
}
case t := <-tm.deleteSimpleTokenCh:
delete(tm.tokens, t)
case <-tokenTicker.C:
nowtime := time.Now()
tm.mu.Lock()
for t, tokenendtime := range tm.tokens {
if nowtime.After(tokenendtime) {
tm.deleteTokenFunc(t)
delete(tm.tokens, t)
}
}
case waitCh := <-tm.stopCh:
tm.tokens = make(map[string]time.Time)
waitCh <- struct{}{}
tm.mu.Unlock()
case <-tm.stopc:
return
}
}
}
func (as *authStore) GenSimpleToken() (string, error) {
type tokenSimple struct {
indexWaiter func(uint64) <-chan struct{}
simpleTokenKeeper *simpleTokenTTLKeeper
simpleTokensMu sync.Mutex
simpleTokens map[string]string // token -> username
}
func (t *tokenSimple) genTokenPrefix() (string, error) {
ret := make([]byte, defaultSimpleTokenLength)
for i := 0; i < defaultSimpleTokenLength; i++ {
@ -115,27 +116,105 @@ func (as *authStore) GenSimpleToken() (string, error) {
return string(ret), nil
}
func (as *authStore) assignSimpleTokenToUser(username, token string) {
as.simpleTokensMu.Lock()
_, ok := as.simpleTokens[token]
func (t *tokenSimple) assignSimpleTokenToUser(username, token string) {
t.simpleTokensMu.Lock()
_, ok := t.simpleTokens[token]
if ok {
plog.Panicf("token %s is alredy used", token)
}
as.simpleTokens[token] = username
as.simpleTokenKeeper.addSimpleToken(token)
as.simpleTokensMu.Unlock()
t.simpleTokens[token] = username
t.simpleTokenKeeper.addSimpleToken(token)
t.simpleTokensMu.Unlock()
}
func (as *authStore) invalidateUser(username string) {
as.simpleTokensMu.Lock()
defer as.simpleTokensMu.Unlock()
for token, name := range as.simpleTokens {
func (t *tokenSimple) invalidateUser(username string) {
if t.simpleTokenKeeper == nil {
return
}
t.simpleTokensMu.Lock()
for token, name := range t.simpleTokens {
if strings.Compare(name, username) == 0 {
delete(as.simpleTokens, token)
as.simpleTokenKeeper.deleteSimpleToken(token)
delete(t.simpleTokens, token)
t.simpleTokenKeeper.deleteSimpleToken(token)
}
}
t.simpleTokensMu.Unlock()
}
func (t *tokenSimple) enable() {
delf := func(tk string) {
if username, ok := t.simpleTokens[tk]; ok {
plog.Infof("deleting token %s for user %s", tk, username)
delete(t.simpleTokens, tk)
}
}
t.simpleTokenKeeper = &simpleTokenTTLKeeper{
tokens: make(map[string]time.Time),
donec: make(chan struct{}),
stopc: make(chan struct{}),
deleteTokenFunc: delf,
mu: &t.simpleTokensMu,
}
go t.simpleTokenKeeper.run()
}
func (t *tokenSimple) disable() {
t.simpleTokensMu.Lock()
tk := t.simpleTokenKeeper
t.simpleTokenKeeper = nil
t.simpleTokens = make(map[string]string) // invalidate all tokens
t.simpleTokensMu.Unlock()
if tk != nil {
tk.stop()
}
}
func (t *tokenSimple) info(ctx context.Context, token string, revision uint64) (*AuthInfo, bool) {
if !t.isValidSimpleToken(ctx, token) {
return nil, false
}
t.simpleTokensMu.Lock()
username, ok := t.simpleTokens[token]
if ok && t.simpleTokenKeeper != nil {
t.simpleTokenKeeper.resetSimpleToken(token)
}
t.simpleTokensMu.Unlock()
return &AuthInfo{Username: username, Revision: revision}, ok
}
func (t *tokenSimple) assign(ctx context.Context, username string, rev uint64) (string, error) {
// rev isn't used in simple token, it is only used in JWT
index := ctx.Value("index").(uint64)
simpleToken := ctx.Value("simpleToken").(string)
token := fmt.Sprintf("%s.%d", simpleToken, index)
t.assignSimpleTokenToUser(username, token)
return token, nil
}
func (t *tokenSimple) isValidSimpleToken(ctx context.Context, token string) bool {
splitted := strings.Split(token, ".")
if len(splitted) != 2 {
return false
}
index, err := strconv.Atoi(splitted[1])
if err != nil {
return false
}
select {
case <-t.indexWaiter(uint64(index)):
return true
case <-ctx.Done():
}
return false
}
func newTokenProviderSimple(indexWaiter func(uint64) <-chan struct{}) *tokenSimple {
return &tokenSimple{
simpleTokens: make(map[string]string),
indexWaiter: indexWaiter,
}
}

View File

@ -18,10 +18,10 @@ import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"sort"
"strings"
"sync"
"sync/atomic"
"github.com/coreos/etcd/auth/authpb"
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
@ -29,6 +29,9 @@ import (
"github.com/coreos/pkg/capnslog"
"golang.org/x/crypto/bcrypt"
"golang.org/x/net/context"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/peer"
)
var (
@ -57,6 +60,9 @@ var (
ErrPermissionNotGranted = errors.New("auth: permission is not granted to the role")
ErrAuthNotEnabled = errors.New("auth: authentication is not enabled")
ErrAuthOldRevision = errors.New("auth: revision in header is old")
ErrInvalidAuthToken = errors.New("auth: invalid auth token")
ErrInvalidAuthOpts = errors.New("auth: invalid auth options")
ErrInvalidAuthMgmt = errors.New("auth: invalid auth management")
// BcryptCost is the algorithm cost / strength for hashing auth passwords
BcryptCost = bcrypt.DefaultCost
@ -126,10 +132,6 @@ type AuthStore interface {
// RoleList gets a list of all roles
RoleList(r *pb.AuthRoleListRequest) (*pb.AuthRoleListResponse, error)
// AuthInfoFromToken gets a username from the given Token and current revision number
// (The revision number is used for preventing the TOCTOU problem)
AuthInfoFromToken(token string) (*AuthInfo, bool)
// IsPutPermitted checks put permission of the user
IsPutPermitted(authInfo *AuthInfo, key []byte) error
@ -142,8 +144,9 @@ type AuthStore interface {
// IsAdminPermitted checks admin permission of the user
IsAdminPermitted(authInfo *AuthInfo) error
// GenSimpleToken produces a simple random string
GenSimpleToken() (string, error)
// GenTokenPrefix produces a random string in a case of simple token
// in a case of JWT, it produces an empty string
GenTokenPrefix() (string, error)
// Revision gets current revision of authStore
Revision() uint64
@ -153,20 +156,35 @@ type AuthStore interface {
// Close does cleanup of AuthStore
Close() error
// AuthInfoFromCtx gets AuthInfo from gRPC's context
AuthInfoFromCtx(ctx context.Context) (*AuthInfo, error)
// AuthInfoFromTLS gets AuthInfo from TLS info of gRPC's context
AuthInfoFromTLS(ctx context.Context) *AuthInfo
}
type TokenProvider interface {
info(ctx context.Context, token string, revision uint64) (*AuthInfo, bool)
assign(ctx context.Context, username string, revision uint64) (string, error)
enable()
disable()
invalidateUser(string)
genTokenPrefix() (string, error)
}
type authStore struct {
// atomic operations; need 64-bit align, or 32-bit tests will crash
revision uint64
be backend.Backend
enabled bool
enabledMu sync.RWMutex
rangePermCache map[string]*unifiedRangePermissions // username -> unifiedRangePermissions
simpleTokensMu sync.RWMutex
simpleTokens map[string]string // token -> username
simpleTokenKeeper *simpleTokenTTLKeeper
revision uint64
tokenProvider TokenProvider
}
func (as *authStore) AuthEnable() error {
@ -196,20 +214,11 @@ func (as *authStore) AuthEnable() error {
tx.UnsafePut(authBucketName, enableFlagKey, authEnabled)
as.enabled = true
tokenDeleteFunc := func(t string) {
as.simpleTokensMu.Lock()
defer as.simpleTokensMu.Unlock()
if username, ok := as.simpleTokens[t]; ok {
plog.Infof("deleting token %s for user %s", t, username)
delete(as.simpleTokens, t)
}
}
as.simpleTokenKeeper = NewSimpleTokenTTLKeeper(tokenDeleteFunc)
as.tokenProvider.enable()
as.rangePermCache = make(map[string]*unifiedRangePermissions)
as.revision = getRevision(tx)
as.setRevision(getRevision(tx))
plog.Noticef("Authentication enabled")
@ -231,14 +240,7 @@ func (as *authStore) AuthDisable() {
b.ForceCommit()
as.enabled = false
as.simpleTokensMu.Lock()
as.simpleTokens = make(map[string]string) // invalidate all tokens
as.simpleTokensMu.Unlock()
if as.simpleTokenKeeper != nil {
as.simpleTokenKeeper.stop()
as.simpleTokenKeeper = nil
}
as.tokenProvider.disable()
plog.Noticef("Authentication disabled")
}
@ -249,10 +251,7 @@ func (as *authStore) Close() error {
if !as.enabled {
return nil
}
if as.simpleTokenKeeper != nil {
as.simpleTokenKeeper.stop()
as.simpleTokenKeeper = nil
}
as.tokenProvider.disable()
return nil
}
@ -261,10 +260,6 @@ func (as *authStore) Authenticate(ctx context.Context, username, password string
return nil, ErrAuthNotEnabled
}
// TODO(mitake): after adding jwt support, branching based on values of ctx is required
index := ctx.Value("index").(uint64)
simpleToken := ctx.Value("simpleToken").(string)
tx := as.be.BatchTx()
tx.Lock()
defer tx.Unlock()
@ -274,14 +269,23 @@ func (as *authStore) Authenticate(ctx context.Context, username, password string
return nil, ErrAuthFailed
}
token := fmt.Sprintf("%s.%d", simpleToken, index)
as.assignSimpleTokenToUser(username, token)
// Password checking is already performed in the API layer, so we don't need to check for now.
// Staleness of password can be detected with OCC in the API layer, too.
plog.Infof("authorized %s, token is %s", username, token)
token, err := as.tokenProvider.assign(ctx, username, as.Revision())
if err != nil {
return nil, err
}
plog.Debugf("authorized %s, token is %s", username, token)
return &pb.AuthenticateResponse{Token: token}, nil
}
func (as *authStore) CheckPassword(username, password string) (uint64, error) {
if !as.isAuthEnabled() {
return 0, ErrAuthNotEnabled
}
tx := as.be.BatchTx()
tx.Lock()
defer tx.Unlock()
@ -311,7 +315,7 @@ func (as *authStore) Recover(be backend.Backend) {
}
}
as.revision = getRevision(tx)
as.setRevision(getRevision(tx))
tx.Unlock()
@ -355,6 +359,11 @@ func (as *authStore) UserAdd(r *pb.AuthUserAddRequest) (*pb.AuthUserAddResponse,
}
func (as *authStore) UserDelete(r *pb.AuthUserDeleteRequest) (*pb.AuthUserDeleteResponse, error) {
if as.enabled && strings.Compare(r.Name, rootUser) == 0 {
plog.Errorf("the user root must not be deleted")
return nil, ErrInvalidAuthMgmt
}
tx := as.be.BatchTx()
tx.Lock()
defer tx.Unlock()
@ -369,7 +378,7 @@ func (as *authStore) UserDelete(r *pb.AuthUserDeleteRequest) (*pb.AuthUserDelete
as.commitRevision(tx)
as.invalidateCachedPerm(r.Name)
as.invalidateUser(r.Name)
as.tokenProvider.invalidateUser(r.Name)
plog.Noticef("deleted a user: %s", r.Name)
@ -405,7 +414,7 @@ func (as *authStore) UserChangePassword(r *pb.AuthUserChangePasswordRequest) (*p
as.commitRevision(tx)
as.invalidateCachedPerm(r.Name)
as.invalidateUser(r.Name)
as.tokenProvider.invalidateUser(r.Name)
plog.Noticef("changed a password of a user: %s", r.Name)
@ -480,6 +489,11 @@ func (as *authStore) UserList(r *pb.AuthUserListRequest) (*pb.AuthUserListRespon
}
func (as *authStore) UserRevokeRole(r *pb.AuthUserRevokeRoleRequest) (*pb.AuthUserRevokeRoleResponse, error) {
if as.enabled && strings.Compare(r.Name, rootUser) == 0 && strings.Compare(r.Role, rootRole) == 0 {
plog.Errorf("the role root must not be revoked from the user root")
return nil, ErrInvalidAuthMgmt
}
tx := as.be.BatchTx()
tx.Lock()
defer tx.Unlock()
@ -582,17 +596,10 @@ func (as *authStore) RoleRevokePermission(r *pb.AuthRoleRevokePermissionRequest)
}
func (as *authStore) RoleDelete(r *pb.AuthRoleDeleteRequest) (*pb.AuthRoleDeleteResponse, error) {
// TODO(mitake): current scheme of role deletion allows existing users to have the deleted roles
//
// Assume a case like below:
// create a role r1
// create a user u1 and grant r1 to u1
// delete r1
//
// After this sequence, u1 is still granted the role r1. So if admin create a new role with the name r1,
// the new r1 is automatically granted u1.
// In some cases, it would be confusing. So we need to provide an option for deleting the grant relation
// from all users.
if as.enabled && strings.Compare(r.Role, rootRole) == 0 {
plog.Errorf("the role root must not be deleted")
return nil, ErrInvalidAuthMgmt
}
tx := as.be.BatchTx()
tx.Lock()
@ -605,6 +612,28 @@ func (as *authStore) RoleDelete(r *pb.AuthRoleDeleteRequest) (*pb.AuthRoleDelete
delRole(tx, r.Role)
users := getAllUsers(tx)
for _, user := range users {
updatedUser := &authpb.User{
Name: user.Name,
Password: user.Password,
}
for _, role := range user.Roles {
if strings.Compare(role, r.Role) != 0 {
updatedUser.Roles = append(updatedUser.Roles, role)
}
}
if len(updatedUser.Roles) == len(user.Roles) {
continue
}
putUser(tx, updatedUser)
as.invalidateCachedPerm(string(user.Name))
}
as.commitRevision(tx)
plog.Noticef("deleted role %s", r.Role)
@ -634,14 +663,8 @@ func (as *authStore) RoleAdd(r *pb.AuthRoleAddRequest) (*pb.AuthRoleAddResponse,
return &pb.AuthRoleAddResponse{}, nil
}
func (as *authStore) AuthInfoFromToken(token string) (*AuthInfo, bool) {
as.simpleTokensMu.RLock()
defer as.simpleTokensMu.RUnlock()
t, ok := as.simpleTokens[token]
if ok {
as.simpleTokenKeeper.resetSimpleToken(token)
}
return &AuthInfo{Username: t, Revision: as.revision}, ok
func (as *authStore) authInfoFromToken(ctx context.Context, token string) (*AuthInfo, bool) {
return as.tokenProvider.info(ctx, token, as.Revision())
}
type permSlice []*authpb.Permission
@ -711,7 +734,7 @@ func (as *authStore) isOpPermitted(userName string, revision uint64, key, rangeE
return ErrUserEmpty
}
if revision < as.revision {
if revision < as.Revision() {
return ErrAuthOldRevision
}
@ -753,6 +776,9 @@ func (as *authStore) IsAdminPermitted(authInfo *AuthInfo) error {
if !as.isAuthEnabled() {
return nil
}
if authInfo == nil {
return ErrUserEmpty
}
tx := as.be.BatchTx()
tx.Lock()
@ -871,7 +897,7 @@ func (as *authStore) isAuthEnabled() bool {
return as.enabled
}
func NewAuthStore(be backend.Backend) *authStore {
func NewAuthStore(be backend.Backend, tp TokenProvider) *authStore {
tx := be.BatchTx()
tx.Lock()
@ -879,13 +905,29 @@ func NewAuthStore(be backend.Backend) *authStore {
tx.UnsafeCreateBucket(authUsersBucketName)
tx.UnsafeCreateBucket(authRolesBucketName)
as := &authStore{
be: be,
simpleTokens: make(map[string]string),
revision: 0,
enabled := false
_, vs := tx.UnsafeRange(authBucketName, enableFlagKey, nil, 0)
if len(vs) == 1 {
if bytes.Equal(vs[0], authEnabled) {
enabled = true
}
}
as.commitRevision(tx)
as := &authStore{
be: be,
revision: getRevision(tx),
enabled: enabled,
rangePermCache: make(map[string]*unifiedRangePermissions),
tokenProvider: tp,
}
if enabled {
as.tokenProvider.enable()
}
if as.Revision() == 0 {
as.commitRevision(tx)
}
tx.Unlock()
be.ForceCommit()
@ -903,21 +945,115 @@ func hasRootRole(u *authpb.User) bool {
}
func (as *authStore) commitRevision(tx backend.BatchTx) {
as.revision++
atomic.AddUint64(&as.revision, 1)
revBytes := make([]byte, revBytesLen)
binary.BigEndian.PutUint64(revBytes, as.revision)
binary.BigEndian.PutUint64(revBytes, as.Revision())
tx.UnsafePut(authBucketName, revisionKey, revBytes)
}
func getRevision(tx backend.BatchTx) uint64 {
_, vs := tx.UnsafeRange(authBucketName, []byte(revisionKey), nil, 0)
if len(vs) != 1 {
plog.Panicf("failed to get the key of auth store revision")
// this can happen in the initialization phase
return 0
}
return binary.BigEndian.Uint64(vs[0])
}
func (as *authStore) Revision() uint64 {
return as.revision
func (as *authStore) setRevision(rev uint64) {
atomic.StoreUint64(&as.revision, rev)
}
func (as *authStore) Revision() uint64 {
return atomic.LoadUint64(&as.revision)
}
func (as *authStore) AuthInfoFromTLS(ctx context.Context) *AuthInfo {
peer, ok := peer.FromContext(ctx)
if !ok || peer == nil || peer.AuthInfo == nil {
return nil
}
tlsInfo := peer.AuthInfo.(credentials.TLSInfo)
for _, chains := range tlsInfo.State.VerifiedChains {
for _, chain := range chains {
cn := chain.Subject.CommonName
plog.Debugf("found common name %s", cn)
return &AuthInfo{
Username: cn,
Revision: as.Revision(),
}
}
}
return nil
}
func (as *authStore) AuthInfoFromCtx(ctx context.Context) (*AuthInfo, error) {
md, ok := metadata.FromContext(ctx)
if !ok {
return nil, nil
}
ts, tok := md["token"]
if !tok {
return nil, nil
}
token := ts[0]
authInfo, uok := as.authInfoFromToken(ctx, token)
if !uok {
plog.Warningf("invalid auth token: %s", token)
return nil, ErrInvalidAuthToken
}
return authInfo, nil
}
func (as *authStore) GenTokenPrefix() (string, error) {
return as.tokenProvider.genTokenPrefix()
}
func decomposeOpts(optstr string) (string, map[string]string, error) {
opts := strings.Split(optstr, ",")
tokenType := opts[0]
typeSpecificOpts := make(map[string]string)
for i := 1; i < len(opts); i++ {
pair := strings.Split(opts[i], "=")
if len(pair) != 2 {
plog.Errorf("invalid token specific option: %s", optstr)
return "", nil, ErrInvalidAuthOpts
}
if _, ok := typeSpecificOpts[pair[0]]; ok {
plog.Errorf("invalid token specific option, duplicated parameters (%s): %s", pair[0], optstr)
return "", nil, ErrInvalidAuthOpts
}
typeSpecificOpts[pair[0]] = pair[1]
}
return tokenType, typeSpecificOpts, nil
}
func NewTokenProvider(tokenOpts string, indexWaiter func(uint64) <-chan struct{}) (TokenProvider, error) {
tokenType, typeSpecificOpts, err := decomposeOpts(tokenOpts)
if err != nil {
return nil, ErrInvalidAuthOpts
}
switch tokenType {
case "simple":
plog.Warningf("simple token is not cryptographically signed")
return newTokenProviderSimple(indexWaiter), nil
case "jwt":
return newTokenProviderJWT(typeSpecificOpts)
default:
plog.Errorf("unknown token type: %s", tokenType)
return nil, ErrInvalidAuthOpts
}
}

View File

@ -15,43 +15,94 @@
package auth
import (
"fmt"
"os"
"reflect"
"sync"
"testing"
"time"
"github.com/coreos/etcd/auth/authpb"
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
"github.com/coreos/etcd/mvcc/backend"
"golang.org/x/crypto/bcrypt"
"golang.org/x/net/context"
"google.golang.org/grpc/metadata"
)
func init() { BcryptCost = bcrypt.MinCost }
func TestUserAdd(t *testing.T) {
b, tPath := backend.NewDefaultTmpBackend()
defer func() {
b.Close()
os.Remove(tPath)
func dummyIndexWaiter(index uint64) <-chan struct{} {
ch := make(chan struct{})
go func() {
ch <- struct{}{}
}()
return ch
}
as := NewAuthStore(b)
ua := &pb.AuthUserAddRequest{Name: "foo"}
_, err := as.UserAdd(ua) // add a non-existing user
// TestNewAuthStoreRevision ensures newly auth store
// keeps the old revision when there are no changes.
func TestNewAuthStoreRevision(t *testing.T) {
b, tPath := backend.NewDefaultTmpBackend()
defer os.Remove(tPath)
tp, err := NewTokenProvider("simple", dummyIndexWaiter)
if err != nil {
t.Fatal(err)
}
_, err = as.UserAdd(ua) // add an existing user
if err == nil {
t.Fatalf("expected %v, got %v", ErrUserAlreadyExist, err)
}
if err != ErrUserAlreadyExist {
t.Fatalf("expected %v, got %v", ErrUserAlreadyExist, err)
}
ua = &pb.AuthUserAddRequest{Name: ""}
_, err = as.UserAdd(ua) // add a user with empty name
if err != ErrUserEmpty {
as := NewAuthStore(b, tp)
err = enableAuthAndCreateRoot(as)
if err != nil {
t.Fatal(err)
}
old := as.Revision()
b.Close()
as.Close()
// no changes to commit
b2 := backend.NewDefaultBackend(tPath)
as = NewAuthStore(b2, tp)
new := as.Revision()
b2.Close()
as.Close()
if old != new {
t.Fatalf("expected revision %d, got %d", old, new)
}
}
func setupAuthStore(t *testing.T) (store *authStore, teardownfunc func(t *testing.T)) {
b, tPath := backend.NewDefaultTmpBackend()
tp, err := NewTokenProvider("simple", dummyIndexWaiter)
if err != nil {
t.Fatal(err)
}
as := NewAuthStore(b, tp)
err = enableAuthAndCreateRoot(as)
if err != nil {
t.Fatal(err)
}
// adds a new role
_, err = as.RoleAdd(&pb.AuthRoleAddRequest{Name: "role-test"})
if err != nil {
t.Fatal(err)
}
ua := &pb.AuthUserAddRequest{Name: "foo", Password: "bar"}
_, err = as.UserAdd(ua) // add a non-existing user
if err != nil {
t.Fatal(err)
}
tearDown := func(t *testing.T) {
b.Close()
os.Remove(tPath)
as.Close()
}
return as, tearDown
}
func enableAuthAndCreateRoot(as *authStore) error {
@ -73,28 +124,32 @@ func enableAuthAndCreateRoot(as *authStore) error {
return as.AuthEnable()
}
func TestUserAdd(t *testing.T) {
as, tearDown := setupAuthStore(t)
defer tearDown(t)
ua := &pb.AuthUserAddRequest{Name: "foo"}
_, err := as.UserAdd(ua) // add an existing user
if err == nil {
t.Fatalf("expected %v, got %v", ErrUserAlreadyExist, err)
}
if err != ErrUserAlreadyExist {
t.Fatalf("expected %v, got %v", ErrUserAlreadyExist, err)
}
ua = &pb.AuthUserAddRequest{Name: ""}
_, err = as.UserAdd(ua) // add a user with empty name
if err != ErrUserEmpty {
t.Fatal(err)
}
}
func TestCheckPassword(t *testing.T) {
b, tPath := backend.NewDefaultTmpBackend()
defer func() {
b.Close()
os.Remove(tPath)
}()
as := NewAuthStore(b)
defer as.Close()
err := enableAuthAndCreateRoot(as)
if err != nil {
t.Fatal(err)
}
ua := &pb.AuthUserAddRequest{Name: "foo", Password: "bar"}
_, err = as.UserAdd(ua)
if err != nil {
t.Fatal(err)
}
as, tearDown := setupAuthStore(t)
defer tearDown(t)
// auth a non-existing user
_, err = as.CheckPassword("foo-test", "bar")
_, err := as.CheckPassword("foo-test", "bar")
if err == nil {
t.Fatalf("expected %v, got %v", ErrAuthFailed, err)
}
@ -119,28 +174,12 @@ func TestCheckPassword(t *testing.T) {
}
func TestUserDelete(t *testing.T) {
b, tPath := backend.NewDefaultTmpBackend()
defer func() {
b.Close()
os.Remove(tPath)
}()
as := NewAuthStore(b)
defer as.Close()
err := enableAuthAndCreateRoot(as)
if err != nil {
t.Fatal(err)
}
ua := &pb.AuthUserAddRequest{Name: "foo"}
_, err = as.UserAdd(ua)
if err != nil {
t.Fatal(err)
}
as, tearDown := setupAuthStore(t)
defer tearDown(t)
// delete an existing user
ud := &pb.AuthUserDeleteRequest{Name: "foo"}
_, err = as.UserDelete(ud)
_, err := as.UserDelete(ud)
if err != nil {
t.Fatal(err)
}
@ -156,37 +195,22 @@ func TestUserDelete(t *testing.T) {
}
func TestUserChangePassword(t *testing.T) {
b, tPath := backend.NewDefaultTmpBackend()
defer func() {
b.Close()
os.Remove(tPath)
}()
as := NewAuthStore(b)
defer as.Close()
err := enableAuthAndCreateRoot(as)
if err != nil {
t.Fatal(err)
}
_, err = as.UserAdd(&pb.AuthUserAddRequest{Name: "foo"})
if err != nil {
t.Fatal(err)
}
as, tearDown := setupAuthStore(t)
defer tearDown(t)
ctx1 := context.WithValue(context.WithValue(context.TODO(), "index", uint64(1)), "simpleToken", "dummy")
_, err = as.Authenticate(ctx1, "foo", "")
_, err := as.Authenticate(ctx1, "foo", "bar")
if err != nil {
t.Fatal(err)
}
_, err = as.UserChangePassword(&pb.AuthUserChangePasswordRequest{Name: "foo", Password: "bar"})
_, err = as.UserChangePassword(&pb.AuthUserChangePasswordRequest{Name: "foo", Password: "baz"})
if err != nil {
t.Fatal(err)
}
ctx2 := context.WithValue(context.WithValue(context.TODO(), "index", uint64(2)), "simpleToken", "dummy")
_, err = as.Authenticate(ctx2, "foo", "bar")
_, err = as.Authenticate(ctx2, "foo", "baz")
if err != nil {
t.Fatal(err)
}
@ -202,53 +226,22 @@ func TestUserChangePassword(t *testing.T) {
}
func TestRoleAdd(t *testing.T) {
b, tPath := backend.NewDefaultTmpBackend()
defer func() {
b.Close()
os.Remove(tPath)
}()
as := NewAuthStore(b)
defer as.Close()
err := enableAuthAndCreateRoot(as)
if err != nil {
t.Fatal(err)
}
as, tearDown := setupAuthStore(t)
defer tearDown(t)
// adds a new role
_, err = as.RoleAdd(&pb.AuthRoleAddRequest{Name: "role-test"})
_, err := as.RoleAdd(&pb.AuthRoleAddRequest{Name: "role-test-1"})
if err != nil {
t.Fatal(err)
}
}
func TestUserGrant(t *testing.T) {
b, tPath := backend.NewDefaultTmpBackend()
defer func() {
b.Close()
os.Remove(tPath)
}()
as := NewAuthStore(b)
defer as.Close()
err := enableAuthAndCreateRoot(as)
if err != nil {
t.Fatal(err)
}
_, err = as.UserAdd(&pb.AuthUserAddRequest{Name: "foo"})
if err != nil {
t.Fatal(err)
}
// adds a new role
_, err = as.RoleAdd(&pb.AuthRoleAddRequest{Name: "role-test"})
if err != nil {
t.Fatal(err)
}
as, tearDown := setupAuthStore(t)
defer tearDown(t)
// grants a role to the user
_, err = as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "foo", Role: "role-test"})
_, err := as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "foo", Role: "role-test"})
if err != nil {
t.Fatal(err)
}
@ -256,9 +249,407 @@ func TestUserGrant(t *testing.T) {
// grants a role to a non-existing user
_, err = as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "foo-test", Role: "role-test"})
if err == nil {
t.Fatalf("expected %v, got %v", ErrUserNotFound, err)
t.Errorf("expected %v, got %v", ErrUserNotFound, err)
}
if err != ErrUserNotFound {
t.Fatalf("expected %v, got %v", ErrUserNotFound, err)
t.Errorf("expected %v, got %v", ErrUserNotFound, err)
}
}
func TestGetUser(t *testing.T) {
as, tearDown := setupAuthStore(t)
defer tearDown(t)
_, err := as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "foo", Role: "role-test"})
if err != nil {
t.Fatal(err)
}
u, err := as.UserGet(&pb.AuthUserGetRequest{Name: "foo"})
if err != nil {
t.Fatal(err)
}
if u == nil {
t.Fatal("expect user not nil, got nil")
}
expected := []string{"role-test"}
if !reflect.DeepEqual(expected, u.Roles) {
t.Errorf("expected %v, got %v", expected, u.Roles)
}
}
func TestListUsers(t *testing.T) {
as, tearDown := setupAuthStore(t)
defer tearDown(t)
ua := &pb.AuthUserAddRequest{Name: "user1", Password: "pwd1"}
_, err := as.UserAdd(ua) // add a non-existing user
if err != nil {
t.Fatal(err)
}
ul, err := as.UserList(&pb.AuthUserListRequest{})
if err != nil {
t.Fatal(err)
}
if !contains(ul.Users, "root") {
t.Errorf("expected %v in %v", "root", ul.Users)
}
if !contains(ul.Users, "user1") {
t.Errorf("expected %v in %v", "user1", ul.Users)
}
}
func TestRoleGrantPermission(t *testing.T) {
as, tearDown := setupAuthStore(t)
defer tearDown(t)
_, err := as.RoleAdd(&pb.AuthRoleAddRequest{Name: "role-test-1"})
if err != nil {
t.Fatal(err)
}
perm := &authpb.Permission{
PermType: authpb.WRITE,
Key: []byte("Keys"),
RangeEnd: []byte("RangeEnd"),
}
_, err = as.RoleGrantPermission(&pb.AuthRoleGrantPermissionRequest{
Name: "role-test-1",
Perm: perm,
})
if err != nil {
t.Error(err)
}
r, err := as.RoleGet(&pb.AuthRoleGetRequest{Role: "role-test-1"})
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(perm, r.Perm[0]) {
t.Errorf("expected %v, got %v", perm, r.Perm[0])
}
}
func TestRoleRevokePermission(t *testing.T) {
as, tearDown := setupAuthStore(t)
defer tearDown(t)
_, err := as.RoleAdd(&pb.AuthRoleAddRequest{Name: "role-test-1"})
if err != nil {
t.Fatal(err)
}
perm := &authpb.Permission{
PermType: authpb.WRITE,
Key: []byte("Keys"),
RangeEnd: []byte("RangeEnd"),
}
_, err = as.RoleGrantPermission(&pb.AuthRoleGrantPermissionRequest{
Name: "role-test-1",
Perm: perm,
})
if err != nil {
t.Fatal(err)
}
_, err = as.RoleGet(&pb.AuthRoleGetRequest{Role: "role-test-1"})
if err != nil {
t.Fatal(err)
}
_, err = as.RoleRevokePermission(&pb.AuthRoleRevokePermissionRequest{
Role: "role-test-1",
Key: "Keys",
RangeEnd: "RangeEnd",
})
if err != nil {
t.Fatal(err)
}
var r *pb.AuthRoleGetResponse
r, err = as.RoleGet(&pb.AuthRoleGetRequest{Role: "role-test-1"})
if err != nil {
t.Fatal(err)
}
if len(r.Perm) != 0 {
t.Errorf("expected %v, got %v", 0, len(r.Perm))
}
}
func TestUserRevokePermission(t *testing.T) {
as, tearDown := setupAuthStore(t)
defer tearDown(t)
_, err := as.RoleAdd(&pb.AuthRoleAddRequest{Name: "role-test-1"})
if err != nil {
t.Fatal(err)
}
_, err = as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "foo", Role: "role-test"})
if err != nil {
t.Fatal(err)
}
_, err = as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "foo", Role: "role-test-1"})
if err != nil {
t.Fatal(err)
}
u, err := as.UserGet(&pb.AuthUserGetRequest{Name: "foo"})
if err != nil {
t.Fatal(err)
}
expected := []string{"role-test", "role-test-1"}
if !reflect.DeepEqual(expected, u.Roles) {
t.Fatalf("expected %v, got %v", expected, u.Roles)
}
_, err = as.UserRevokeRole(&pb.AuthUserRevokeRoleRequest{Name: "foo", Role: "role-test-1"})
if err != nil {
t.Fatal(err)
}
u, err = as.UserGet(&pb.AuthUserGetRequest{Name: "foo"})
if err != nil {
t.Fatal(err)
}
expected = []string{"role-test"}
if !reflect.DeepEqual(expected, u.Roles) {
t.Errorf("expected %v, got %v", expected, u.Roles)
}
}
func TestRoleDelete(t *testing.T) {
as, tearDown := setupAuthStore(t)
defer tearDown(t)
_, err := as.RoleDelete(&pb.AuthRoleDeleteRequest{Role: "role-test"})
if err != nil {
t.Fatal(err)
}
rl, err := as.RoleList(&pb.AuthRoleListRequest{})
if err != nil {
t.Fatal(err)
}
expected := []string{"root"}
if !reflect.DeepEqual(expected, rl.Roles) {
t.Errorf("expected %v, got %v", expected, rl.Roles)
}
}
func TestAuthInfoFromCtx(t *testing.T) {
as, tearDown := setupAuthStore(t)
defer tearDown(t)
ctx := context.Background()
ai, err := as.AuthInfoFromCtx(ctx)
if err != nil && ai != nil {
t.Errorf("expected (nil, nil), got (%v, %v)", ai, err)
}
ctx = metadata.NewContext(context.Background(), metadata.New(map[string]string{"tokens": "dummy"}))
ai, err = as.AuthInfoFromCtx(ctx)
if err != nil && ai != nil {
t.Errorf("expected (nil, nil), got (%v, %v)", ai, err)
}
ctx = context.WithValue(context.WithValue(context.TODO(), "index", uint64(1)), "simpleToken", "dummy")
resp, err := as.Authenticate(ctx, "foo", "bar")
if err != nil {
t.Error(err)
}
ctx = metadata.NewContext(context.Background(), metadata.New(map[string]string{"token": "Invalid Token"}))
_, err = as.AuthInfoFromCtx(ctx)
if err != ErrInvalidAuthToken {
t.Errorf("expected %v, got %v", ErrInvalidAuthToken, err)
}
ctx = metadata.NewContext(context.Background(), metadata.New(map[string]string{"token": "Invalid.Token"}))
_, err = as.AuthInfoFromCtx(ctx)
if err != ErrInvalidAuthToken {
t.Errorf("expected %v, got %v", ErrInvalidAuthToken, err)
}
ctx = metadata.NewContext(context.Background(), metadata.New(map[string]string{"token": resp.Token}))
ai, err = as.AuthInfoFromCtx(ctx)
if err != nil {
t.Error(err)
}
if ai.Username != "foo" {
t.Errorf("expected %v, got %v", "foo", ai.Username)
}
}
func TestAuthDisable(t *testing.T) {
as, tearDown := setupAuthStore(t)
defer tearDown(t)
as.AuthDisable()
ctx := context.WithValue(context.WithValue(context.TODO(), "index", uint64(2)), "simpleToken", "dummy")
_, err := as.Authenticate(ctx, "foo", "bar")
if err != ErrAuthNotEnabled {
t.Errorf("expected %v, got %v", ErrAuthNotEnabled, err)
}
// Disabling disabled auth to make sure it can return safely if store is already disabled.
as.AuthDisable()
_, err = as.Authenticate(ctx, "foo", "bar")
if err != ErrAuthNotEnabled {
t.Errorf("expected %v, got %v", ErrAuthNotEnabled, err)
}
}
// TestAuthRevisionRace ensures that access to authStore.revision is thread-safe.
func TestAuthInfoFromCtxRace(t *testing.T) {
b, tPath := backend.NewDefaultTmpBackend()
defer os.Remove(tPath)
tp, err := NewTokenProvider("simple", dummyIndexWaiter)
if err != nil {
t.Fatal(err)
}
as := NewAuthStore(b, tp)
defer as.Close()
donec := make(chan struct{})
go func() {
defer close(donec)
ctx := metadata.NewContext(context.Background(), metadata.New(map[string]string{"token": "test"}))
as.AuthInfoFromCtx(ctx)
}()
as.UserAdd(&pb.AuthUserAddRequest{Name: "test"})
<-donec
}
func TestIsAdminPermitted(t *testing.T) {
as, tearDown := setupAuthStore(t)
defer tearDown(t)
err := as.IsAdminPermitted(&AuthInfo{Username: "root", Revision: 1})
if err != nil {
t.Errorf("expected nil, got %v", err)
}
// invalid user
err = as.IsAdminPermitted(&AuthInfo{Username: "rooti", Revision: 1})
if err != ErrUserNotFound {
t.Errorf("expected %v, got %v", ErrUserNotFound, err)
}
// non-admin user
err = as.IsAdminPermitted(&AuthInfo{Username: "foo", Revision: 1})
if err != ErrPermissionDenied {
t.Errorf("expected %v, got %v", ErrPermissionDenied, err)
}
// disabled auth should return nil
as.AuthDisable()
err = as.IsAdminPermitted(&AuthInfo{Username: "root", Revision: 1})
if err != nil {
t.Errorf("expected nil, got %v", err)
}
}
func TestRecoverFromSnapshot(t *testing.T) {
as, _ := setupAuthStore(t)
ua := &pb.AuthUserAddRequest{Name: "foo"}
_, err := as.UserAdd(ua) // add an existing user
if err == nil {
t.Fatalf("expected %v, got %v", ErrUserAlreadyExist, err)
}
if err != ErrUserAlreadyExist {
t.Fatalf("expected %v, got %v", ErrUserAlreadyExist, err)
}
ua = &pb.AuthUserAddRequest{Name: ""}
_, err = as.UserAdd(ua) // add a user with empty name
if err != ErrUserEmpty {
t.Fatal(err)
}
as.Close()
tp, err := NewTokenProvider("simple", dummyIndexWaiter)
if err != nil {
t.Fatal(err)
}
as2 := NewAuthStore(as.be, tp)
defer func(a *authStore) {
a.Close()
}(as2)
if !as2.isAuthEnabled() {
t.Fatal("recovering authStore from existing backend failed")
}
ul, err := as.UserList(&pb.AuthUserListRequest{})
if err != nil {
t.Fatal(err)
}
if !contains(ul.Users, "root") {
t.Errorf("expected %v in %v", "root", ul.Users)
}
}
func contains(array []string, str string) bool {
for _, s := range array {
if s == str {
return true
}
}
return false
}
func TestHammerSimpleAuthenticate(t *testing.T) {
// set TTL values low to try to trigger races
oldTTL, oldTTLRes := simpleTokenTTL, simpleTokenTTLResolution
defer func() {
simpleTokenTTL = oldTTL
simpleTokenTTLResolution = oldTTLRes
}()
simpleTokenTTL = 10 * time.Millisecond
simpleTokenTTLResolution = simpleTokenTTL
users := make(map[string]struct{})
as, tearDown := setupAuthStore(t)
defer tearDown(t)
// create lots of users
for i := 0; i < 50; i++ {
u := fmt.Sprintf("user-%d", i)
ua := &pb.AuthUserAddRequest{Name: u, Password: "123"}
if _, err := as.UserAdd(ua); err != nil {
t.Fatal(err)
}
users[u] = struct{}{}
}
// hammer on authenticate with lots of users
for i := 0; i < 10; i++ {
var wg sync.WaitGroup
wg.Add(len(users))
for u := range users {
go func(user string) {
defer wg.Done()
token := fmt.Sprintf("%s(%d)", user, i)
ctx := context.WithValue(context.WithValue(context.TODO(), "index", uint64(1)), "simpleToken", token)
if _, err := as.Authenticate(ctx, user, "123"); err != nil {
t.Fatal(err)
}
if _, err := as.AuthInfoFromCtx(ctx); err != nil {
t.Fatal(err)
}
}(u)
}
time.Sleep(time.Millisecond)
wg.Wait()
}
}

207
bill-of-materials.json Normal file
View File

@ -0,0 +1,207 @@
[
{
"project": "bitbucket.org/ww/goautoneg",
"license": "BSD 3-clause \"New\" or \"Revised\" License",
"confidence": 1
},
{
"project": "github.com/beorn7/perks/quantile",
"license": "MIT License",
"confidence": 0.989
},
{
"project": "github.com/bgentry/speakeasy",
"license": "MIT License",
"confidence": 0.944
},
{
"project": "github.com/boltdb/bolt",
"license": "MIT License",
"confidence": 1
},
{
"project": "github.com/cockroachdb/cmux",
"license": "Apache License 2.0",
"confidence": 1
},
{
"project": "github.com/coreos/etcd",
"license": "Apache License 2.0",
"confidence": 1
},
{
"project": "github.com/coreos/go-semver/semver",
"license": "Apache License 2.0",
"confidence": 1
},
{
"project": "github.com/coreos/go-systemd",
"license": "Apache License 2.0",
"confidence": 0.997
},
{
"project": "github.com/coreos/pkg",
"license": "Apache License 2.0",
"confidence": 1
},
{
"project": "github.com/cpuguy83/go-md2man/md2man",
"license": "MIT License",
"confidence": 1
},
{
"project": "github.com/dgrijalva/jwt-go",
"license": "MIT License",
"confidence": 0.989
},
{
"project": "github.com/dustin/go-humanize",
"license": "MIT License",
"confidence": 0.969
},
{
"project": "github.com/ghodss/yaml",
"license": "MIT License and BSD 3-clause \"New\" or \"Revised\" License",
"confidence": 1
},
{
"project": "github.com/gogo/protobuf/proto",
"license": "BSD 3-clause \"New\" or \"Revised\" License",
"confidence": 0.909
},
{
"project": "github.com/golang/groupcache/lru",
"license": "Apache License 2.0",
"confidence": 0.997
},
{
"project": "github.com/golang/protobuf",
"license": "BSD 3-clause \"New\" or \"Revised\" License",
"confidence": 0.92
},
{
"project": "github.com/google/btree",
"license": "Apache License 2.0",
"confidence": 1
},
{
"project": "github.com/grpc-ecosystem/go-grpc-prometheus",
"license": "Apache License 2.0",
"confidence": 1
},
{
"project": "github.com/grpc-ecosystem/grpc-gateway",
"license": "BSD 3-clause \"New\" or \"Revised\" License",
"confidence": 0.979
},
{
"project": "github.com/inconshreveable/mousetrap",
"license": "Apache License 2.0",
"confidence": 1
},
{
"project": "github.com/jonboulle/clockwork",
"license": "Apache License 2.0",
"confidence": 1
},
{
"project": "github.com/mattn/go-runewidth",
"license": "MIT License",
"confidence": 1
},
{
"project": "github.com/matttproud/golang_protobuf_extensions/pbutil",
"license": "Apache License 2.0",
"confidence": 1
},
{
"project": "github.com/olekukonko/tablewriter",
"license": "MIT License",
"confidence": 0.989
},
{
"project": "github.com/prometheus/client_golang/prometheus",
"license": "Apache License 2.0",
"confidence": 1
},
{
"project": "github.com/prometheus/client_model/go",
"license": "Apache License 2.0",
"confidence": 1
},
{
"project": "github.com/prometheus/common",
"license": "Apache License 2.0",
"confidence": 1
},
{
"project": "github.com/prometheus/procfs",
"license": "Apache License 2.0",
"confidence": 1
},
{
"project": "github.com/russross/blackfriday",
"license": "BSD 2-clause \"Simplified\" License",
"confidence": 0.963
},
{
"project": "github.com/spf13/cobra",
"license": "Apache License 2.0",
"confidence": 0.957
},
{
"project": "github.com/spf13/pflag",
"license": "BSD 3-clause \"New\" or \"Revised\" License",
"confidence": 0.966
},
{
"project": "github.com/ugorji/go/codec",
"license": "MIT License",
"confidence": 0.995
},
{
"project": "github.com/urfave/cli",
"license": "MIT License",
"confidence": 1
},
{
"project": "github.com/xiang90/probing",
"license": "MIT License",
"confidence": 1
},
{
"project": "golang.org/x/crypto",
"license": "BSD 3-clause \"New\" or \"Revised\" License",
"confidence": 0.966
},
{
"project": "golang.org/x/net",
"license": "BSD 3-clause \"New\" or \"Revised\" License",
"confidence": 0.966
},
{
"project": "golang.org/x/text",
"license": "BSD 3-clause \"New\" or \"Revised\" License",
"confidence": 0.966
},
{
"project": "golang.org/x/time/rate",
"license": "BSD 3-clause \"New\" or \"Revised\" License",
"confidence": 0.966
},
{
"project": "google.golang.org/grpc",
"license": "BSD 3-clause \"New\" or \"Revised\" License",
"confidence": 0.979
},
{
"project": "gopkg.in/cheggaaa/pb.v1",
"license": "BSD 3-clause \"New\" or \"Revised\" License",
"confidence": 0.992
},
{
"project": "gopkg.in/yaml.v2",
"license": "Apache License 2.0 and MIT License",
"confidence": 1
}
]

View File

@ -0,0 +1,18 @@
[
{
"project": "bitbucket.org/ww/goautoneg",
"license": "BSD 3-clause \"New\" or \"Revised\" License"
},
{
"project": "github.com/ghodss/yaml",
"license": "MIT License and BSD 3-clause \"New\" or \"Revised\" License"
},
{
"project": "github.com/inconshreveable/mousetrap",
"license": "Apache License 2.0"
},
{
"project": "gopkg.in/yaml.v2",
"license": "Apache License 2.0 and MIT License"
}
]

23
build
View File

@ -3,9 +3,7 @@
# set some environment variables
ORG_PATH="github.com/coreos"
REPO_PATH="${ORG_PATH}/etcd"
export GO15VENDOREXPERIMENT="1"
eval $(go env)
GIT_SHA=`git rev-parse --short HEAD || echo "GitNotFound"`
if [ ! -z "$FAILPOINTS" ]; then
GIT_SHA="$GIT_SHA"-FAILPOINTS
@ -17,11 +15,7 @@ GO_LDFLAGS="$GO_LDFLAGS -X ${REPO_PATH}/cmd/vendor/${REPO_PATH}/version.GitSHA=$
# enable/disable failpoints
toggle_failpoints() {
FAILPKGS="etcdserver/ mvcc/backend/"
mode="disable"
if [ ! -z "$FAILPOINTS" ]; then mode="enable"; fi
if [ ! -z "$1" ]; then mode="$1"; fi
mode="$1"
if which gofail >/dev/null 2>&1; then
gofail "$mode" $FAILPKGS
elif [ "$mode" != "disable" ]; then
@ -30,19 +24,26 @@ toggle_failpoints() {
fi
}
toggle_failpoints_default() {
mode="disable"
if [ ! -z "$FAILPOINTS" ]; then mode="enable"; fi
toggle_failpoints "$mode"
}
etcd_build() {
out="bin"
if [ -n "${BINDIR}" ]; then out="${BINDIR}"; fi
toggle_failpoints
toggle_failpoints_default
# Static compilation is useful when etcd is run in a container
CGO_ENABLED=0 go build $GO_BUILD_FLAGS -installsuffix cgo -ldflags "$GO_LDFLAGS" -o ${out}/etcd ${REPO_PATH}/cmd/etcd || return
CGO_ENABLED=0 go build $GO_BUILD_FLAGS -installsuffix cgo -ldflags "$GO_LDFLAGS" -o ${out}/etcdctl ${REPO_PATH}/cmd/etcdctl || return
}
etcd_setup_gopath() {
CDIR=$(cd `dirname "$0"` && pwd)
d=$(dirname "$0")
CDIR=$(cd "$d" && pwd)
cd "$CDIR"
etcdGOPATH=${CDIR}/gopath
etcdGOPATH="${CDIR}/gopath"
# preserve old gopath to support building with unvendored tooling deps (e.g., gofail)
if [ -n "$GOPATH" ]; then
GOPATH=":$GOPATH"
@ -53,7 +54,7 @@ etcd_setup_gopath() {
ln -s ${CDIR}/cmd/vendor ${etcdGOPATH}/src
}
toggle_failpoints
toggle_failpoints_default
# only build when called directly, not sourced
if echo "$0" | grep "build$" >/dev/null; then

View File

@ -15,6 +15,7 @@
package client
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
@ -27,6 +28,8 @@ import (
"sync"
"time"
"github.com/coreos/etcd/version"
"golang.org/x/net/context"
)
@ -201,6 +204,9 @@ type Client interface {
// returned
SetEndpoints(eps []string) error
// GetVersion retrieves the current etcd server and cluster version
GetVersion(ctx context.Context) (*version.Versions, error)
httpClient
}
@ -477,6 +483,33 @@ func (c *httpClusterClient) AutoSync(ctx context.Context, interval time.Duration
}
}
func (c *httpClusterClient) GetVersion(ctx context.Context) (*version.Versions, error) {
act := &getAction{Prefix: "/version"}
resp, body, err := c.Do(ctx, act)
if err != nil {
return nil, err
}
switch resp.StatusCode {
case http.StatusOK:
if len(body) == 0 {
return nil, ErrEmptyBody
}
var vresp version.Versions
if err := json.Unmarshal(body, &vresp); err != nil {
return nil, ErrInvalidJSON
}
return &vresp, nil
default:
var etcdErr Error
if err := json.Unmarshal(body, &etcdErr); err != nil {
return nil, ErrInvalidJSON
}
return nil, etcdErr
}
}
type roundTripResponse struct {
resp *http.Response
err error

View File

@ -28,6 +28,7 @@ import (
"time"
"github.com/coreos/etcd/pkg/testutil"
"github.com/coreos/etcd/version"
"golang.org/x/net/context"
)
@ -860,6 +861,34 @@ func TestHTTPClusterClientAutoSyncFail(t *testing.T) {
}
}
func TestHTTPClusterClientGetVersion(t *testing.T) {
body := []byte(`{"etcdserver":"2.3.2","etcdcluster":"2.3.0"}`)
cf := newStaticHTTPClientFactory([]staticHTTPResponse{
{
resp: http.Response{StatusCode: http.StatusOK, Header: http.Header{"Content-Length": []string{"44"}}},
body: body,
},
})
hc := &httpClusterClient{
clientFactory: cf,
rand: rand.New(rand.NewSource(0)),
}
err := hc.SetEndpoints([]string{"http://127.0.0.1:4003", "http://127.0.0.1:2379", "http://127.0.0.1:4001", "http://127.0.0.1:4002"})
if err != nil {
t.Fatalf("unexpected error during setup: %#v", err)
}
actual, err := hc.GetVersion(context.Background())
if err != nil {
t.Errorf("non-nil error: %#v", err)
}
expected := version.Versions{Server: "2.3.2", Cluster: "2.3.0"}
if !reflect.DeepEqual(&expected, actual) {
t.Errorf("incorrect Response: want=%#v got=%#v", expected, actual)
}
}
// TestHTTPClusterClientSyncPinEndpoint tests that Sync() pins the endpoint when
// it gets the exactly same member list as before.
func TestHTTPClusterClientSyncPinEndpoint(t *testing.T) {

View File

@ -14,8 +14,27 @@
package client
import (
"github.com/coreos/etcd/pkg/srv"
)
// Discoverer is an interface that wraps the Discover method.
type Discoverer interface {
// Discover looks up the etcd servers for the domain.
Discover(domain string) ([]string, error)
}
type srvDiscover struct{}
// NewSRVDiscover constructs a new Discoverer that uses the stdlib to lookup SRV records.
func NewSRVDiscover() Discoverer {
return &srvDiscover{}
}
func (d *srvDiscover) Discover(domain string) ([]string, error) {
srvs, err := srv.GetClient("etcd-client", domain)
if err != nil {
return nil, err
}
return srvs.Endpoints, nil
}

View File

@ -34,7 +34,7 @@ import (
func TestV2NoRetryEOF(t *testing.T) {
defer testutil.AfterTest(t)
// generate an EOF response; specify address so appears first in sorted ep list
lEOF := integration.NewListenerWithAddr(t, fmt.Sprintf("eof:123.%d.sock", os.Getpid()))
lEOF := integration.NewListenerWithAddr(t, fmt.Sprintf("127.0.0.1:%05d", os.Getpid()))
defer lEOF.Close()
tries := uint32(0)
go func() {
@ -65,8 +65,7 @@ func TestV2NoRetryEOF(t *testing.T) {
// TestV2NoRetryNoLeader tests destructive api calls won't retry if given an error code.
func TestV2NoRetryNoLeader(t *testing.T) {
defer testutil.AfterTest(t)
lHttp := integration.NewListenerWithAddr(t, fmt.Sprintf("errHttp:123.%d.sock", os.Getpid()))
lHttp := integration.NewListenerWithAddr(t, fmt.Sprintf("127.0.0.1:%05d", os.Getpid()))
eh := &errHandler{errCode: http.StatusServiceUnavailable}
srv := httptest.NewUnstartedServer(eh)
defer lHttp.Close()

View File

@ -1,65 +0,0 @@
// Copyright 2015 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package client
import (
"fmt"
"net"
"net/url"
)
var (
// indirection for testing
lookupSRV = net.LookupSRV
)
type srvDiscover struct{}
// NewSRVDiscover constructs a new Discoverer that uses the stdlib to lookup SRV records.
func NewSRVDiscover() Discoverer {
return &srvDiscover{}
}
// Discover looks up the etcd servers for the domain.
func (d *srvDiscover) Discover(domain string) ([]string, error) {
var urls []*url.URL
updateURLs := func(service, scheme string) error {
_, addrs, err := lookupSRV(service, "tcp", domain)
if err != nil {
return err
}
for _, srv := range addrs {
urls = append(urls, &url.URL{
Scheme: scheme,
Host: net.JoinHostPort(srv.Target, fmt.Sprintf("%d", srv.Port)),
})
}
return nil
}
errHTTPS := updateURLs("etcd-client-ssl", "https")
errHTTP := updateURLs("etcd-client", "http")
if errHTTPS != nil && errHTTP != nil {
return nil, fmt.Errorf("dns lookup errors: %s and %s", errHTTPS, errHTTP)
}
endpoints := make([]string, len(urls))
for i := range urls {
endpoints[i] = urls[i].String()
}
return endpoints, nil
}

View File

@ -1,102 +0,0 @@
// Copyright 2015 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package client
import (
"errors"
"net"
"reflect"
"testing"
)
func TestSRVDiscover(t *testing.T) {
defer func() { lookupSRV = net.LookupSRV }()
tests := []struct {
withSSL []*net.SRV
withoutSSL []*net.SRV
expected []string
}{
{
[]*net.SRV{},
[]*net.SRV{},
[]string{},
},
{
[]*net.SRV{
{Target: "10.0.0.1", Port: 2480},
{Target: "10.0.0.2", Port: 2480},
{Target: "10.0.0.3", Port: 2480},
},
[]*net.SRV{},
[]string{"https://10.0.0.1:2480", "https://10.0.0.2:2480", "https://10.0.0.3:2480"},
},
{
[]*net.SRV{
{Target: "10.0.0.1", Port: 2480},
{Target: "10.0.0.2", Port: 2480},
{Target: "10.0.0.3", Port: 2480},
},
[]*net.SRV{
{Target: "10.0.0.1", Port: 7001},
},
[]string{"https://10.0.0.1:2480", "https://10.0.0.2:2480", "https://10.0.0.3:2480", "http://10.0.0.1:7001"},
},
{
[]*net.SRV{
{Target: "10.0.0.1", Port: 2480},
{Target: "10.0.0.2", Port: 2480},
{Target: "10.0.0.3", Port: 2480},
},
[]*net.SRV{
{Target: "10.0.0.1", Port: 7001},
},
[]string{"https://10.0.0.1:2480", "https://10.0.0.2:2480", "https://10.0.0.3:2480", "http://10.0.0.1:7001"},
},
{
[]*net.SRV{
{Target: "a.example.com", Port: 2480},
{Target: "b.example.com", Port: 2480},
{Target: "c.example.com", Port: 2480},
},
[]*net.SRV{},
[]string{"https://a.example.com:2480", "https://b.example.com:2480", "https://c.example.com:2480"},
},
}
for i, tt := range tests {
lookupSRV = func(service string, proto string, domain string) (string, []*net.SRV, error) {
if service == "etcd-client-ssl" {
return "", tt.withSSL, nil
}
if service == "etcd-client" {
return "", tt.withoutSSL, nil
}
return "", nil, errors.New("Unknown service in mock")
}
d := NewSRVDiscover()
endpoints, err := d.Discover("example.com")
if err != nil {
t.Fatalf("%d: err: %#v", i, err)
}
if !reflect.DeepEqual(endpoints, tt.expected) {
t.Errorf("#%d: endpoints = %v, want %v", i, endpoints, tt.expected)
}
}
}

View File

@ -32,7 +32,7 @@ pass `context.WithTimeout` to APIs:
```go
ctx, cancel := context.WithTimeout(context.Background(), timeout)
resp, err := kvc.Put(ctx, "sample_key", "sample_value")
resp, err := cli.Put(ctx, "sample_key", "sample_value")
cancel()
if err != nil {
// handle error!
@ -57,7 +57,7 @@ etcd client returns 2 types of errors:
Here is the example code to handle client errors:
```go
resp, err := kvc.Put(ctx, "", "")
resp, err := cli.Put(ctx, "", "")
if err != nil {
switch err {
case context.Canceled:
@ -76,6 +76,10 @@ if err != nil {
The etcd client optionally exposes RPC metrics through [go-grpc-prometheus](https://github.com/grpc-ecosystem/go-grpc-prometheus). See the [examples](https://github.com/coreos/etcd/blob/master/clientv3/example_metrics_test.go).
## Namespacing
The [namespace](https://godoc.org/github.com/coreos/etcd/clientv3/namespace) package provides `clientv3` interface wrappers to transparently isolate client requests to a user-defined prefix.
## Examples
More code examples can be found at [GoDoc](https://godoc.org/github.com/coreos/etcd/clientv3).

View File

@ -100,19 +100,11 @@ type Auth interface {
}
type auth struct {
c *Client
conn *grpc.ClientConn // conn in-use
remote pb.AuthClient
}
func NewAuth(c *Client) Auth {
conn := c.ActiveConnection()
return &auth{
conn: c.ActiveConnection(),
remote: pb.NewAuthClient(conn),
c: c,
}
return &auth{remote: pb.NewAuthClient(c.ActiveConnection())}
}
func (auth *auth) AuthEnable(ctx context.Context) (*AuthEnableResponse, error) {

View File

@ -43,11 +43,22 @@ type simpleBalancer struct {
// mu protects upEps, pinAddr, and connectingAddr
mu sync.RWMutex
// upEps holds the current endpoints that have an active connection
upEps map[string]struct{}
// upc closes when upEps transitions from empty to non-zero or the balancer closes.
upc chan struct{}
// downc closes when grpc calls down() on pinAddr
downc chan struct{}
// stopc is closed to signal updateNotifyLoop should stop.
stopc chan struct{}
// donec closes when all goroutines are exited
donec chan struct{}
// updateAddrsC notifies updateNotifyLoop to update addrs.
updateAddrsC chan struct{}
// grpc issues TLS cert checks using the string passed into dial so
// that string must be the host. To recover the full scheme://host URL,
// have a map from hosts to the original endpoint.
@ -66,15 +77,19 @@ func newSimpleBalancer(eps []string) *simpleBalancer {
for i := range eps {
addrs[i].Addr = getHost(eps[i])
}
notifyCh <- addrs
sb := &simpleBalancer{
addrs: addrs,
notifyCh: notifyCh,
readyc: make(chan struct{}),
upEps: make(map[string]struct{}),
upc: make(chan struct{}),
host2ep: getHost2ep(eps),
addrs: addrs,
notifyCh: notifyCh,
readyc: make(chan struct{}),
upc: make(chan struct{}),
stopc: make(chan struct{}),
downc: make(chan struct{}),
donec: make(chan struct{}),
updateAddrsC: make(chan struct{}, 1),
host2ep: getHost2ep(eps),
}
close(sb.downc)
go sb.updateNotifyLoop()
return sb
}
@ -105,7 +120,6 @@ func (b *simpleBalancer) updateAddrs(eps []string) {
np := getHost2ep(eps)
b.mu.Lock()
defer b.mu.Unlock()
match := len(np) == len(b.host2ep)
for k, v := range np {
@ -116,6 +130,7 @@ func (b *simpleBalancer) updateAddrs(eps []string) {
}
if match {
// same endpoints, so no need to update address
b.mu.Unlock()
return
}
@ -126,7 +141,92 @@ func (b *simpleBalancer) updateAddrs(eps []string) {
addrs = append(addrs, grpc.Address{Addr: getHost(eps[i])})
}
b.addrs = addrs
b.notifyCh <- addrs
// updating notifyCh can trigger new connections,
// only update addrs if all connections are down
// or addrs does not include pinAddr.
update := !hasAddr(addrs, b.pinAddr)
b.mu.Unlock()
if update {
select {
case b.updateAddrsC <- struct{}{}:
case <-b.stopc:
}
}
}
func hasAddr(addrs []grpc.Address, targetAddr string) bool {
for _, addr := range addrs {
if targetAddr == addr.Addr {
return true
}
}
return false
}
func (b *simpleBalancer) updateNotifyLoop() {
defer close(b.donec)
for {
b.mu.RLock()
upc, downc, addr := b.upc, b.downc, b.pinAddr
b.mu.RUnlock()
// downc or upc should be closed
select {
case <-downc:
downc = nil
default:
}
select {
case <-upc:
upc = nil
default:
}
switch {
case downc == nil && upc == nil:
// stale
select {
case <-b.stopc:
return
default:
}
case downc == nil:
b.notifyAddrs()
select {
case <-upc:
case <-b.updateAddrsC:
b.notifyAddrs()
case <-b.stopc:
return
}
case upc == nil:
select {
// close connections that are not the pinned address
case b.notifyCh <- []grpc.Address{{Addr: addr}}:
case <-downc:
case <-b.stopc:
return
}
select {
case <-downc:
case <-b.updateAddrsC:
case <-b.stopc:
return
}
b.notifyAddrs()
}
}
}
func (b *simpleBalancer) notifyAddrs() {
b.mu.RLock()
addrs := b.addrs
b.mu.RUnlock()
select {
case b.notifyCh <- addrs:
case <-b.stopc:
}
}
func (b *simpleBalancer) Up(addr grpc.Address) func(error) {
@ -139,49 +239,46 @@ func (b *simpleBalancer) Up(addr grpc.Address) func(error) {
if b.closed {
return func(err error) {}
}
if len(b.upEps) == 0 {
// notify waiting Get()s and pin first connected address
close(b.upc)
b.pinAddr = addr.Addr
// gRPC might call Up on a stale address.
// Prevent updating pinAddr with a stale address.
if !hasAddr(b.addrs, addr.Addr) {
return func(err error) {}
}
b.upEps[addr.Addr] = struct{}{}
if b.pinAddr != "" {
return func(err error) {}
}
// notify waiting Get()s and pin first connected address
close(b.upc)
b.downc = make(chan struct{})
b.pinAddr = addr.Addr
// notify client that a connection is up
b.readyOnce.Do(func() { close(b.readyc) })
return func(err error) {
b.mu.Lock()
delete(b.upEps, addr.Addr)
if len(b.upEps) == 0 && b.pinAddr != "" {
b.upc = make(chan struct{})
} else if b.pinAddr == addr.Addr {
// choose new random up endpoint
for k := range b.upEps {
b.pinAddr = k
break
}
}
b.upc = make(chan struct{})
close(b.downc)
b.pinAddr = ""
b.mu.Unlock()
}
}
func (b *simpleBalancer) Get(ctx context.Context, opts grpc.BalancerGetOptions) (grpc.Address, func(), error) {
var addr string
var (
addr string
closed bool
)
// If opts.BlockingWait is false (for fail-fast RPCs), it should return
// an address it has notified via Notify immediately instead of blocking.
if !opts.BlockingWait {
b.mu.RLock()
closed := b.closed
closed = b.closed
addr = b.pinAddr
upEps := len(b.upEps)
b.mu.RUnlock()
if closed {
return grpc.Address{Addr: ""}, nil, grpc.ErrClientConnClosing
}
if upEps == 0 {
if addr == "" {
return grpc.Address{Addr: ""}, nil, ErrNoAddrAvilable
}
return grpc.Address{Addr: addr}, func() {}, nil
@ -193,17 +290,20 @@ func (b *simpleBalancer) Get(ctx context.Context, opts grpc.BalancerGetOptions)
b.mu.RUnlock()
select {
case <-ch:
case <-b.donec:
return grpc.Address{Addr: ""}, nil, grpc.ErrClientConnClosing
case <-ctx.Done():
return grpc.Address{Addr: ""}, nil, ctx.Err()
}
b.mu.RLock()
closed = b.closed
addr = b.pinAddr
upEps := len(b.upEps)
b.mu.RUnlock()
if addr == "" {
// Close() which sets b.closed = true can be called before Get(), Get() must exit if balancer is closed.
if closed {
return grpc.Address{Addr: ""}, nil, grpc.ErrClientConnClosing
}
if upEps > 0 {
if addr != "" {
break
}
}
@ -214,19 +314,36 @@ func (b *simpleBalancer) Notify() <-chan []grpc.Address { return b.notifyCh }
func (b *simpleBalancer) Close() error {
b.mu.Lock()
defer b.mu.Unlock()
// In case gRPC calls close twice. TODO: remove the checking
// when we are sure that gRPC wont call close twice.
if b.closed {
b.mu.Unlock()
<-b.donec
return nil
}
b.closed = true
close(b.notifyCh)
// terminate all waiting Get()s
close(b.stopc)
b.pinAddr = ""
if len(b.upEps) == 0 {
// In the case of following scenario:
// 1. upc is not closed; no pinned address
// 2. client issues an rpc, calling invoke(), which calls Get(), enters for loop, blocks
// 3. clientconn.Close() calls balancer.Close(); closed = true
// 4. for loop in Get() never exits since ctx is the context passed in by the client and may not be canceled
// we must close upc so Get() exits from blocking on upc
select {
case <-b.upc:
default:
// terminate all waiting Get()s
close(b.upc)
}
b.mu.Unlock()
// wait for updateNotifyLoop to finish
<-b.donec
close(b.notifyCh)
return nil
}

View File

@ -16,9 +16,14 @@ package clientv3
import (
"errors"
"net"
"sync"
"testing"
"time"
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
"github.com/coreos/etcd/pkg/testutil"
"golang.org/x/net/context"
"google.golang.org/grpc"
)
@ -29,6 +34,10 @@ var (
func TestBalancerGetUnblocking(t *testing.T) {
sb := newSimpleBalancer(endpoints)
defer sb.Close()
if addrs := <-sb.Notify(); len(addrs) != len(endpoints) {
t.Errorf("Initialize newSimpleBalancer should have triggered Notify() chan, but it didn't")
}
unblockingOpts := grpc.BalancerGetOptions{BlockingWait: false}
_, _, err := sb.Get(context.Background(), unblockingOpts)
@ -37,6 +46,9 @@ func TestBalancerGetUnblocking(t *testing.T) {
}
down1 := sb.Up(grpc.Address{Addr: endpoints[1]})
if addrs := <-sb.Notify(); len(addrs) != 1 {
t.Errorf("first Up() should have triggered balancer to send the first connected address via Notify chan so that other connections can be closed")
}
down2 := sb.Up(grpc.Address{Addr: endpoints[2]})
addrFirst, putFun, err := sb.Get(context.Background(), unblockingOpts)
if err != nil {
@ -54,6 +66,9 @@ func TestBalancerGetUnblocking(t *testing.T) {
}
down1(errors.New("error"))
if addrs := <-sb.Notify(); len(addrs) != len(endpoints) {
t.Errorf("closing the only connection should triggered balancer to send the all endpoints via Notify chan so that we can establish a connection")
}
down2(errors.New("error"))
_, _, err = sb.Get(context.Background(), unblockingOpts)
if err != ErrNoAddrAvilable {
@ -63,6 +78,10 @@ func TestBalancerGetUnblocking(t *testing.T) {
func TestBalancerGetBlocking(t *testing.T) {
sb := newSimpleBalancer(endpoints)
defer sb.Close()
if addrs := <-sb.Notify(); len(addrs) != len(endpoints) {
t.Errorf("Initialize newSimpleBalancer should have triggered Notify() chan, but it didn't")
}
blockingOpts := grpc.BalancerGetOptions{BlockingWait: true}
ctx, _ := context.WithTimeout(context.Background(), time.Millisecond*100)
@ -76,7 +95,11 @@ func TestBalancerGetBlocking(t *testing.T) {
go func() {
// ensure sb.Up() will be called after sb.Get() to see if Up() releases blocking Get()
time.Sleep(time.Millisecond * 100)
downC <- sb.Up(grpc.Address{Addr: endpoints[1]})
f := sb.Up(grpc.Address{Addr: endpoints[1]})
if addrs := <-sb.Notify(); len(addrs) != 1 {
t.Errorf("first Up() should have triggered balancer to send the first connected address via Notify chan so that other connections can be closed")
}
downC <- f
}()
addrFirst, putFun, err := sb.Get(context.Background(), blockingOpts)
if err != nil {
@ -97,6 +120,9 @@ func TestBalancerGetBlocking(t *testing.T) {
}
down1(errors.New("error"))
if addrs := <-sb.Notify(); len(addrs) != len(endpoints) {
t.Errorf("closing the only connection should triggered balancer to send the all endpoints via Notify chan so that we can establish a connection")
}
down2(errors.New("error"))
ctx, _ = context.WithTimeout(context.Background(), time.Millisecond*100)
_, _, err = sb.Get(ctx, blockingOpts)
@ -104,3 +130,110 @@ func TestBalancerGetBlocking(t *testing.T) {
t.Errorf("Get() with no up endpoints should timeout, got %v", err)
}
}
// TestBalancerDoNotBlockOnClose ensures that balancer and grpc don't deadlock each other
// due to rapid open/close conn. The deadlock causes balancer.Close() to block forever.
// See issue: https://github.com/coreos/etcd/issues/7283 for more detail.
func TestBalancerDoNotBlockOnClose(t *testing.T) {
defer testutil.AfterTest(t)
kcl := newKillConnListener(t, 3)
defer kcl.close()
for i := 0; i < 5; i++ {
sb := newSimpleBalancer(kcl.endpoints())
conn, err := grpc.Dial("", grpc.WithInsecure(), grpc.WithBalancer(sb))
if err != nil {
t.Fatal(err)
}
kvc := pb.NewKVClient(conn)
<-sb.readyc
var wg sync.WaitGroup
wg.Add(100)
cctx, cancel := context.WithCancel(context.TODO())
for j := 0; j < 100; j++ {
go func() {
defer wg.Done()
kvc.Range(cctx, &pb.RangeRequest{}, grpc.FailFast(false))
}()
}
// balancer.Close() might block
// if balancer and grpc deadlock each other.
bclosec, cclosec := make(chan struct{}), make(chan struct{})
go func() {
defer close(bclosec)
sb.Close()
}()
go func() {
defer close(cclosec)
conn.Close()
}()
select {
case <-bclosec:
case <-time.After(3 * time.Second):
testutil.FatalStack(t, "balancer close timeout")
}
select {
case <-cclosec:
case <-time.After(3 * time.Second):
t.Fatal("grpc conn close timeout")
}
cancel()
wg.Wait()
}
}
// killConnListener listens incoming conn and kills it immediately.
type killConnListener struct {
wg sync.WaitGroup
eps []string
stopc chan struct{}
t *testing.T
}
func newKillConnListener(t *testing.T, size int) *killConnListener {
kcl := &killConnListener{stopc: make(chan struct{}), t: t}
for i := 0; i < size; i++ {
ln, err := net.Listen("tcp", ":0")
if err != nil {
t.Fatal(err)
}
kcl.eps = append(kcl.eps, ln.Addr().String())
kcl.wg.Add(1)
go kcl.listen(ln)
}
return kcl
}
func (kcl *killConnListener) endpoints() []string {
return kcl.eps
}
func (kcl *killConnListener) listen(l net.Listener) {
go func() {
defer kcl.wg.Done()
for {
conn, err := l.Accept()
select {
case <-kcl.stopc:
return
default:
}
if err != nil {
kcl.t.Fatal(err)
}
time.Sleep(1 * time.Millisecond)
conn.Close()
}
}()
<-kcl.stopc
l.Close()
}
func (kcl *killConnListener) close() {
close(kcl.stopc)
kcl.wg.Wait()
}

View File

@ -20,12 +20,12 @@ import (
"fmt"
"net"
"net/url"
"strconv"
"strings"
"sync"
"time"
"github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
"golang.org/x/net/context"
"google.golang.org/grpc"
@ -36,6 +36,7 @@ import (
var (
ErrNoAvailableEndpoints = errors.New("etcdclient: no available endpoints")
ErrOldCluster = errors.New("etcdclient: old cluster version")
)
// Client provides and manages an etcd v3 client session.
@ -47,7 +48,9 @@ type Client struct {
Auth
Maintenance
conn *grpc.ClientConn
conn *grpc.ClientConn
dialerrc chan error
cfg Config
creds *credentials.TransportCredentials
balancer *simpleBalancer
@ -74,26 +77,28 @@ func New(cfg Config) (*Client, error) {
return newClient(&cfg)
}
// NewCtxClient creates a client with a context but no underlying grpc
// connection. This is useful for embedded cases that override the
// service interface implementations and do not need connection management.
func NewCtxClient(ctx context.Context) *Client {
cctx, cancel := context.WithCancel(ctx)
return &Client{ctx: cctx, cancel: cancel}
}
// NewFromURL creates a new etcdv3 client from a URL.
func NewFromURL(url string) (*Client, error) {
return New(Config{Endpoints: []string{url}})
}
// NewFromConfigFile creates a new etcdv3 client from a configuration file.
func NewFromConfigFile(path string) (*Client, error) {
cfg, err := configFromFile(path)
if err != nil {
return nil, err
}
return New(*cfg)
}
// Close shuts down the client's etcd connections.
func (c *Client) Close() error {
c.cancel()
c.Watcher.Close()
c.Lease.Close()
return toErr(c.ctx, c.conn.Close())
if c.conn != nil {
return toErr(c.ctx, c.conn.Close())
}
return c.ctx.Err()
}
// Ctx is a context for "out of band" messages (e.g., for sending
@ -177,8 +182,9 @@ func parseEndpoint(endpoint string) (proto string, host string, scheme string) {
host = url.Host
switch url.Scheme {
case "http", "https":
case "unix":
case "unix", "unixs":
proto = "unix"
host = url.Host + url.Path
default:
proto, host = "", ""
}
@ -191,7 +197,7 @@ func (c *Client) processCreds(scheme string) (creds *credentials.TransportCreden
case "unix":
case "http":
creds = nil
case "https":
case "https", "unixs":
if creds != nil {
break
}
@ -213,6 +219,11 @@ func (c *Client) dialSetupOpts(endpoint string, dopts ...grpc.DialOption) (opts
f := func(host string, t time.Duration) (net.Conn, error) {
proto, host, _ := parseEndpoint(c.balancer.getEndpoint(host))
if host == "" && endpoint != "" {
// dialing an endpoint not in the balancer; use
// endpoint passed into dial
proto, host, _ = parseEndpoint(endpoint)
}
if proto == "" {
return nil, fmt.Errorf("unknown scheme for %q", host)
}
@ -221,7 +232,15 @@ func (c *Client) dialSetupOpts(endpoint string, dopts ...grpc.DialOption) (opts
return nil, c.ctx.Err()
default:
}
return net.DialTimeout(proto, host, t)
dialer := &net.Dialer{Timeout: t}
conn, err := dialer.DialContext(c.ctx, proto, host)
if err != nil {
select {
case c.dialerrc <- err:
default:
}
}
return conn, err
}
opts = append(opts, grpc.WithDialer(f))
@ -281,19 +300,29 @@ func (c *Client) dial(endpoint string, dopts ...grpc.DialOption) (*grpc.ClientCo
tokenMu: &sync.RWMutex{},
}
err := c.getToken(context.TODO())
if err != nil {
return nil, err
ctx := c.ctx
if c.cfg.DialTimeout > 0 {
cctx, cancel := context.WithTimeout(ctx, c.cfg.DialTimeout)
defer cancel()
ctx = cctx
}
opts = append(opts, grpc.WithPerRPCCredentials(c.tokenCred))
err := c.getToken(ctx)
if err != nil {
if toErr(ctx, err) != rpctypes.ErrAuthNotEnabled {
if err == ctx.Err() && ctx.Err() != c.ctx.Err() {
err = grpc.ErrClientConnTimeout
}
return nil, err
}
} else {
opts = append(opts, grpc.WithPerRPCCredentials(c.tokenCred))
}
}
// add metrics options
opts = append(opts, grpc.WithUnaryInterceptor(prometheus.UnaryClientInterceptor))
opts = append(opts, grpc.WithStreamInterceptor(prometheus.StreamClientInterceptor))
opts = append(opts, c.cfg.DialOptions...)
conn, err := grpc.Dial(host, opts...)
conn, err := grpc.DialContext(c.ctx, host, opts...)
if err != nil {
return nil, err
}
@ -318,13 +347,19 @@ func newClient(cfg *Config) (*Client, error) {
}
// use a temporary skeleton client to bootstrap first connection
ctx, cancel := context.WithCancel(context.TODO())
baseCtx := context.TODO()
if cfg.Context != nil {
baseCtx = cfg.Context
}
ctx, cancel := context.WithCancel(baseCtx)
client := &Client{
conn: nil,
cfg: *cfg,
creds: creds,
ctx: ctx,
cancel: cancel,
conn: nil,
dialerrc: make(chan error, 1),
cfg: *cfg,
creds: creds,
ctx: ctx,
cancel: cancel,
}
if cfg.Username != "" && cfg.Password != "" {
client.Username = cfg.Username
@ -332,8 +367,12 @@ func newClient(cfg *Config) (*Client, error) {
}
client.balancer = newSimpleBalancer(cfg.Endpoints)
// use Endpoints[0] so that for https:// without any tls config given, then
// grpc will assume the ServerName is in the endpoint.
conn, err := client.dial(cfg.Endpoints[0], grpc.WithBalancer(client.balancer))
if err != nil {
client.cancel()
client.balancer.Close()
return nil, err
}
client.conn = conn
@ -351,9 +390,15 @@ func newClient(cfg *Config) (*Client, error) {
case <-waitc:
}
if !hasConn {
err := grpc.ErrClientConnTimeout
select {
case err = <-client.dialerrc:
default:
}
client.cancel()
client.balancer.Close()
conn.Close()
return nil, grpc.ErrClientConnTimeout
return nil, err
}
}
@ -364,10 +409,57 @@ func newClient(cfg *Config) (*Client, error) {
client.Auth = NewAuth(client)
client.Maintenance = NewMaintenance(client)
if cfg.RejectOldCluster {
if err := client.checkVersion(); err != nil {
client.Close()
return nil, err
}
}
go client.autoSync()
return client, nil
}
func (c *Client) checkVersion() (err error) {
var wg sync.WaitGroup
errc := make(chan error, len(c.cfg.Endpoints))
ctx, cancel := context.WithCancel(c.ctx)
if c.cfg.DialTimeout > 0 {
ctx, _ = context.WithTimeout(ctx, c.cfg.DialTimeout)
}
wg.Add(len(c.cfg.Endpoints))
for _, ep := range c.cfg.Endpoints {
// if cluster is current, any endpoint gives a recent version
go func(e string) {
defer wg.Done()
resp, rerr := c.Status(ctx, e)
if rerr != nil {
errc <- rerr
return
}
vs := strings.Split(resp.Version, ".")
maj, min := 0, 0
if len(vs) >= 2 {
maj, rerr = strconv.Atoi(vs[0])
min, rerr = strconv.Atoi(vs[1])
}
if maj < 3 || (maj == 3 && min < 2) {
rerr = ErrOldCluster
}
errc <- rerr
}(ep)
}
// wait for success
for i := 0; i < len(c.cfg.Endpoints); i++ {
if err = <-errc; err == nil {
break
}
}
cancel()
wg.Wait()
return err
}
// ActiveConnection returns the current in-use connection
func (c *Client) ActiveConnection() *grpc.ClientConn { return c.conn }
@ -413,3 +505,11 @@ func toErr(ctx context.Context, err error) error {
}
return err
}
func canceledByCaller(stopCtx context.Context, err error) bool {
if stopCtx.Err() == nil || err == nil {
return false
}
return err == context.Canceled || err == context.DeadlineExceeded
}

View File

@ -16,6 +16,7 @@ package clientv3
import (
"fmt"
"net"
"testing"
"time"
@ -25,36 +26,100 @@ import (
"google.golang.org/grpc"
)
func TestDialTimeout(t *testing.T) {
func TestDialCancel(t *testing.T) {
defer testutil.AfterTest(t)
donec := make(chan error)
// accept first connection so client is created with dial timeout
ln, err := net.Listen("unix", "dialcancel:12345")
if err != nil {
t.Fatal(err)
}
defer ln.Close()
ep := "unix://dialcancel:12345"
cfg := Config{
Endpoints: []string{ep},
DialTimeout: 30 * time.Second}
c, err := New(cfg)
if err != nil {
t.Fatal(err)
}
// connect to ipv4 blackhole so dial blocks
c.SetEndpoints("http://254.0.0.1:12345")
// issue Get to force redial attempts
getc := make(chan struct{})
go func() {
// without timeout, grpc keeps redialing if connection refused
cfg := Config{
Endpoints: []string{"localhost:12345"},
DialTimeout: 2 * time.Second}
c, err := New(cfg)
if c != nil || err == nil {
t.Errorf("new client should fail")
}
donec <- err
defer close(getc)
// Get may hang forever on grpc's Stream.Header() if its
// context is never canceled.
c.Get(c.Ctx(), "abc")
}()
time.Sleep(10 * time.Millisecond)
// wait a little bit so client close is after dial starts
time.Sleep(100 * time.Millisecond)
select {
case err := <-donec:
t.Errorf("dial didn't wait (%v)", err)
default:
}
donec := make(chan struct{})
go func() {
defer close(donec)
c.Close()
}()
select {
case <-time.After(5 * time.Second):
t.Errorf("failed to timeout dial on time")
case err := <-donec:
if err != grpc.ErrClientConnTimeout {
t.Errorf("unexpected error %v, want %v", err, grpc.ErrClientConnTimeout)
t.Fatalf("failed to close")
case <-donec:
}
select {
case <-time.After(5 * time.Second):
t.Fatalf("get failed to exit")
case <-getc:
}
}
func TestDialTimeout(t *testing.T) {
defer testutil.AfterTest(t)
testCfgs := []Config{
{
Endpoints: []string{"http://254.0.0.1:12345"},
DialTimeout: 2 * time.Second,
},
{
Endpoints: []string{"http://254.0.0.1:12345"},
DialTimeout: time.Second,
Username: "abc",
Password: "def",
},
}
for i, cfg := range testCfgs {
donec := make(chan error)
go func() {
// without timeout, dial continues forever on ipv4 blackhole
c, err := New(cfg)
if c != nil || err == nil {
t.Errorf("#%d: new client should fail", i)
}
donec <- err
}()
time.Sleep(10 * time.Millisecond)
select {
case err := <-donec:
t.Errorf("#%d: dial didn't wait (%v)", i, err)
default:
}
select {
case <-time.After(5 * time.Second):
t.Errorf("#%d: failed to timeout dial on time", i)
case err := <-donec:
if err != grpc.ErrClientConnTimeout {
t.Errorf("#%d: unexpected error %v, want %v", i, err, grpc.ErrClientConnTimeout)
}
}
}
}

View File

@ -0,0 +1,66 @@
// Copyright 2017 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package clientv3util_test
import (
"context"
"log"
"github.com/coreos/etcd/clientv3"
"github.com/coreos/etcd/clientv3/clientv3util"
)
func ExampleKeyExists_put() {
cli, err := clientv3.New(clientv3.Config{
Endpoints: []string{"127.0.0.1:2379"},
})
if err != nil {
log.Fatal(err)
}
defer cli.Close()
kvc := clientv3.NewKV(cli)
// perform a put only if key is missing
// It is useful to do the check (transactionally) to avoid overwriting
// the existing key which would generate potentially unwanted events,
// unless of course you wanted to do an overwrite no matter what.
_, err = kvc.Txn(context.Background()).
If(clientv3util.KeyMissing("purpleidea")).
Then(clientv3.OpPut("purpleidea", "hello world")).
Commit()
if err != nil {
log.Fatal(err)
}
}
func ExampleKeyExists_delete() {
cli, err := clientv3.New(clientv3.Config{
Endpoints: []string{"127.0.0.1:2379"},
})
if err != nil {
log.Fatal(err)
}
defer cli.Close()
kvc := clientv3.NewKV(cli)
// perform a delete only if key already exists
_, err = kvc.Txn(context.Background()).
If(clientv3util.KeyExists("purpleidea")).
Then(clientv3.OpDelete("purpleidea")).
Commit()
if err != nil {
log.Fatal(err)
}
}

View File

@ -0,0 +1,33 @@
// Copyright 2017 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package clientv3util contains utility functions derived from clientv3.
package clientv3util
import (
"github.com/coreos/etcd/clientv3"
)
// KeyExists returns a comparison operation that evaluates to true iff the given
// key exists. It does this by checking if the key `Version` is greater than 0.
// It is a useful guard in transaction delete operations.
func KeyExists(key string) clientv3.Cmp {
return clientv3.Compare(clientv3.Version(key), ">", 0)
}
// KeyMissing returns a comparison operation that evaluates to true iff the
// given key does not exist.
func KeyMissing(key string) clientv3.Cmp {
return clientv3.Compare(clientv3.Version(key), "=", 0)
}

View File

@ -50,28 +50,26 @@ func NewCluster(c *Client) Cluster {
return &cluster{remote: RetryClusterClient(c)}
}
func NewClusterFromClusterClient(remote pb.ClusterClient) Cluster {
return &cluster{remote: remote}
}
func (c *cluster) MemberAdd(ctx context.Context, peerAddrs []string) (*MemberAddResponse, error) {
r := &pb.MemberAddRequest{PeerURLs: peerAddrs}
resp, err := c.remote.MemberAdd(ctx, r)
if err == nil {
return (*MemberAddResponse)(resp), nil
}
if isHaltErr(ctx, err) {
if err != nil {
return nil, toErr(ctx, err)
}
return nil, toErr(ctx, err)
return (*MemberAddResponse)(resp), nil
}
func (c *cluster) MemberRemove(ctx context.Context, id uint64) (*MemberRemoveResponse, error) {
r := &pb.MemberRemoveRequest{ID: id}
resp, err := c.remote.MemberRemove(ctx, r)
if err == nil {
return (*MemberRemoveResponse)(resp), nil
}
if isHaltErr(ctx, err) {
if err != nil {
return nil, toErr(ctx, err)
}
return nil, toErr(ctx, err)
return (*MemberRemoveResponse)(resp), nil
}
func (c *cluster) MemberUpdate(ctx context.Context, id uint64, peerAddrs []string) (*MemberUpdateResponse, error) {

View File

@ -82,6 +82,23 @@ func ModRevision(key string) Cmp {
return Cmp{Key: []byte(key), Target: pb.Compare_MOD}
}
// KeyBytes returns the byte slice holding with the comparison key.
func (cmp *Cmp) KeyBytes() []byte { return cmp.Key }
// WithKeyBytes sets the byte slice for the comparison key.
func (cmp *Cmp) WithKeyBytes(key []byte) { cmp.Key = key }
// ValueBytes returns the byte slice holding the comparison value, if any.
func (cmp *Cmp) ValueBytes() []byte {
if tu, ok := cmp.TargetUnion.(*pb.Compare_Value); ok {
return tu.Value
}
return nil
}
// WithValueBytes sets the byte slice for the comparison's value.
func (cmp *Cmp) WithValueBytes(v []byte) { cmp.TargetUnion.(*pb.Compare_Value).Value = v }
func mustInt64(val interface{}) int64 {
if v, ok := val.(int64); ok {
return v

View File

@ -19,6 +19,7 @@ import (
"fmt"
v3 "github.com/coreos/etcd/clientv3"
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
"github.com/coreos/etcd/mvcc/mvccpb"
"golang.org/x/net/context"
)
@ -36,6 +37,7 @@ type Election struct {
leaderKey string
leaderRev int64
leaderSession *Session
hdr *pb.ResponseHeader
}
// NewElection returns a new election on a given key prefix.
@ -43,6 +45,16 @@ func NewElection(s *Session, pfx string) *Election {
return &Election{session: s, keyPrefix: pfx + "/"}
}
// ResumeElection initializes an election with a known leader.
func ResumeElection(s *Session, pfx string, leaderKey string, leaderRev int64) *Election {
return &Election{
session: s,
leaderKey: leaderKey,
leaderRev: leaderRev,
leaderSession: s,
}
}
// Campaign puts a value as eligible for the election. It blocks until
// it is elected, an error occurs, or the context is cancelled.
func (e *Election) Campaign(ctx context.Context, val string) error {
@ -69,7 +81,7 @@ func (e *Election) Campaign(ctx context.Context, val string) error {
}
}
err = waitDeletes(ctx, client, e.keyPrefix, e.leaderRev-1)
_, err = waitDeletes(ctx, client, e.keyPrefix, e.leaderRev-1)
if err != nil {
// clean up in case of context cancel
select {
@ -80,6 +92,7 @@ func (e *Election) Campaign(ctx context.Context, val string) error {
}
return err
}
e.hdr = resp.Header
return nil
}
@ -101,6 +114,8 @@ func (e *Election) Proclaim(ctx context.Context, val string) error {
e.leaderKey = ""
return ErrElectionNotLeader
}
e.hdr = tresp.Header
return nil
}
@ -110,28 +125,36 @@ func (e *Election) Resign(ctx context.Context) (err error) {
return nil
}
client := e.session.Client()
_, err = client.Delete(ctx, e.leaderKey)
cmp := v3.Compare(v3.CreateRevision(e.leaderKey), "=", e.leaderRev)
resp, err := client.Txn(ctx).If(cmp).Then(v3.OpDelete(e.leaderKey)).Commit()
if err == nil {
e.hdr = resp.Header
}
e.leaderKey = ""
e.leaderSession = nil
return err
}
// Leader returns the leader value for the current election.
func (e *Election) Leader(ctx context.Context) (string, error) {
func (e *Election) Leader(ctx context.Context) (*v3.GetResponse, error) {
client := e.session.Client()
resp, err := client.Get(ctx, e.keyPrefix, v3.WithFirstCreate()...)
if err != nil {
return "", err
return nil, err
} else if len(resp.Kvs) == 0 {
// no leader currently elected
return "", ErrElectionNoLeader
return nil, ErrElectionNoLeader
}
return string(resp.Kvs[0].Value), nil
return resp, nil
}
// Observe returns a channel that observes all leader proposal values as
// GetResponse values on the current leader key. The channel closes when
// the context is cancelled or the underlying watcher is otherwise disrupted.
// Observe returns a channel that reliably observes ordered leader proposals
// as GetResponse values on every current elected leader key. It will not
// necessarily fetch all historical leader updates, but will always post the
// most recent leader value.
//
// The channel closes when the context is canceled or the underlying watcher
// is otherwise disrupted.
func (e *Election) Observe(ctx context.Context) <-chan v3.GetResponse {
retc := make(chan v3.GetResponse)
go e.observe(ctx, retc)
@ -149,13 +172,13 @@ func (e *Election) observe(ctx context.Context, ch chan<- v3.GetResponse) {
}
var kv *mvccpb.KeyValue
var hdr *pb.ResponseHeader
cctx, cancel := context.WithCancel(ctx)
if len(resp.Kvs) == 0 {
cctx, cancel := context.WithCancel(ctx)
// wait for first key put on prefix
opts := []v3.OpOption{v3.WithRev(resp.Header.Revision), v3.WithPrefix()}
wch := client.Watch(cctx, e.keyPrefix, opts...)
for kv == nil {
wr, ok := <-wch
if !ok || wr.Err() != nil {
@ -165,16 +188,27 @@ func (e *Election) observe(ctx context.Context, ch chan<- v3.GetResponse) {
// only accept PUTs; a DELETE will make observe() spin
for _, ev := range wr.Events {
if ev.Type == mvccpb.PUT {
kv = ev.Kv
hdr, kv = &wr.Header, ev.Kv
// may have multiple revs; hdr.rev = the last rev
// set to kv's rev in case batch has multiple PUTs
hdr.Revision = kv.ModRevision
break
}
}
}
cancel()
} else {
kv = resp.Kvs[0]
hdr, kv = resp.Header, resp.Kvs[0]
}
wch := client.Watch(cctx, string(kv.Key), v3.WithRev(kv.ModRevision))
select {
case ch <- v3.GetResponse{Header: hdr, Kvs: []*mvccpb.KeyValue{kv}}:
case <-ctx.Done():
return
}
cctx, cancel := context.WithCancel(ctx)
wch := client.Watch(cctx, string(kv.Key), v3.WithRev(hdr.Revision+1))
keyDeleted := false
for !keyDeleted {
wr, ok := <-wch
@ -201,3 +235,9 @@ func (e *Election) observe(ctx context.Context, ch chan<- v3.GetResponse) {
// Key returns the leader key if elected, empty string otherwise.
func (e *Election) Key() string { return e.leaderKey }
// Rev returns the leader key's creation revision, if elected.
func (e *Election) Rev() int64 { return e.leaderRev }
// Header is the response header from the last successful election proposal.
func (m *Election) Header() *pb.ResponseHeader { return m.hdr }

Some files were not shown because too many files have changed in this diff Show More