Compare commits

...

785 Commits

Author SHA1 Message Date
5695120efc version: bump to v3.0.7 2016-08-31 09:49:24 -07:00
183293e061 wal: lowercase segmentSizeBytes 2016-08-31 09:48:30 -07:00
4b48876f0e clientv3/concurrency: allow election on prefixes of keys.
After winning an election or obtaining a lock, we
auto-append a slash after the provided key prefix.
This avoids the previous deadlock due to waiting
on the wrong key.

Fixes #6278

Conflicts:
	clientv3/concurrency/election.go
	clientv3/concurrency/mutex.go
2016-08-31 09:46:05 -07:00
5089bf58fb wal: hold file lock while renaming WAL directory on non-Windows
Windows requires this lock to be released before the directory is
renamed. But on unix-like operating systems, releasing the lock and
trying to reacquire it immediately can be flaky if a process is forked
around the same time. The file descriptors are marked as close-on-exec
by the Go runtime, but there is a window between the fork and exec where
another process will be holding the lock.
2016-08-31 09:39:57 -07:00
480a347179 wal: use page buffered writer for writing records
Forces torn writes to only happen on sector boundaries.

Fixes #6271
2016-08-30 21:06:36 -07:00
59e560c7a7 ioutil: add page buffered writer
A buffered writer that only writes full pages or when explicitly flushed.
2016-08-30 21:06:33 -07:00
0bd9bea2e9 etcdserver: allow zero kv index for cluster upgrade
If a user upgrades etcd from 2.3.x to 3.0 and shutdown the
cluster immediately without triggering any new backend writes,
then the consistent index in backend would be zero.

The user cannot restart etcdserver due to today's strick index
match checking. We now have to lose this a bit for this case.
2016-08-30 21:05:20 -07:00
bd7581ac59 wal: zero out wal tail past its first zero record
Whenever the WAL is opened for writes, it should write zeroes to its tail
starting from the first zero record. Otherwise, if there are entries past
the first zero record due to a torn write, any new writes that overlap the
old entries will lead to a garbage record on the tail and cause a CRC
mismatch.
2016-08-26 14:27:53 -07:00
db378c3d26 wal: test for truncation on torn writes 2016-08-26 14:27:51 -07:00
23740162dc fileutil: add ZeroToEnd for zeroing files 2016-08-26 14:27:49 -07:00
96422a955f discovery: reject IP address records in SRVGetCluster
Was incorrectly trimming the trailing '.' from the target; this in turn
caused the etcd server to accept any SRV record with an IP target
instead of only targets with A records.
2016-08-24 09:14:47 -07:00
6fd996fdac version: bump to v3.0.6+git 2016-08-19 12:38:13 -07:00
9efa00d103 version: bump to v3.0.6 2016-08-19 12:03:02 -07:00
72d30f4c34 *: minor cleanup for lease 2016-08-19 11:53:38 -07:00
2e92779777 mvcc: attach keys to leases after recover all state
The previous logic is wrong. When we have hisotry like Put(foo, bar, lease1),
and Put(foo, bar, lease2), we will end up with attaching foo to two leases 1 and
2. Similar things can happen for deattach by clearing the lease of a key.

Now we try to fix this by starting to attach leases at the end of the recovery.
We use a map to keep the last lease attachment state.
2016-08-19 11:49:05 -07:00
404415b1e3 lease: do lease delection in the kv txn 2016-08-19 11:49:05 -07:00
07e421d245 lease: delete kvs in a txn 2016-08-19 11:49:05 -07:00
a7d6e29275 etcdserver: always recover lessor first 2016-08-19 11:49:05 -07:00
1a8b295dab vendor: update grpc/grpc-go for clientconn patch 2016-08-19 11:46:51 -07:00
ffc45cc066 rafthttp: fix race between streamReader.stop() and connection closer 2016-08-19 11:45:39 -07:00
0db1ba8093 version: bump to v3.0.5+git 2016-08-19 11:11:10 -07:00
43f7c94ac8 version: bump to v3.0.5 2016-08-19 10:20:37 -07:00
93d13fb5b4 integration: NewClusterV3 should launch cluster before creating clients 2016-08-18 14:54:45 -07:00
6a1e3e73dd vendor: boltdb/bolt v1.3.0 for Go 1.7
In case somebody wants to build this branch with Go 1.7
2016-08-18 14:41:34 -07:00
ec576ee5ac mvcc: fix count 2016-08-16 12:13:33 -07:00
606d79afc4 clientv3: use failfast and retry wrappers for at-most-once rpcs 2016-08-16 12:12:44 -07:00
f4d15a430c integration: treat client TLS connecting to insecure server as timeout 2016-08-16 12:09:42 -07:00
4a841459f1 clientv3: respect up/down notifications from grpc
Fixes #5842
2016-08-16 12:09:38 -07:00
ee8c577fc0 vendor: update grpc 2016-08-16 12:09:16 -07:00
8ae0f94cd7 clientv3: only block on New() when DialTimeout > 0
Fixes #6162
2016-08-12 12:03:33 -07:00
69a97863a9 clientv3: handle watchGrpcStream shutdown if prior to goroutine start
Fixes #6141
2016-08-09 20:59:09 -07:00
12c7e4a9f8 clientv3: close watcher stream once all watchers detach
Fixes #6134
2016-08-09 10:44:21 -07:00
23cced240b transport: add ServerName to TLSConfig and add ValidateSecureEndpoints
ServerName prevents accepting forged SRV records with cross-domain
credentials. ValidateSecureEndpoints prevents downgrade attacks from SRV
records.
2016-08-04 11:00:28 -07:00
e73c928d85 etcdctl: set ServerName for TLS when using --discovery-srv 2016-08-04 11:00:25 -07:00
779ad90f9a Documentation: update clustering guide about PKI SRV record forging 2016-08-04 11:00:22 -07:00
dca1740be5 etcdmain: check TLS on gateway SRV records 2016-08-04 11:00:15 -07:00
487b34d857 embed: use ServerName on TLS DNS discovery w/o CA file 2016-08-04 10:56:11 -07:00
a31283cf51 v2http: use guest access in non-TLS mode
Fix https://github.com/coreos/etcd/issues/6075.
2016-08-04 10:52:42 -07:00
b722bedf8a version: bump to v3.0.4+git 2016-07-27 15:30:31 -07:00
d53923c636 version: bump to v3.0.4 2016-07-27 13:40:42 -07:00
9356665d60 *: regenerate proto files for grpc-gateway 2016-07-27 13:40:07 -07:00
0932d17395 scripts/genproto: use latest grpc-gateway c8ec92d0 2016-07-27 13:39:00 -07:00
2a3ea3f996 Dockerfile-release: add '/var/lib/etcd/'
We have '/var/etcd/' in Dockerfile for historical reason.
Most cases, user store data in '/var/lib/etcd/'.
2016-07-27 13:38:58 -07:00
e5a5e5f7c6 etcdserver, api, membership: don't race on setting version
Fixes #6029
2016-07-27 09:39:39 -07:00
00bdd907d5 Documentation: fix links in upgrades 2016-07-26 13:16:15 -07:00
8eab756d3f *: regenerate proto 2016-07-25 21:36:07 -07:00
3d9b1d1635 scripts:genproto.sh: update grpc-gateway 2016-07-25 21:31:33 -07:00
4218193dd7 etcdserverpb: add missing deleterange annotation 2016-07-25 21:31:30 -07:00
6499d01c9b etcdmain: correctly check return values from SdNotify()
SdNotify() now returns 2 values, sent and err. So startEtcdOrProxyV2()
needs to check the 2 return values correctly. As the 2 values are
independent of each other, error checking needs to be slightly updated
too.

SdNotifyNoSocket, which was previously provided by go-systemd, does not
exist any more. In that case (false, nil) will be returned instead.
2016-07-21 11:00:37 -07:00
83b39b4f6b vendor: update go-systemd
Godeps.json and vendor need to be updated according to the newest
go-systemd, as SdNotify() in go-systemd has changed its API.
2016-07-21 11:00:34 -07:00
21092ca715 integration: change timeouts for TestWatchWithProgressNotify
a) 2 * progress interval was passing with dropped notifies
b) waitResponse was waiting so long that it expected a dropped notify
2016-07-21 10:59:54 -07:00
a4e79d7ebf v3rpc: don't elide next progress notification on progress notification
Fixes #5878
2016-07-21 10:59:51 -07:00
846883a979 rpctypes, clientv3: retry RPC on EtcdStopped
Fixes #5983
2016-07-21 10:59:27 -07:00
c7a3edb90f fileutil: rework purge tests so they don't poll
Fixes #5966
2016-07-21 10:57:06 -07:00
f308a27e91 e2e: test auth enabled with CN name cert 2016-07-21 10:55:56 -07:00
1d37154793 v2http: test with 'ClientCertAuthEnabled' 2016-07-21 10:55:54 -07:00
092d069d3e v2http: set 'ClientCertAuthEnabled' in client.go 2016-07-21 10:55:51 -07:00
ab5c4e23bd v2http: add 'ClientCertAuthEnabled' in handlers 2016-07-21 10:55:44 -07:00
59bf6693c7 embed: set 'ClientCertAuthEnabled' 2016-07-21 10:55:30 -07:00
affcbfbf06 etcdserver: add 'ClientCertAuthEnabled' option 2016-07-21 10:52:14 -07:00
e81df2648c v2http: move 'testdata' from 'etcdhttp' 2016-07-21 10:52:09 -07:00
27a450235a v2http: client cert cn authentication
introduce client certificate authentication using certificate cn.
2016-07-21 10:52:06 -07:00
42454f9ed8 v2http: refactor http basic auth
refactor http basic auth code to combine basic auth extraction and validation
2016-07-21 10:52:04 -07:00
7ea8860670 e2e: use a single member cluster in TestCtlV3Migrate
Occasionally migrate would fail because a minority node would be missing
v2 keys. Instead, just use a single member cluster.

Fixes #5992
2016-07-21 10:50:49 -07:00
2fb72029ef etcdctl: Add support for formating output of ls command in json
The ls command will check for and honor json or extended output formats.

Fixes #5993
2016-07-21 10:50:47 -07:00
77af59796d clientv3/integration: fix race in TestWatchCompactRevision 2016-07-21 10:50:46 -07:00
b732f96e07 integration: drain keepalives in TestLeaseKeepAliveCloseAfterDisconnectRevoke
Fixes #5900
2016-07-21 10:50:44 -07:00
602198105d *: regenerate proto 2016-07-18 11:08:51 -07:00
e513cbd562 vendor: update 'gogo/protobuf' 2016-07-18 11:06:58 -07:00
4198369dd0 scripts: update gogo/protobuf, use 'gofast' plugin
- Fix https://github.com/coreos/etcd/issues/5942
- Partial fix for https://github.com/coreos/etcd/issues/5865
2016-07-18 11:06:55 -07:00
debecc1868 vendor: change to 'grpc-ecosystem' from 'gengo' 2016-07-18 11:06:33 -07:00
140fc04c62 *: regenerate proto files 2016-07-18 11:06:17 -07:00
7e34665774 scripts: update genproto with grpc-ecosystem 2016-07-18 11:03:54 -07:00
be541f3641 Documentation: change to grpc-ecosystem 2016-07-18 11:03:52 -07:00
e582416994 embed: change import path to 'grpc-ecosystem' 2016-07-18 11:03:50 -07:00
842145ecb3 *: fix issue found in fast lease renew 2016-07-18 11:03:20 -07:00
d68936c4da version: bump to v3.0.3+git 2016-07-15 11:51:50 -07:00
24a90baff8 version: bump to v3.0.3 2016-07-15 11:26:14 -07:00
6b7891d5f1 integration: add FailFast(false) to failing tests 2016-07-14 19:01:17 -07:00
129b271ff8 clientv3: use grpc.FailFast(false) for all calls 2016-07-14 19:00:46 -07:00
a11ee983c4 vendor: update grpc
Fixes #5871
2016-07-14 18:47:02 -07:00
bec58d5f58 integration: test grpc error equivalence with Error() 2016-07-14 18:47:00 -07:00
4b6f9b79e6 rpctypes: test error equivalence with Error()
grpc.Errorf() now returns *rpcError, which makes comparisons shallow.
2016-07-14 18:46:58 -07:00
f7ec7f025b embed: only get initial cluster setting if the member is not init 2016-07-14 13:01:29 -07:00
34c76a47c1 Revert "Dockerfile: use 'ENTRYPOINT' instead of 'CMD'" 2016-07-14 12:24:06 -07:00
525653ff51 raft: do not change RecentActive when resetState for progress 2016-07-12 09:59:42 -07:00
a647b79038 etcdserver: fix TestSnap 2016-07-11 13:59:12 -07:00
9bc1d08753 etcdctl: only takes 127.0.0.1:2379 as default endpoint 2016-07-11 13:41:53 -07:00
6a79bda691 e2e: add basic upgrade tests 2016-07-11 13:41:50 -07:00
1edfcd6859 test: add upgrade test flag 2016-07-11 13:41:47 -07:00
f51fdbccec version: bump to v3.0.2+git 2016-07-08 12:09:09 -07:00
faeeb2fc75 version: bump to v3.0.2 2016-07-08 11:45:18 -07:00
d50c487132 v3rpc: lock progress and prevKV map correctly 2016-07-08 10:16:10 -07:00
b837feffe4 client/integration: test v2 client one shot operations 2016-07-07 17:30:09 -07:00
4d89640195 client: make set/delete one shot operations
Old behavior would retry set and delete even if there's an error. This
can lead to the client returning an error for deleting twice, instead
of returning an error for an interdeterminate state.

Fixes #5832
2016-07-07 17:30:04 -07:00
1292d453c3 clientv3: fix sync base
It is not correct to use WithPrefix. Range end will change in every
internal batch.
2016-07-07 14:21:43 -07:00
ec20b381ed clientv3: add public function to get prefix range end 2016-07-07 14:21:41 -07:00
37cc3f5262 Dockerfile: use 'ENTRYPOINT' instead of 'CMD'
use entrypoint, so people can specify flags to etcd
without providing the binary.

Signed-off-by: Secret <haichuang221@163.com>
2016-07-05 11:40:47 -07:00
7f1940e5ed etcdserver: commit before sending snapshot 2016-07-05 11:06:54 -07:00
caccf8e5e6 v3rpc: do not panic on user error for watch 2016-07-05 11:06:35 -07:00
ef65dfe2eb wal: release wal locks before renaming directory on init
Fixes #5852
2016-07-05 11:05:51 -07:00
ff6c6916f2 etcdserver/api: print only major.minor version API
Before

2016-07-01 14:57:50.927170 I | api: enabled capabilities for version 3.0.0

After

2016-07-01 14:57:50.927170 I | api: enabled capabilities for version 3.0
2016-07-01 15:19:53 -07:00
3dfe8765d3 version: bump to v3.0.1+git 2016-07-01 14:53:20 -07:00
a4a52cb15d version: bump to v3.0.1 2016-07-01 13:58:37 -07:00
014970930a *: test, docs with go1.6+
etcd v3 uses http/2, which doesn't work well with go1.5
2016-07-01 11:59:37 -07:00
4628be982c Documentation: fix typo in api_grpc_gateway.md 2016-07-01 11:59:35 -07:00
ff55e5a188 etcdserver: exit on missing backend only if semver is >= 3.0.0 2016-07-01 11:59:32 -07:00
bf0898266c release: fix Dockerfile etcd binary paths
release script uses binary files in 'release/image-docker',
not the ones in "bin/". Tested with v3.0.0 release.
2016-06-30 12:27:34 -07:00
b9d69f7698 version: bump to v3.0.0+git 2016-06-30 11:37:05 -07:00
6f48bda7ac version: bump to v3.0.0 2016-06-30 10:04:59 -07:00
316534e09e *: remove beta from docs 2016-06-30 10:04:34 -07:00
3cecbdb464 hack: install goreman in tls-setup example 2016-06-30 09:33:19 -07:00
62f11e43ee hack: add tls-setup example generated certs to gitignore 2016-06-30 09:33:12 -07:00
064c1585ee Merge pull request #5822 from raoofm/patch-9
Doc: fix typo in dev-guide.md
2016-06-30 09:06:32 -07:00
15300a1eb8 Doc: fix typo in dev-guide.md 2016-06-30 10:36:50 -04:00
58dd047ee4 ctlv3: make flags, commands formats consistent
1. Capitalize first letter
2. Remove period at the end

(followed the pattern in linux coreutil man page)
2016-06-29 16:16:56 -07:00
4b42ea6cd7 clientv3: only use closeErr on watch when donec is closed
Fixes #5800
2016-06-28 17:48:44 -07:00
53c27ae621 benchmark: fix Compact request 2016-06-28 14:15:32 -07:00
269de67bde mvcc: do not hash consistent index 2016-06-28 12:29:36 -07:00
8bbccf1047 clientv3, ctl3, clientv3/integration: add compact response to compact 2016-06-28 12:29:32 -07:00
c00e97ea49 Merge pull request #5785 from gyuho/doc_update
Documentation/upgrades: upgrade 3.0 doc
2016-06-27 15:46:53 -07:00
c8a7d281ee Documentation/upgrades: upgrade 3.0 doc 2016-06-27 15:45:44 -07:00
a5c2cd2708 Merge pull request #5784 from heyitsanthony/doc-todos
Documentation: clear out some TODOs
2016-06-27 15:20:30 -07:00
11fdf2dd18 Documentation: clear out some TODOs 2016-06-27 15:00:18 -07:00
3b300f42e9 Merge pull request #5781 from gyuho/compact_client
*: compact with physical in client side
2016-06-27 14:46:54 -07:00
b4162f8a45 Merge pull request #5782 from heyitsanthony/doc-lint
Documentation: conform to header style
2016-06-27 12:20:31 -07:00
f63e6875bd e2e: test 'physical' flag in compact cmd 2016-06-27 12:07:49 -07:00
76e2bf03b8 etcdctl: v3 compact with physical flag 2016-06-27 12:07:46 -07:00
859e336d68 clientv3: configurable physical in compact 2016-06-27 12:04:04 -07:00
35229eb2d3 Documentation: conform to header style 2016-06-27 12:00:24 -07:00
bbed3ecc8d Merge pull request #5780 from xiang90/check_i
etcdserver: check index of the kv when restarting
2016-06-27 11:44:10 -07:00
9614dc6e71 etcdserver: check index of the kv when restarting 2016-06-27 10:27:27 -07:00
aab905f7cc Merge pull request #5776 from mitake/commit-title
test: more accurate checking of commit title
2016-06-27 14:48:10 +09:00
cfc171d5f7 Merge pull request #5777 from xiang90/c_be
etcdserver: refuse to restart if backend file is missing
2016-06-26 22:34:08 -07:00
891ddcba6e etcdserver: refuse to restart if backend file is missing 2016-06-26 21:16:51 -07:00
555028f3d1 test: more accurate checking of commit title 2016-06-26 21:05:47 -07:00
efcf03f0b1 Merge pull request #5773 from heyitsanthony/integration-unixsock
integration: use unix sockets for all connections
2016-06-25 16:17:20 -07:00
ae6e879812 Merge pull request #5774 from gyuho/raft_minor_fix
raft: len(entries) before Lock, use firstIndex
2016-06-25 11:13:16 -07:00
6a48961895 raft: len(entries) before Lock, use firstIndex
- To avoid unnecessary locking in case len(entries) == 0
- use firstIndex method
2016-06-24 23:50:00 -07:00
13d0ea7f54 integration: use unix domain sockets for all connections 2016-06-24 21:18:19 -07:00
bbb84ff709 discovery: use pkg/transport to create http transport 2016-06-24 21:04:39 -07:00
54d56e2531 pkg/types: accept unix and unixs schemes 2016-06-24 21:04:39 -07:00
fc1a226d15 pkg/transport: unix domain socket listener and transport 2016-06-24 21:04:31 -07:00
0c820dc7ba Merge pull request #5769 from xiang90/unstable
doc: add unstable
2016-06-24 13:38:54 -07:00
40f62ab4a5 Merge pull request #5771 from gyuho/docker
*: separate Dockerfile for quay build trigger
2016-06-24 13:26:05 -07:00
0da05a896f doc: add experimental apis 2016-06-24 13:05:53 -07:00
8a71f749d7 *: separate Dockerfile for quay build trigger
Fix https://quay.io/repository/coreos/etcd-git/build/d75d80b1-7d8d-42bd-af07-645b7da3a118.
2016-06-24 12:55:10 -07:00
3424f95b03 Merge pull request #5770 from gyuho/op_guide
*: move 'Project detail' to op-guide
2016-06-24 10:50:03 -07:00
862b3fe2be *: move 'Project detail' to op-guide 2016-06-24 10:47:12 -07:00
aeb5b3c82b Merge pull request #5766 from heyitsanthony/eschew-you
doc: remove you/your from current docs
2016-06-24 09:29:26 -07:00
e1b9ccb1d7 doc: eschew "you" for current docs 2016-06-24 09:28:12 -07:00
d284a45a4b Merge pull request #5765 from heyitsanthony/autotls-security
doc: auto-tls example in security guide
2016-06-24 09:17:38 -07:00
9bde740cf9 doc: auto-tls example in security guide 2016-06-24 09:15:46 -07:00
c1d2149a0f Merge pull request #5767 from mitake/build
build: remove needless output
2016-06-24 09:03:14 -07:00
15b267fbfd Merge pull request #5768 from gyuho/raft_comment
raft: fix comment, method name in progress
2016-06-24 08:38:02 -07:00
33f7e7583b raft: fix comment,method name to needSnapshotAbort
And 'maybeSnapshotAbort' does not 'unset'
the pendingSnapshot. 'resetState', which is called after this
metho, is the one that unsets pendingSnapshot. So this changes
the method name.
2016-06-24 07:54:10 -07:00
abc1cb945b build: remove needless output
Current build script outputs its name to stdout because of its
checking argv[0].

$ ./build
./build

The line is a little bit mysterious so this commit removes it.
2016-06-24 13:54:53 +09:00
a7189ef073 Merge pull request #5762 from gyuho/member_auth
Documentation/demo: add member, auth example
2016-06-23 16:10:57 -07:00
78d9ae1820 Merge pull request #5763 from heyitsanthony/local-tester-fp
local-tester: support failpoints
2016-06-23 13:01:26 -07:00
9b4dc92fdc Merge pull request #5761 from xiang90/proxy_v2
*: make it clear that proxy only supports v2 api now
2016-06-23 12:35:04 -07:00
755d192ff7 *: make it clear that proxy only supports v2 api now 2016-06-23 12:06:42 -07:00
244266708b local-tester: support failpoints 2016-06-23 12:04:11 -07:00
b2a8acdf10 Documentation/demo: add member, auth example 2016-06-23 11:50:37 -07:00
9664df1b5e Merge pull request #5760 from gyuho/peer-urls
*: change ctlv3 flag peerURLs to 'peer-urls'
2016-06-23 10:12:28 -07:00
f9d250ad1b e2e: update flag to 'peer-urls' 2016-06-23 09:53:30 -07:00
fa74a0d3bb etcdctl: change peerURLs flag to 'peer-urls' 2016-06-23 09:52:25 -07:00
c949811752 Merge pull request #5758 from dannysauer/master
index is incremented in Watcher; remove double-increment
2016-06-23 07:57:21 -07:00
5247702d8d Merge pull request #5755 from nekto0n/reuse-timer
Reuse timer in backend.run.
2016-06-23 07:28:09 -07:00
a998fb4af1 etcdctl: index is incremented in Watcher; remove double-increment 2016-06-23 08:54:34 -05:00
dbc7c2cf4e backend: reuse timer in run().
Benchmarks:

```
import (
	"testing"
	"time"
)

func BenchmarkTimeAfter(b *testing.B) {
	b.ReportAllocs()
	for n := 0; n < b.N; n++ {
		select {
		case <- time.After(1 * time.Millisecond):
		}
	}
}

func BenchmarkTimerReset(b *testing.B) {
	b.ReportAllocs()
	t := time.NewTimer(1 * time.Millisecond)
	for n := 0; n < b.N; n++ {
		select {
		case <- t.C:
		}
		t.Reset(1 * time.Millisecond)
	}
}
```

Running reveals that each loop results in 3 allocs:

```
BenchmarkTimeAfter-4 	    2000	   1112134 ns/op	     192 B/op	       3 allocs/op
BenchmarkTimerReset-4	    2000	   1109774 ns/op	       0 B/op	       0 allocs/op
```
2016-06-23 18:49:41 +05:00
b945a3fcc8 Merge pull request #5753 from gyuho/example
clientv3: add auth example
2016-06-22 20:27:30 -07:00
2da5bdd4df clientv3: add auth example 2016-06-22 20:06:13 -07:00
e4ab1540c8 Merge pull request #5752 from gyuho/mkdir
Make mkdir consistent
2016-06-22 16:16:38 -07:00
4a0f922a6c pkg/transport: use TouchDirAll 2016-06-22 15:57:55 -07:00
6cfc03a5f9 wal: use CreateDirAll 2016-06-22 15:57:55 -07:00
c363fd288b etcdserver: use CreateDirAll 2016-06-22 15:57:47 -07:00
5720fe812e etcdctl: use CreateDirAll 2016-06-22 15:55:56 -07:00
187faba3e0 pkg/fileutil: fix TouchDirAll, add CreateDirAll
os.MkdirAll never returns os.ErrExist.
And add another function to ensure deepest
directory is empty.
2016-06-22 15:54:17 -07:00
df9a52e53f Merge pull request #5702 from gyuho/vet
*: go vet, go lint fixes
2016-06-22 14:52:34 -07:00
6fbf8be3ac Merge pull request #5751 from heyitsanthony/fail-bad-commit-msg
test: check commit titles
2016-06-22 14:03:15 -07:00
b7253992d4 test: check commit titles 2016-06-22 13:30:22 -07:00
c1e3601776 raftexample: fixes from go vet, go lint 2016-06-22 12:04:15 -07:00
e221699fd8 rafthttp: fix from go vet, go lint 2016-06-22 12:04:15 -07:00
725ded40f7 etcdserver: fix from go vet, go lint 2016-06-22 12:04:15 -07:00
e2138179e3 client: fix from go vet, go lint 2016-06-22 12:04:15 -07:00
6557ef7cd8 *: copy all exported members in tls.Config
Without this, go vet complains

assignment copies lock value to n: crypto/tls.Config contains sync.Once
contains sync.Mutex
2016-06-22 12:04:08 -07:00
84c416491e Merge pull request #5739 from heyitsanthony/serialize-txn
etcdserver: make serialized txns auth-aware
2016-06-22 11:49:56 -07:00
caffcb7fbb *: go vet fix in go tip 2016-06-22 11:10:59 -07:00
30cfa30490 etcdserver: make serialized txns auth-aware 2016-06-22 10:51:42 -07:00
aafb2e9430 etcdserver: add lock to authApplier so serialized requests don't race 2016-06-22 10:51:42 -07:00
27ef4baa9c Merge pull request #5749 from gyuho/manual
*: misc typos and go vet fixes
2016-06-22 10:45:02 -07:00
6480066054 *: misc typos and go vet fixes 2016-06-22 10:32:13 -07:00
8d259d3cf1 Merge pull request #5745 from xiang90/count_client
clientv3: add withCount support
2016-06-22 10:04:06 -07:00
82991074bf Merge pull request #5733 from mitake/user-detail
etcdctl: a flag for getting detailed information of a user
2016-06-22 09:26:00 -07:00
0e7690780f etcdctl: a flag for getting detailed information of a user
This commit adds a new flag --detail to etcdctl user get command. The
flag enables printing the detailed permission information of the user
like below example:

$ ETCDCTL_API=3 bin/etcdctl --user root:p user get u1
User: u1
Roles: r1 r2
$ ETCDCTL_API=3 bin/etcdctl --user root:p user get u1 --detail
User: u1

Role r1
KV Read:
        [k1, k5)
KV Write:
        [k1, k5)

Role r2
KV Read:
        a
        b
        [k8, k9)
KV Write:
        a
        b
        [k8, k9)
2016-06-22 13:29:48 +09:00
6496ae005d clientv3: add withCount support 2016-06-21 21:17:35 -07:00
0b5ea3ec94 Merge pull request #5742 from xiang90/count
*: support count in range query
2016-06-21 19:42:08 -07:00
def21f11a9 *: support count in range query 2016-06-21 16:20:55 -07:00
5a6ad1ea76 Merge pull request #5738 from heyitsanthony/fp
build with failpoints
2016-06-21 15:02:45 -07:00
de68818f03 etcdserver: add some failpoints 2016-06-21 14:43:20 -07:00
7f8ffd7dbe test, build: support failpoints 2016-06-21 14:43:20 -07:00
6009e88077 test, build: make build script source-able without doing a build 2016-06-21 14:35:20 -07:00
99957e9831 Merge pull request #5736 from gyuho/cleanup
etcdctl/ctlv3: minor clean ups
2016-06-21 13:31:20 -07:00
80aa5978ca etcdctl/ctlv3: minor clean ups
- Fix typo
- Improve command ordering (elect should be below lock)
- Update migrate command description
2016-06-21 13:12:01 -07:00
c01c36bcfd Merge pull request #5735 from gyuho/auth_doc
etcdctl/ctlv3: document auth,user,role
2016-06-21 12:49:31 -07:00
e5d9ca5180 etcdctl/ctlv3: document auth,user,role 2016-06-21 12:46:42 -07:00
22bae02fe5 Merge pull request #5734 from xiang90/learning
doc: move docs to learning
2016-06-21 11:02:04 -07:00
7c12949b41 doc: move docs to learning 2016-06-21 10:49:46 -07:00
1b8e83ae60 Merge pull request #5732 from mitake/e2e-user-role-dyn-update
e2e: add test cases for updating user and role during operations
2016-06-21 09:54:18 -07:00
4106e56d91 e2e: check role revoking during operations 2016-06-21 15:52:36 +09:00
68bcbdc84e e2e: check user deletion during operations 2016-06-21 15:03:04 +09:00
d017814eaa Merge pull request #5722 from mitake/auth-v3-check-test
e2e: check runtime permission changing
2016-06-20 22:42:43 -07:00
8920e7c4d5 Merge pull request #5731 from gyuho/grpc_log
*: use capnslog for grpclog
2016-06-20 20:35:28 -07:00
a1c7a7df5e *: use capnslog for grpclog 2016-06-20 20:35:03 -07:00
6fe4d9d30a e2e: check runtime permission changing
This commit adds extends the test for checking runtime permission
grant/revoke.
2016-06-21 11:55:09 +09:00
6d81601df3 vendor: update capnslog 2016-06-20 19:39:15 -07:00
0cc59f3976 Merge pull request #5730 from gyuho/cli_dep
*: codegangsta/cli to urfave/cli
2016-06-20 16:54:15 -07:00
bdca594495 etcdctl/ctlv2: use latest Action interface 2016-06-20 16:34:28 -07:00
1e0ff8555e Merge pull request #5729 from xiang90/fix_bench
benchmark: fix watch bench
2016-06-20 16:02:09 -07:00
0ae9d444f9 ctlv2: use urfave/cli in ctlv2 2016-06-20 15:17:03 -07:00
c4df15ff3e vendor: codegangsta/cli to urfave/cli
For https://github.com/coreos/etcd/issues/3901.
2016-06-20 15:06:20 -07:00
ce180bbaf1 Merge pull request #5685 from heyitsanthony/multictx-watcher
clientv3: watch with arbitrary ctx values
2016-06-20 14:52:40 -07:00
d5696cb6ef Merge pull request #5712 from gyuho/curl_v3
e2e: grpc-gateway cURL tests
2016-06-20 14:48:29 -07:00
b4f0a8853b e2e: grpc-gateway cURL tests 2016-06-20 14:29:10 -07:00
1097d63ff7 clientv3/integration: test WithRequireLeader on Watch 2016-06-20 14:26:16 -07:00
2bd5d66596 benchmark: fix watch bench 2016-06-20 14:00:46 -07:00
a01f5a2786 Merge pull request #5728 from gyuho/log_dir
etcd-agent: set up directory for etcd logs
2016-06-20 13:25:25 -07:00
722f5b2a8c clientv3: watch with arbitrary ctx values
Sets up a new watch stream for every unique set of ctx values.

Fixes #5354
2016-06-20 12:44:51 -07:00
e5583b26eb Merge pull request #5711 from xiang90/client_bytes
*: add client network metrics
2016-06-20 12:03:18 -07:00
50f2f984e4 etcd-agent: set up directory for etcd logs 2016-06-20 11:32:14 -07:00
35fd81e465 *: add client network metrics 2016-06-20 11:18:06 -07:00
fb1f1ce1fd Merge pull request #5727 from xiang90/fix_watch_bench
benchmark: correctly count number of watchers
2016-06-20 11:00:18 -07:00
2a2dd1075f benchmark: correctly count number of watchers 2016-06-20 10:37:17 -07:00
729f5b45fd Merge pull request #5720 from xiang90/report_recv
*: fix pending events metrics
2016-06-20 06:44:16 -07:00
6e717775a8 Merge pull request #5723 from mitake/etcdctl-misc
etcdctl: slightly enhance output of role revoke-permission
2016-06-20 06:14:28 -07:00
0173564122 etcdctl: slightly enhance output of role revoke-permission 2016-06-20 16:57:50 +09:00
6f28b43806 *: fix pending events metrics 2016-06-19 23:00:39 -07:00
8111e0f7dc Merge pull request #5716 from ajityagaty/get_filtering
v3api: Add a flag to RangeRequest to return only the keys.
2016-06-19 14:50:15 -07:00
ad5d55dd4c v3api: Add a flag to RangeRequest to return only the keys.
Currently the user can't list only the keys in a prefix search. In
order to support such operations the filtering will be done on the
server side to reduce the encoding and network transfer costs.
2016-06-19 14:18:39 -07:00
23621387fc Merge pull request #5714 from gyuho/wal_dir
*: use fileutil.TouchDirAll
2016-06-19 12:02:46 -07:00
d37e564eaa etcdserver: use TouchDirAll 2016-06-19 11:26:52 -07:00
ce50ee14d8 Merge pull request #5710 from xiang90/rm_la
*: remove old flag support
2016-06-19 06:57:28 -07:00
eaa72dfa0b Merge pull request #5709 from gyuho/docker
update: Dockerfile, documentation
2016-06-18 19:57:34 -07:00
b03c832bed Merge pull request #5698 from gyuho/documentation
Documentation: grpc-gateway
2016-06-17 15:33:18 -07:00
3ddfa16c46 Documentation: update container.md 2016-06-17 15:22:13 -07:00
eec706b9ae etcdserverpb: generate Swagger API JSON 2016-06-17 15:19:32 -07:00
09e5db5a46 Documentation: add grpc-gateway doc 2016-06-17 15:19:28 -07:00
8ea6be38ba *: remove old flag support
These legacy flags support are here only because we do not want
CoreOS updates to break people.

Now people will be aware of that they switch to etcd3. Do not need
to support 0.x flags any more.
2016-06-17 14:51:45 -07:00
c25ff426af Dockerfile: build image with alpine 2016-06-17 14:42:40 -07:00
6dcd020d7d Merge pull request #5707 from heyitsanthony/test-all
test: don't hardcode packages for testing
2016-06-17 14:08:46 -07:00
3f6619ada9 Merge pull request #5708 from xiang90/pending
*: add pending/failed proposal metrics
2016-06-17 13:48:39 -07:00
9feb3d0e51 etcd-tester: fix goword warnings 2016-06-17 13:37:35 -07:00
f7b84d69a4 etcd-agent/client: fixup godocs 2016-06-17 13:37:35 -07:00
ea21b8ee1f lessor: fix go vet, goword warnings, and unreliable test 2016-06-17 13:37:25 -07:00
016be1ef31 contrib/recipes: fix govet and goword warnings 2016-06-17 13:13:09 -07:00
598fa7a10e *: add pending/failed proposal metrics 2016-06-17 13:09:38 -07:00
aa503f84d5 Merge pull request #5705 from xiang90/metrics_peer
*: add peer prefix for network metrics between peers
2016-06-17 12:38:06 -07:00
bd8627c8ab Merge pull request #5706 from xiang90/app_metrics
etcdserver: add applied metrics
2016-06-17 12:26:23 -07:00
6af0917812 *: add peer prefix for network metrics between peers 2016-06-17 11:59:49 -07:00
57474697af etcdserver: add applied metrics 2016-06-17 11:52:50 -07:00
74b13aab61 grpcproxy: fix go vet warnings 2016-06-17 11:41:49 -07:00
6c0882145a test: don't use hardcoded package lists for testing 2016-06-17 11:41:49 -07:00
e4f56c4eb6 Merge pull request #5701 from xiang90/rm_exp
*: make auto-compaction-retention non-experimental
2016-06-17 11:02:43 -07:00
8bb0ce54e6 Merge pull request #5704 from gyuho/agent_fix
etcd-agent: fix test
2016-06-17 10:58:14 -07:00
61659302db Merge pull request #5703 from gyuho/grpc_proto
Update gRPC, gogo/protobuf
2016-06-17 10:56:38 -07:00
63c13e8b98 etcd-agent: fix test 2016-06-17 10:47:15 -07:00
63901be674 *: regenerate proto 2016-06-17 10:22:28 -07:00
d03a3d141e vendor: update gRPC dependency 2016-06-17 10:22:16 -07:00
b0d7455fb1 scripts: use latest gogo/protobuf for proto files
For https://github.com/coreos/etcd/issues/5671.
2016-06-17 10:21:18 -07:00
d68664841c *: make auto-compaction-retention non-experimental 2016-06-17 10:04:31 -07:00
3488555bc3 Merge pull request #5674 from mitake/auth-v3-get-users-roles
*: support getting all users and roles in auth v3
2016-06-17 06:51:47 -07:00
18253e2723 *: support getting all users and roles in auth v3
This commit expands RPCs for getting user and role and support list up
all users and roles. etcdctl v3 is now support getting all users and
roles with the newly added option --all e.g. etcdctl user get --all
2016-06-17 16:22:41 +09:00
cc4f35887c Merge pull request #5699 from gyuho/readme
README: more demos, links
2016-06-16 22:57:31 -07:00
dde2aea214 Documentation: add 'migrate' command example 2016-06-16 19:47:57 -07:00
1066c9b806 README: add dash, play.etcd.io, animated demo link 2016-06-16 19:47:25 -07:00
2d08e093c1 Merge pull request #5696 from xiang90/fix_panic
etcdserver: fix panic when getting header of raft request
2016-06-16 13:58:50 -07:00
adff458895 etcdserver: fix panic when getting header of raft request 2016-06-16 13:42:10 -07:00
b3558894f2 Merge pull request #5695 from gyuho/proto
*: use latest protodoc, regenerate
2016-06-16 12:35:44 -07:00
c98ca2db43 Merge pull request #5493 from mqliang/cache
proxy: cache range request in proxy
2016-06-16 12:30:13 -07:00
5f5c3c8f82 Merge pull request #5694 from xiang90/comp
etcdserver: only pause compaction when sending snapshot
2016-06-16 12:26:55 -07:00
7f9adfd5b8 Merge pull request #5692 from xiang90/fix_live
raft: make tick unblock and fix potential live lock
2016-06-16 12:26:31 -07:00
0bae7b635c *: regenerate proto, doc 2016-06-16 11:57:46 -07:00
d26d006fd6 scripts: use latest protodoc to skip grpc-gateway
protodoc now skips grpc-gateway options
2016-06-16 11:57:05 -07:00
1c6070ccc7 Merge pull request #5693 from Jiaweizdev/update-port-number-in-proxy-doc
doc: update port number in proxy doc
2016-06-16 08:59:39 -07:00
699e76b631 etcdserver: only pause compaction when sending snapshot 2016-06-16 08:57:02 -07:00
fb165fcc58 doc: update port number 2016-06-16 17:13:52 +02:00
848f539536 raft: make tick unblock and fix potential live lock 2016-06-16 08:01:06 -07:00
49266dca2d Merge pull request #5690 from xiang90/fix_s
etcdserver: save state before save snapshot
2016-06-15 22:36:30 -07:00
9c78cda088 etcdserver: save state before save snapshot 2016-06-15 22:00:33 -07:00
b07fbbf27c Merge pull request #5687 from mitake/auth-v3-txn-2
etcdserver: permission checking of Txn() in authApplierV3
2016-06-16 12:51:10 +09:00
cdf1a2ee2c etcdserver: permission checking of Txn() in authApplierV3 2016-06-15 20:10:16 -07:00
5385ca0a43 Merge pull request #5659 from heyitsanthony/bridge-more-errors
bridge: packet corruption and reordering
2016-06-15 19:23:22 -07:00
11869905ae bridge: packet corruption and reordering
With bonus bridge connection code refactor.
2016-06-15 17:08:19 -07:00
555976ea84 Merge pull request #5684 from gyuho/test
etcd-agent: SIGQUIT when cleanup
2016-06-15 16:13:20 -07:00
bc69142940 Merge pull request #5683 from xiang90/fix_refresh
store: copy old value when refresh + cas
2016-06-15 16:11:26 -07:00
bd604a029e etcd-agent: SIGQUIT when cleanup 2016-06-15 16:03:25 -07:00
df56f9d6f9 store: copy old value when refresh + cas 2016-06-15 15:32:58 -07:00
b607b36a6c Merge pull request #5648 from ingvagabund/doc-nits
docs: Clustering.md: Switch "command line" and "environment variables"
2016-06-15 15:24:20 -07:00
c505f03c62 Merge pull request #5682 from cdancy/patch-2
Documentation: add gradle-etcd-rest-plugin to libraries-and-tools.md
2016-06-15 15:02:51 -07:00
f392370f73 Documentation: add gradle-etcd-rest-plugin to libraries-and-tools.md
Add link to the gradle-etcd-rest-plugin client under the 'Gradle plugins' sub-section.

Fixes #5681
2016-06-15 17:59:50 -04:00
7d666ab8b9 Merge pull request #5677 from gyuho/minor_etcdserver_fix
etcdserver: preallocate slices
2016-06-15 13:20:06 -07:00
32d766d749 etcdserver: preallocate slice 2016-06-15 13:03:10 -07:00
b98fa063c8 Merge pull request #5672 from heyitsanthony/applier-auth-layer
auth, etcdserver: separate auth checking apply from core apply
2016-06-15 10:06:34 -07:00
16db9e68a2 auth, etcdserver: separate auth checking apply from core apply 2016-06-15 09:03:27 -07:00
5676c5cf26 proxy: serve range request from proxy cache if set serializable 2016-06-15 14:12:36 +08:00
eca38c109a vendor:add groupcache lru package 2016-06-15 14:12:36 +08:00
16d86fd4f8 Merge pull request #5669 from xiang90/proto-gw
main: add grpc-gateway support
2016-06-14 17:46:00 -07:00
7f569a163c test: go vet should only test the go code in the dir 2016-06-14 17:09:06 -07:00
252adc0caf *: update dependencies 2016-06-14 17:09:06 -07:00
5a7b7f7595 main: add grpc-gateway support
Now etcd can serve HTTP json request at /v3alpha/
2016-06-14 17:09:06 -07:00
a6fec46c0e Merge pull request #5652 from gyuho/version
etcdctl/*: print API version
2016-06-14 16:04:24 -07:00
1e38ab1706 etcdctl: print API version (v2, v3 separate) 2016-06-14 15:33:39 -07:00
6958334db2 Merge pull request #5662 from xiang90/auth_delete
*: support deleteRange perm checking
2016-06-13 20:13:43 -07:00
c97107cf81 Merge pull request #5660 from heyitsanthony/fix-watch-test
e2e: don't Put() after watchTest finishes
2016-06-13 19:39:30 -07:00
a571bd0271 Merge pull request #5661 from xiang90/fix_subset
auth: fix remove subset when there are equal ranges
2016-06-13 19:03:10 -07:00
c75fa6fdc9 *: support deleteRange perm checking 2016-06-13 17:49:13 -07:00
e67613830e auth: fix remove subset when there are equal ranges 2016-06-13 17:13:55 -07:00
d78ef8bc72 e2e: don't Put() after watchTest finishes
Fixes #5598
2016-06-13 16:55:02 -07:00
a26ebfb675 Merge pull request #5654 from xiang90/auth_key
auth: add key support in merge func
2016-06-13 16:53:36 -07:00
38546a9d24 auth: use bytes equal when possible 2016-06-13 16:37:21 -07:00
390c89b7f9 auth: remove the special checking case for key auth 2016-06-13 16:37:20 -07:00
9be65414eb auth: add key support in merge func 2016-06-13 16:37:20 -07:00
2a018240e7 Merge pull request #5657 from gyuho/cleanup
etcd-tester: cleanup in compact error, log level
2016-06-13 15:15:52 -07:00
84953365a2 etcd-tester: cleanup in compact error, log level 2016-06-13 14:54:53 -07:00
18851e70b6 Merge pull request #5656 from gyuho/auth_bytes
make auth key, rangeEnd typed like mvcc ([]byte)
2016-06-13 14:41:19 -07:00
5d6af0b51f etcdserver: key, rangeEnd in []byte for auth 2016-06-13 14:21:25 -07:00
e9d2eb2b54 auth: key, range in []byte type
Fix https://github.com/coreos/etcd/issues/5655.
2016-06-13 14:21:22 -07:00
70a2add2b0 Merge pull request #5650 from gyuho/wal_update
wal: use bytes.Equal, other minor updates
2016-06-13 09:05:53 -07:00
b4aa4607cb wal: use bytes.Equal, other minor updates
- Replace reflect.Equal with bytes.Equal where possible
- Remove some TODOs
- Some minor simplifications
2016-06-13 01:33:53 -07:00
2e29bea8fe docs: Clustering.md: Switch command line and environment variables to reflect the order of examples right below 2016-06-13 10:23:21 +02:00
f25b3dbfc8 Merge pull request #5640 from xiang90/permcheck
auth: clean permission checking
2016-06-12 18:26:21 -07:00
667093bbd1 Merge pull request #5645 from gyuho/wal_simple
wal: simplify boolean return
2016-06-11 11:10:59 -07:00
3243795522 wal: simplify boolean return 2016-06-11 10:36:52 -07:00
4aaf7f94cf Merge pull request #5643 from hongchaodeng/doc-fix
v3 docs: ErrCompaction -> ErrCompacted
2016-06-11 01:40:58 -07:00
c11418b56c docs: v3 api, ErrCompaction -> ErrCompacted 2016-06-10 21:53:06 -07:00
bdb5a321d1 Merge pull request #5642 from gyuho/client
vendor: update grpc dependency
2016-06-10 21:09:52 -07:00
5225a4e4bc clientv3: fix client for grpc change
Fix https://github.com/coreos/etcd/issues/5638.
2016-06-10 20:40:46 -07:00
b2a531d5a3 vendor: update grpc dependency
For 59486d9c17
2016-06-10 20:40:06 -07:00
1bbe09eb3c auth: clean permission checking 2016-06-10 19:23:20 -07:00
cff5851956 Merge pull request #5639 from mitake/email
MAINTAINERS: updating email address of Hitoshi Mitake
2016-06-10 18:40:41 -07:00
6b80f0ad7e MAINTAINERS: updating email address of Hitoshi Mitake
I'm mainly using the updated email address for working.
2016-06-10 18:12:39 -07:00
ae366ba4f1 Merge pull request #5637 from xiang90/auth_clean
auth: cleanup get perm func
2016-06-10 18:12:07 -07:00
f99ff5d513 auth: cleanup get perm func 2016-06-10 16:36:51 -07:00
3eab6bef6a Merge pull request #5635 from xiang90/cl
auth: clean up range_perm_cache.go
2016-06-10 16:08:54 -07:00
c802c23e6d Merge pull request #5636 from xiang90/mt
MAINTAINERS: add Hitoshi as a maintainer of auth pkg
2016-06-10 16:07:04 -07:00
43db5515e7 MAINTAINERS: add Hitoshi as a maintainer of auth pkg 2016-06-10 15:55:57 -07:00
c6fae5d566 Merge pull request #5631 from raoofm/patch-8
Doc: Fault tolerance table
2016-06-10 15:49:36 -07:00
175c67a552 Merge pull request #5634 from gyuho/wal
wal: PrivateFileMode/DirMode as in pkg/fileutil
2016-06-10 15:41:43 -07:00
65ff76882b Merge pull request #5624 from xiang90/warn_apply
etcdserver: warn heavy apply
2016-06-10 15:28:27 -07:00
47d5257622 pkg/fileutil: expose PrivateFileMode/DirMode 2016-06-10 15:22:14 -07:00
77efe4cda9 auth: clean up range_perm_cache.go 2016-06-10 15:21:04 -07:00
4570eddc2c wal: PrivateFileMode/DirMode as in pkg/fileutil
To make it consistent with pkg/fileutil
2016-06-10 15:20:57 -07:00
3210bb8181 Merge pull request #5632 from xiang90/auth_store_cleanup
auth: cleanup store.go
2016-06-10 14:49:56 -07:00
a92ea417b4 Merge pull request #5534 from gyuho/readme
README: minor fix in README
2016-06-10 14:46:15 -07:00
64eccd519d etcdserver: warn heavy apply 2016-06-10 14:43:34 -07:00
bb6102c00c Merge pull request #5630 from xiang90/del_user
auth: add del functions for user/role
2016-06-10 14:28:36 -07:00
f8c1a50195 auth: cleanup store.go 2016-06-10 14:19:29 -07:00
2781553a9e Merge pull request #5615 from mitake/auth-v3-consistent-token
auth, etcdserver: make auth tokens consistent for all nodes
2016-06-10 14:19:21 -07:00
37ac90c419 Doc: Fault tolerance table 2016-06-10 17:12:36 -04:00
8776962008 auth: add del functions for user/role 2016-06-10 14:11:00 -07:00
ead5096fa9 auth, etcdserver: make auth tokens consistent for all nodes
Currently auth tokens are generated in the replicated state machine
layer randomly. It means one auth token generated in node A cannot be
used for node B. It is problematic for load balancing and fail
over. This commit moves the token generation logic from the state
machine to API layer (before raft) and let all nodes share a single
token.

Log index of Raft is also added to a token for ensuring uniqueness of
the token and detecting activation of the token in the cluster (some
nodes can receive the token before generating and installing the token
in its state machine).

This commit also lets authStore have simple token related things. It
is required because of unit test. The test requires cleaning of the
state of the simple token things after one test (succeeding test can
create duplicated token and it causes panic).
2016-06-10 13:55:37 -07:00
65abcc1a59 Merge pull request #5629 from xiang90/put_role
auth: cleanup
2016-06-10 13:53:34 -07:00
cf99d596f5 auth: cleanup get user and get role usage 2016-06-10 13:34:40 -07:00
0914d65c1f auth: add put role 2016-06-10 13:20:48 -07:00
e854fa1856 Merge pull request #5622 from heyitsanthony/e2e-auth-keys
e2e: auth key put test
2016-06-10 12:17:38 -07:00
cd569d640b Merge pull request #5600 from lucab/to-upstream/armored-sigs
doc: sign release artifacts in armor mode
2016-06-10 12:11:53 -07:00
aa56e47712 Merge pull request #5625 from xiang90/put_user
auth: add put_user
2016-06-10 12:10:21 -07:00
1e22137a9a e2e: test auth is respected for Puts 2016-06-10 11:43:06 -07:00
b3a0b0502c etcdserver: respect auth on serialized Range 2016-06-10 11:43:05 -07:00
ae30ab7897 auth: add put_user 2016-06-10 11:27:42 -07:00
247103c40b Merge pull request #5623 from xiang90/get_role
auth: add getRole
2016-06-10 11:17:59 -07:00
1958598a18 auth: add getRole 2016-06-10 10:59:34 -07:00
c459073c6d Merge pull request #5620 from xiang90/auth_recover
auth: implement recover
2016-06-10 10:35:03 -07:00
05f9d1b716 Merge pull request #5610 from gyuho/handle_timeout_error
etcd-tester: do not exit for compaction timeout
2016-06-10 09:47:54 -07:00
5631acdb8f etcd-tester: do not exit for compact timeout
Temporary fix for https://github.com/coreos/etcd/issues/5606.
2016-06-10 09:44:45 -07:00
ca4e78687e auth: implement recover 2016-06-10 09:37:37 -07:00
bdc7035c10 Merge pull request #5617 from liggitt/preallocation
fileutil: avoid double preallocation
2016-06-09 22:27:17 -07:00
4f7622fb9a fileutil: avoid double preallocation 2016-06-10 00:27:59 -04:00
d4ac09de0f Merge pull request #5612 from gyuho/index_bench
mvcc: add keyIndex, treeIndex Restore benchmark
2016-06-09 16:09:56 -07:00
6e32e8501a Merge pull request #5613 from xiang90/rootrole
*: add admin permission checking
2016-06-09 16:00:37 -07:00
7da1940dce Merge pull request #5607 from xiang90/raft_user
raft: add docker/swarmkit as notable raft users
2016-06-09 15:39:09 -07:00
f1c6fa48f5 *: add admin permission checking 2016-06-09 15:25:09 -07:00
6bbd8b7efb mvcc: add keyIndex benchmark test
Useful later when trying to optimize our restore operations.
2016-06-09 14:13:18 -07:00
a7c5058953 Merge pull request #5608 from heyitsanthony/clientv3-auth-opts
clientv3: use separate dialopts for auth dial
2016-06-09 12:56:59 -07:00
349eaf117a clientv3: use separate dialopts for auth dial
Needs to use a different balancer from the main client connection
because of the way grpc uses the Notify channel.
2016-06-09 10:38:57 -07:00
ab65d2b848 raft: add docker/swarmkit as notable raft users 2016-06-09 10:10:44 -07:00
78c957df41 Merge pull request #5603 from heyitsanthony/clientv3-close-keepalive
clientv3: close keepalive channel if TTL locally exceeded
2016-06-09 09:44:32 -07:00
0554ef9c39 clientv3/integration: tests for closing lease channel 2016-06-09 09:12:59 -07:00
e534532523 clientv3: close keep alive channel if no response within TTL 2016-06-09 09:12:59 -07:00
fb0df211f0 Merge pull request #5586 from xiang90/root
auth: add root user and root role
2016-06-09 00:23:45 -07:00
da2f2a5189 auth: add root user and root role 2016-06-08 19:55:08 -07:00
a548cab828 Merge pull request #5602 from gyuho/get_leader
clientv3/integration: WaitLeader to follower
2016-06-08 17:03:25 -07:00
753073198f clientv3/integration: WaitLeader to follower
Fix https://github.com/coreos/etcd/issues/5601.
2016-06-08 16:45:32 -07:00
77dee97c2f Merge pull request #5578 from mitake/auth-v3-range
auth, etcdserver: permission of range requests
2016-06-08 16:33:25 -07:00
253e313c09 *: support granting and revoking range
This commit adds a feature for granting and revoking range of keys,
not a single key.

Example:
$ ETCDCTL_API=3 bin/etcdctl role grant r1 readwrite k1 k3
Role r1 updated
$ ETCDCTL_API=3 bin/etcdctl role get r1
Role r1
KV Read:
        [a, b)
        [k1, k3)
        [k2, k4)
KV Write:
        [a, b)
        [k1, k3)
        [k2, k4)
$ ETCDCTL_API=3 bin/etcdctl --user u1:p get k1 k4
k1
v1
$ ETCDCTL_API=3 bin/etcdctl --user u1:p get k1 k5
Error:  etcdserver: permission denied
2016-06-08 14:58:25 -07:00
9dad78c68f Merge pull request #5599 from gyuho/e2e_fix
e2e: fix race in ranging test tables
2016-06-08 14:46:02 -07:00
bd5e1ea1c0 e2e: fix race in ranging test tables
Fix https://github.com/coreos/etcd/issues/5598.

race conditions were detected in iterating the test table
because the go func closure doesn't receive the 'puts' index
in the argument. This can cause the test to run wrong put
operations.
2016-06-08 13:44:05 -07:00
87d105c036 Merge pull request #5596 from heyitsanthony/wal-warn-slow-fsync
wal: warn if sync exceeds a second
2016-06-08 13:07:13 -07:00
6bb96074da auth, etcdserver: permission of range requests
Currently the auth mechanism doesn't support permissions of range
request. It just checks exact matching of key names even for range
queries. This commit adds a mechanism for setting permission to range
queries. Range queries are allowed if a range of the query is [begin1,
end1) and the user has a permission of reading [begin2, range2) and
[begin1, end2) is a subset of [begin2, range2). Range delete requests
will follow the same rule.
2016-06-08 11:57:32 -07:00
35329a1674 Merge pull request #5597 from gyuho/btree_dep
*: update google/btree dependency
2016-06-08 11:39:29 -07:00
0b7e5c70a5 *: update google/btree dependency 2016-06-08 11:23:49 -07:00
39eaa37dcf wal: warn if sync exceeds a second 2016-06-08 11:03:18 -07:00
ff2b24a8ac Merge pull request #5583 from heyitsanthony/grpc-nuke-waitstate
clientv3: use grpc balancer
2016-06-08 09:45:44 -07:00
4a13c9f9b3 clientv3: use grpc balancer 2016-06-08 09:24:13 -07:00
e551aec339 doc: sign release artifacts in armor mode
Release guide steps to artifacts signing defaults to binary
signatures, while producing .asc files.
This commit changes to armored signatures, also matching appc
requirements.

Fixes #5594
2016-06-08 17:51:54 +02:00
66a6ed63cb Merge pull request #5585 from xiang90/token_cleanup
etcdserver: make usernameFromCtx more go style
2016-06-08 08:08:58 -07:00
4d56f54898 Merge pull request #5590 from xiang90/user
auth: add getuser
2016-06-08 08:08:36 -07:00
7abc8f21eb integration: update tests for new grpc reconnection interface 2016-06-08 01:04:59 -07:00
62f8ec25c0 clientv3: use grpc reconnection logic 2016-06-08 01:04:59 -07:00
1823702cc6 integration: bridge connections to grpc server
Tests need to disconnect the network connection for the client to check
reconnection paths but closing a grpc connection closes the logical connection.
To disconnect the client, instead have a bridge between the server and
the client which can monitor and reset connections.
2016-06-08 00:34:53 -07:00
b382c2c86f vendor: update grpc 2016-06-07 22:46:43 -07:00
c6496dcff6 auth: add getuser 2016-06-07 22:43:04 -07:00
3e057129e2 Merge pull request #5588 from purpleidea/fix/test-typo
e2e: tests: fix small typo
2016-06-07 22:25:57 -07:00
0048782d97 e2e: tests: fix small typo
Found when trying to get the e2e tests to run on Fedora which they
don't because of https://github.com/kr/pty/issues/21
2016-06-08 01:14:11 -04:00
2da6fb6616 Merge pull request #5587 from gyuho/function
etcd-tester: retry for 'etcdserver: not capable'
2016-06-07 22:01:07 -07:00
350673f1f8 etcd-tester: retry for 'etcdserver: not capable'
Fix https://github.com/coreos/etcd/issues/5573.

Currently stresser starts at the same time as cluster start.
If the stresser got launched too fast/early, all stressers
exit from the error 'etcdserver: not capable', which
means the cluster is not ready yet. This adds additional
error checking, so stresser can retry.
2016-06-07 21:56:04 -07:00
cc1155c93b etcdserver: make usernameFromCtx more go style 2016-06-07 21:17:32 -07:00
9a14b796e0 Merge pull request #5582 from gyuho/watch_range_end
etcdctl: support watch with range_end
2016-06-07 17:08:49 -07:00
7eaf73d273 e2e: test watch command with 2 args 2016-06-07 16:52:19 -07:00
624d5eb0cb etcdctl: support range_end for watch command
Fix https://github.com/coreos/etcd/issues/5575.
2016-06-07 16:52:15 -07:00
50ef8f148c Merge pull request #5579 from gyuho/request_union
RequestOp, ResponseOp
2016-06-07 13:54:59 -07:00
1610391449 *: following changes for proto update 2016-06-07 13:33:03 -07:00
1e4d3603db clientv3,ctlv3: following changes for proto change 2016-06-07 13:32:36 -07:00
6e149e3485 etcdserver: following updates for proto change 2016-06-07 13:32:07 -07:00
ca630a0803 etcdserverpb: RequestOp, ResponseOp
Fix https://github.com/coreos/etcd/issues/5504.
2016-06-07 13:31:10 -07:00
0d1133178f Merge pull request #5574 from xiang90/auth
auth: make naming consistent
2016-06-07 11:24:29 -07:00
83ce1051ff auth: make naming consistent 2016-06-07 10:54:50 -07:00
4984d82d27 Merge pull request #5570 from heyitsanthony/rafthttp-snapshot-tests
rafthttp: snapshot testing
2016-06-06 16:02:22 -07:00
7f461b2df9 Merge pull request #5572 from heyitsanthony/fallocate-eintr-fallback
pkg/fileutil: fall back to truncate() if fallocate is interrupted
2016-06-06 15:24:42 -07:00
dc91da50b5 rafthttp: snapshot tests 2016-06-06 11:38:11 -07:00
93f114c76c snap: return errors if Message's snapshot is not entirely read 2016-06-06 11:38:11 -07:00
3aadb25c31 pkg/ioutil: exact readcloser
NewExactReadCloser wraps a ReadCloser so it returns errors if exact number
of bytes are not read.
2016-06-06 11:38:10 -07:00
5be39d2c84 wal: don't preallocate on old tail file
Code is only there to handle an edge case where the tail wasn't preallocated
already (e.g., via old etcd version or a crash). It also triggers tmpfs
corruption, so remove it.
2016-06-06 11:31:25 -07:00
9022137d2b Merge pull request #5567 from gyuho/wal_type
wal: minor fixes
2016-06-06 10:31:03 -07:00
54aac4ab7e pkg/fileutil: fall back to truncate() if fallocate is interrupted
Fixes #5558
2016-06-06 09:52:34 -07:00
008081ffb5 wal: minor fixes
- remove unnecessary type cast
- simply modulo operations
2016-06-06 09:43:19 -07:00
c63eaf45f9 Merge pull request #5566 from ktateish/fix-single-dash
*: replace '-' with '--' for long options
2016-06-05 21:38:29 -07:00
8b75a33398 *: replace '-' with '--' for long options
A long option should have double dashes (cf. #4595),
so are error messages.
2016-06-06 12:25:45 +09:00
3c2a47ea64 Merge pull request #5565 from gyuho/raft_doc
raft: small fix in doc
2016-06-05 19:16:08 -07:00
843c53192a raft: small fix in doc
'MsgBeat' is an internal type to signal the leader, not the message type
that gets sent to its followers. 'MsgHeartbeat' is the type sent to followers.
2016-06-05 17:47:46 -07:00
2baca91ee2 Merge pull request #5564 from mitake/auth-v3-cleaning
cleaning auth v3
2016-06-05 08:40:06 -07:00
94f22e8a07 *: rename RPCs and structs related to revoking
This commit renames RPCs and structs related to revoking.
1. UserRevoke -> UserRevokeRole
2. RoleRevoke -> RoleRevokePermission
2016-06-05 16:57:23 +09:00
60fc1e4d4e auth, etcdserver: error codes for revoking non existing role and permission
This commit adds error codes for representing revoking non existing
role (from user) and permission (from role).
2016-06-05 16:41:10 +09:00
8bebd8caa9 Merge pull request #5559 from gyuho/docker_guide
Documentation: add docker guide for v3
2016-06-04 19:14:48 -07:00
2f00b1e071 Documentation: add docker guide for v3 2016-06-04 16:43:44 -07:00
429b2eee58 Merge pull request #5548 from mitake/auth-v3-revoke-delete
revoke user, revoke role, and delete role in auth v3
2016-06-03 21:44:37 -07:00
c7a1423d45 *: support deleting a role in auth v3
This commit implements RoleDelete() RPC for supporting deleting a role
in auth v3. It also adds a new subcommand "role delete" to etcdctl.
2016-06-04 13:42:45 +09:00
0cb1343109 *: support revoking a key from a role in auth v3
This commit implements RoleRevoke() RPC for supporting revoking a key
from a role in auth v3. It also adds a new subcommand "role revoke" to
etcdctl.
2016-06-04 13:42:45 +09:00
957b07c408 *: support revoking a role from a user in auth v3
This commit implements UserRevoke() RPC for supporting revoking a role
from a user in auth v3. It also adds a new subcommand "user revoke" to
etcdctl.
2016-06-04 13:39:26 +09:00
3f1af453b9 Merge pull request #5560 from gyuho/lease_test
clientv3/integration: test lease closed connection
2016-06-03 18:23:03 -07:00
0cb4dd4331 clientv3/integration: test lease closed connection
Tests if lease operations return ErrConnClosed when
the client is closed.
2016-06-03 16:41:32 -07:00
6a35833fc3 Merge pull request #5450 from luxas/more_arches
travis: Catch compilation errors in CI for arm and ppc64le
2016-06-03 16:12:28 -07:00
c093234e3a Merge pull request #5557 from heyitsanthony/fix-watcher-cancel
mvcc: don't cancel watcher if stream is already closed
2016-06-03 11:28:54 -07:00
88afb0b0a6 Merge pull request #5543 from heyitsanthony/clientv3-unblock-reconnect
clientv3: don't hold client lock while dialing
2016-06-03 11:28:44 -07:00
6187d812da Merge pull request #5556 from xiang90/r_test
raft: fix TestNodeStepUnblock
2016-06-03 11:13:43 -07:00
f57b4eb46d mvcc: don't cancel watcher if stream is already closed
Close() already cancels all the watchers but doesn't bother to clear out
the bookkeeping maps so Cancel() may try to cancel twice.

Fixes #5533
2016-06-03 11:12:46 -07:00
7dfe7db243 clientv3: panic if ActiveConnection tries to return non-nil connection 2016-06-03 10:25:20 -07:00
267d1cb16f clientv3: fix watch to reconnect on failure
It was spinning before.
2016-06-03 10:25:20 -07:00
5f5a203e27 clientv3: don't hold client lock while dialing
Causes async reconnect to block while the client is dialing.

This was also causing problems with the Close error message, so
now Close() will return the last dial error (if any) instead of
clearing it out with a cancel().

Fixes #5416
2016-06-03 10:25:20 -07:00
500296d0fb raft: fix TestNodeStepUnblock
The test cases have side-effect. We need to stop testing if one of the test
fails. Also timeout should be much longer to avoid false-positive.
2016-06-03 10:22:11 -07:00
948dc5e425 Merge pull request #5552 from ktateish/fix-wrong-link
Fix wrong links
2016-06-03 10:06:13 -07:00
634b9584ef Merge pull request #5555 from xiang90/fix_rm
rafthttp: report error to correct chan
2016-06-03 09:48:43 -07:00
5183631f17 rafthttp: report error to correct chan 2016-06-03 09:18:02 -07:00
95fc21e38b travis: Catch compilation errors in CI for arm and ppc64le 2016-06-03 18:46:36 +03:00
5bff4d85d6 Doc: fix links using url for internal doc 2016-06-03 22:26:01 +09:00
9585daf0a9 Doc: fix wrong links and remove unused or duplicate ones 2016-06-03 22:23:57 +09:00
b3fee0abff Merge pull request #5539 from mitake/auth-v3-get-role
*: support getting role in auth v3
2016-06-02 21:48:45 -07:00
10ee69b44c *: support getting role in auth v3
This commit implements RoleGet() RPC of etcdserver and adds a new
subcommand "role get" to etcdctl v3. It will list up permissions that
are granted to a given role.

$ ETCDCTL_API=3 bin/etcdctl role get r1
Role r1
KV Read:
        b
        d
KV Write:
        a
        c
        d
2016-06-03 13:03:54 +09:00
755567cb3d Merge pull request #5547 from xiang90/int
integration: always return active client
2016-06-02 15:52:38 -07:00
bbfe7f401f integration: always return active client
In the integration test, we sometimes stop/restart an etcd server.
Now our client has internal connection monitoring logic that might
set conn to nil when there is a connection failure and the redial
also fails.

Chaning randClient to always return a client with active connection
to make integration test reliable.
2016-06-02 14:49:32 -07:00
85691dbbe5 Merge pull request #5546 from raoofm/patch-6
Doc: fix link for migrate command in v2-migration
2016-06-02 14:21:36 -07:00
6ac67ecd5c Doc: fix link for migrate command in v2-migration
Doc: fix link for migrate command in v2-migration
2016-06-02 17:19:43 -04:00
6d96dd581a Merge pull request #5545 from heyitsanthony/revert-more-i64
Revert "etcdserverpb: make RangeResponse.More an int64"
2016-06-02 14:09:31 -07:00
84a487f723 Revert "etcdserverpb: make RangeResponse.More an int64"
This reverts commit 84e1ab8765.
2016-06-02 13:43:40 -07:00
3005f2717f Merge pull request #5541 from xiang90/tls
transport: require tls12
2016-06-02 10:11:57 -07:00
8b28c647ea transport: require tls12 2016-06-02 09:38:56 -07:00
51a048e6b3 Merge pull request #5540 from xiang90/fix_snap
snap: fix write snap
2016-06-02 09:12:50 -07:00
2b77e9a086 Merge pull request #5538 from rustyrobot/fix-header-formatting
doc: fix header formatting
2016-06-02 07:58:27 -07:00
ab0ccdc4df snap: fix write snap
Do not use writeFile since it does not sync file before closing.
This can lead to slient file corruption when disk is full.
2016-06-02 07:38:48 -07:00
9098f27745 doc: fix header formatting 2016-06-02 16:15:08 +03:00
ab3398f7fd README: minor fix in README 2016-06-01 23:33:59 -07:00
29d2caf14a Merge pull request #5532 from xiang90/rh
rafthttp: simplify initialization funcs
2016-06-01 22:31:19 -07:00
a047aa4a81 rafthttp: rename to to peerID 2016-06-01 22:12:47 -07:00
c25c00fcf9 rafthttp: simplify initialization funcs 2016-06-01 21:47:46 -07:00
2fcac66605 Merge pull request #5530 from gyuho/build_script
scripts: include v2 README in the release
2016-06-01 20:59:33 -07:00
140e2a18fb Merge pull request #5492 from mitake/auth-v3-user-get
*: support getting user in etcdctl v3
2016-06-01 20:27:18 -07:00
5609fdb9a8 *: support getting user in etcdctl v3
This commit adds a new subcommand "user get" to etcdctl v3. It will
list up roles that are granted to a given user.

Example:
$ ETCDCTL_API=3 bin/etcdctl user get u1
User: u1
Roles: r1 r2 r3

This commit also modifies the layout of InternalRaftRequest for
frequent update of auth related members.
2016-06-02 12:10:19 +09:00
b95c5b7da9 Merge pull request #5526 from heyitsanthony/more-to-int64
etcdserverpb: make RangeResponse.More an int64
2016-06-01 20:03:15 -07:00
232c1914d2 scripts: include v2 README in the release 2016-06-01 19:12:34 -07:00
84e1ab8765 etcdserverpb: make RangeResponse.More an int64 2016-06-01 17:10:23 -07:00
9fee7732f6 Merge pull request #5468 from swingbach/master
implemented leader lease when quorum check is on.
2016-06-01 16:10:41 -07:00
337ef64ed5 raft: implemented leader lease when quorum check is on 2016-06-02 06:17:27 +08:00
fb64c8ccfe Merge pull request #5521 from heyitsanthony/clientv3-hide-retrydial
clientv3: hide retry dial api
2016-06-01 13:00:02 -07:00
bea4268a0b Merge pull request #5520 from gyuho/grpc_dep
vendor: update grpc dependency
2016-06-01 11:43:23 -07:00
c451a1b350 Merge pull request #5519 from gyuho/etcdctlv3_README
etcdctl: v3 as default README
2016-06-01 11:41:17 -07:00
240757729c etcdctl: make v3 as default README 2016-06-01 11:36:21 -07:00
22744566f4 clientv3: hide retry dial api 2016-06-01 11:36:16 -07:00
542b7dff64 vendor: update grpc dependency 2016-06-01 11:24:03 -07:00
a6144bdf3e Merge pull request #5507 from xiang90/failure
doc: add failures guide
2016-06-01 11:07:22 -07:00
fc33fd1aa6 doc: add failures guide 2016-06-01 11:06:44 -07:00
47ef5f7ca5 Merge pull request #5510 from gyuho/clientv3_fix
clientv3: watch resp with error when client close
2016-06-01 11:01:30 -07:00
75dc10574a clientv3: watch resp with error when client close 2016-06-01 10:39:48 -07:00
9ed3b446ca Merge pull request #5509 from heyitsanthony/clientv3-fix-concurrent-close
clientv3: fix deadlock on Get with concurrent Close
2016-06-01 07:37:28 -07:00
36fcc9e9d4 Merge pull request #5515 from xiang90/logging
*: more logging on critical state change
2016-06-01 07:04:36 -07:00
a83051d0fc clientv3: don't panic on Get if NewKV is created with a closed client 2016-06-01 05:53:21 -07:00
1d88130522 clientv3: fix deadlock on Get with concurrent Close 2016-06-01 05:53:21 -07:00
5cb7400cee Merge pull request #5508 from heyitsanthony/bench-stm-lock
concurrency, benchmark: additional stm support
2016-06-01 05:48:50 -07:00
8528c8c599 *: more logging on critical state change
Add more logging for better debugging purpose.
2016-05-31 23:31:03 -07:00
fc06dd1452 Merge pull request #5480 from heyitsanthony/fix-migrate-nov2
etcdctl: improve error message on migration without v2 keys
2016-05-31 15:18:56 -07:00
2d4c7d6886 Merge pull request #5506 from xiang90/r_rafthttp
rafthttp: simplify streamReader initilization
2016-05-31 15:00:52 -07:00
51551abef5 concurrency, benchmark: read-committed STM isolation policy 2016-05-31 14:35:27 -07:00
f34a9350c3 benchmark: benchmark stm workload with distributed mutex 2016-05-31 14:35:27 -07:00
bb2a3ea8d8 benchmark: respect stm isolation mode flag 2016-05-31 14:35:27 -07:00
7709cd84bb Merge pull request #5505 from heyitsanthony/v3rpc-watcher-close
v3rpc: fix race on ctrl channel when watcher stream closes
2016-05-31 14:24:10 -07:00
cc837dfc6d Merge pull request #5503 from gyuho/fix_clientv3
clientv3: handle nil connection after *Client.Close (KV)
2016-05-31 12:38:20 -07:00
86269ab5bf rafthttp: simplify streamReader initilization 2016-05-31 12:13:37 -07:00
7b5657cf1a clientv3: check if KV.Client is closed
For https://github.com/coreos/etcd/issues/5495.
2016-05-31 12:00:19 -07:00
d116c116fe clientv3: getRemote comment about release 2016-05-31 12:00:19 -07:00
b0d4a0a9bd integration: skip closed client in Terminate 2016-05-31 12:00:15 -07:00
283318d547 v3rpc: add ErrConnClosed for closed client
For https://github.com/coreos/etcd/issues/5495.
2016-05-31 11:15:01 -07:00
09e8f5782e v3rpc: fix race on closing watcher stream ctrl channel
Sometimes close would race with the recvLoop, leading the
recvLoop to write to a close channel.
2016-05-31 11:07:31 -07:00
41d3cea9b3 integration: test closing stream while creating watchers 2016-05-31 11:02:15 -07:00
310ebdd3e1 Merge pull request #5498 from heyitsanthony/wal-tmpfile-fixes
wal: improve tmp file handling
2016-05-31 11:01:29 -07:00
e39f436728 Merge pull request #5494 from xiang90/refactor_rafthttp
rafthttp: remove the newPipeline func
2016-05-31 09:35:47 -07:00
eb9b281741 Merge pull request #5502 from jonboulle/master
MAINTAINERS: remove extraneous space
2016-05-31 07:07:10 -07:00
05cc3c3dbb wal: limit number of tmp file names
This fixes a space leak if the etcd server is restarted in shorter and shorter
intervals causing the tmp files to stack up.
2016-05-31 06:25:23 -07:00
71a9d6fc8b wal: don't warn when opening wal directory with stale tmp files 2016-05-31 06:25:23 -07:00
6686833e51 e2e: check for empty string as etcdctl backup result
Was checking for an ignored wal file warning. Added support for
TMPDIR since repeated runs were failing on left over test data.
2016-05-31 06:25:23 -07:00
ad95ceea2f MAINTAINERS: remove extraneous space 2016-05-31 12:11:53 +02:00
6f8cc58214 Merge pull request #5490 from mitake/errcode
etcdserver, auth: not return grpc error code directly in the apply phase
2016-05-30 22:00:54 -07:00
cc2e0fad3e Merge pull request #5497 from purpleidea/feat/doc-clarify
docs: fix ordering of sentence so it's logical and more clear
2016-05-30 21:52:04 -07:00
2cd3a3bd59 etcdctl: improve error message on migration without v2 keys
Fixes #5478
2016-05-30 19:14:04 -07:00
9c767cbf98 Merge pull request #5464 from heyitsanthony/fix-victim-watchers
mvcc: tighten up watcher cancelation and revision handling
2016-05-30 20:09:39 -06:00
4aab13ac06 docs: fix ordering of sentence so it's logical and more clear 2016-05-30 22:07:31 -04:00
5144318af0 etcdserver, auth: not return grpc error code directly in the apply phase
Current permission checking mechanism doesn't return its error code
well. The internal error (code = 13) is returned to client and the
retry mechanism doesn't work well. This commit fixes the problem.
2016-05-31 11:04:34 +09:00
ba68d7bbe6 rafthttp: make newRemote simpler 2016-05-30 16:24:26 -07:00
efe0ee7e59 rafthttp: remove the newPipeline func
Using struct to initialize pipeline is better when we have many
fields to file in.
2016-05-30 16:19:50 -07:00
815bc5307f Merge pull request #5489 from linuxcer/master
etcdserver: fix typo in server.go
2016-05-30 15:20:02 -07:00
29cc568659 etcdserver: fix typo in server.go 2016-05-31 05:54:30 +08:00
4e5c24fcf9 Merge pull request #5487 from gyuho/mvcc_proto
mvcc: delete EXPIRE event type
2016-05-29 18:22:15 -07:00
c43e59338f etcdctl/ctlv3: remove mvccpb.EXPIRE in mirror cmd 2016-05-29 15:11:29 -07:00
3266c809e4 mvcc: delete EXPIRE event type
Addressing https://github.com/coreos/etcd/pull/5484#discussion_r65005236.
etcd v3 doesn't expire keys. It's either PUT of DELETE.
2016-05-29 14:54:38 -07:00
84e7fa149e Merge pull request #5439 from mitake/auth-v3-permcheck
do permission check in raft log apply phase
2016-05-28 19:05:31 -07:00
0184288479 Merge pull request #5419 from xiang90/raft_doc
raft: initial readme
2016-05-28 18:38:10 -07:00
5b2e130f09 raft: initial readme 2016-05-28 18:37:21 -07:00
a86ae1d969 Merge pull request #5483 from gyuho/client_typo
clientv3: fix panic message in OpPut
2016-05-28 12:11:56 -07:00
9a0fe2620e clientv3: fix panic message in OpPut 2016-05-28 11:55:28 -07:00
8e821cdc70 *: do permission check in raft log apply phase
This commit lets etcdserver check permission during its log applying
phase. With this change, permission checking of operations is
supported.

Currently, put and range are supported. In addition, multi key
permission check of range isn't supported yet.
2016-05-29 00:05:48 +09:00
90e9652f70 etcdserver: return error of apply result without touching response
Current etcdserver tries to return result.resp even if result.err is
not nil. A situation of result.resp == nil and result.err != nil can
happen and it results an error like below:

18:49:57 etcd1 | interface conversion: proto.Message is nil, not *etcdserverpb.PutResponse

This commit lets the functions return result.err if it is not nil.
2016-05-29 00:05:48 +09:00
cfb3f96c2b mvcc: tighten up watcher cancelation and revision handling
Makes w.cur into w.minrev, the minimum revision for the next update, and
retries cancelation if the watcher isn't found (because it's being processed
by moveVictims).

Fixes: #5459
2016-05-27 17:19:32 -07:00
c438310634 v3rpc: make watcher wait for its send goroutine to finish 2016-05-27 16:54:26 -07:00
20fc3e968f Merge pull request #5465 from gyuho/compact1
etcd-tester: log more for compact errors
2016-05-27 16:16:04 -07:00
099dd1d1fb Merge pull request #5477 from gyuho/readme
README: fix write/sec number
2016-05-27 15:52:27 -07:00
c13bf42ac6 README: fix write/sec number 2016-05-27 15:50:04 -07:00
0313484f17 Merge pull request #5476 from gyuho/latency_dodc
Documentation: add average latency numbers
2016-05-27 15:47:26 -07:00
79fac9ee6f Documentation: add average latency numbers 2016-05-27 15:46:35 -07:00
f7fbcf8209 Merge pull request #5475 from heyitsanthony/doc-pkgs
*: add missing godoc package descriptions
2016-05-27 16:37:49 -06:00
fc7da09d67 *: add missing godoc package descriptions
Fixes #4074
2016-05-27 15:15:26 -07:00
0df5bb0002 Merge pull request #5445 from gyuho/performance_doc
Documentation: add benchmark to performance.md
2016-05-27 15:09:03 -07:00
33daeb7464 Documentation: add benchmark to performance.md
Fix https://github.com/coreos/etcd/issues/5433.
2016-05-27 15:05:54 -07:00
d8f325dabf Merge pull request #5472 from xiang90/fix_cap
integration: move cap enabling to init
2016-05-27 11:42:07 -07:00
ac2859057a integration: move cap enabling to init 2016-05-27 11:12:07 -07:00
2d47211589 Merge pull request #5471 from xiang90/proxy_rand
httpproxy: init the rand that we use to randomize endpoints
2016-05-27 10:46:42 -07:00
c73e8fd946 httpproxy: init the rand that we use to randomize endpoints
This is actually does not change anything. The endpoints are already
randomized before feeding into proxy. But it makes the proxy more safe.
2016-05-27 10:28:03 -07:00
45b872fe5d Merge pull request #5470 from dnaeon/gru
docs: add Gru to the list of projects using etcd
2016-05-27 10:18:55 -07:00
6e4fa5e773 docs: add Gru to the list of projects using etcd 2016-05-27 20:17:57 +03:00
04039eb006 etcd-tester: more logs for compact operations 2016-05-27 09:55:13 -07:00
3ed5d28e2e etcd-tester: fix, clean up multiple things (#5462)
* etcd-tester: more logging, fix typo

* etcd-tester: fix prevCompactRev scope

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

* etcd-tester: move utils to bottom, clean up logs

And remove stresser operation inside defrag

* etcd-tester: separate update revision call

* etcd-tester: fix cleanup when case is -1
2016-05-26 11:37:49 -07:00
6acb3d67fb Merge pull request #5448 from xiang90/fix_refrsh
etcd: fix refresh feature
2016-05-26 09:53:13 -07:00
44b59e24eb Merge pull request #5455 from heyitsanthony/clientv3-url-endpoints
clientv3: handle URL scheme when given in endpoint
2016-05-26 10:25:27 -06:00
d117684086 Merge pull request #5453 from gyuho/protobuf_etcdctlv3
etcdctl/ctlv3: protobuf write-out for member list
2016-05-25 22:39:54 -07:00
5cba7080bc etcdctl/ctlv3: protobuf write-out for member list
Fix https://github.com/coreos/etcd/issues/5297.
2016-05-25 22:23:57 -07:00
86591d64c5 etcdctl: doc member list, others protobuf output 2016-05-25 22:17:45 -07:00
d7fa07cffa Merge pull request #5456 from gyuho/tester_fix
etcd-tester: fix compact timeout
2016-05-25 18:53:07 -07:00
4c7af825c7 etcd-tester: timeout per number of compact entries
Fix https://github.com/coreos/etcd/issues/5440.
2016-05-25 18:37:13 -07:00
5ab27e99f2 Merge pull request #5454 from gyuho/document_issue_5401
etcdserverpb: document how to prefix, range query
2016-05-25 17:07:53 -07:00
9dc0782f45 clientv3: handle URL scheme when given in endpoint
Fixes #5427
2016-05-25 18:01:36 -06:00
8a718f3e56 etcdserverpb: document prefix, range query
Fix https://github.com/coreos/etcd/issues/5401.
2016-05-25 16:53:36 -07:00
53084ebead etcd: fix refresh feature
When using refresh, etcd store v2 watch is broken. Although with refresh
store should not trigger current watchers, it should still add events into
the watchhub to make a complete history. Current store fails to add the event
into the watchhub, which causes issues.
2016-05-25 13:33:31 -07:00
9ea1705563 Merge pull request #5441 from mqliang/Rlock-GET
store: use Rlock when GET
2016-05-25 11:29:36 -07:00
84ded59f08 Merge pull request #5443 from raoofm/patch-5
Doc: fix typo in v2-migration.md
2016-05-24 09:35:42 -07:00
5002114127 Doc: fix typo in v2-migration.md 2016-05-24 11:44:40 -04:00
ffd3cb78d4 store: use Rlock when GET 2016-05-24 17:13:29 +08:00
f86dc5c7f7 Merge pull request #5438 from gyuho/proxy_log
proxy/httpproxy: fix v2 proxy log header
2016-05-23 16:49:26 -07:00
340df26883 Merge pull request #5435 from xiang90/cap
api: add v3rpc capability
2016-05-23 15:50:08 -07:00
dd8a36820e proxy/httpproxy: fix v2 proxy log header
Replace all with capnslog
2016-05-23 15:45:49 -07:00
1c544c3ba5 api: add v3rpc capability 2016-05-23 14:45:08 -07:00
663db2bbf8 Merge pull request #5410 from gyuho/e2e_migrate
e2e: test migrate command
2016-05-23 14:42:51 -07:00
23b14a8c8d e2e: add migrate cmd test 2016-05-23 14:27:51 -07:00
96d06d4f2c e2e: add Restart, Start, grpcEndpoints methods 2016-05-23 14:27:48 -07:00
6a8c65cba9 Merge pull request #5436 from gyuho/v3_doc
Documentation: updates for v3 release
2016-05-23 12:29:39 -07:00
fd7685f3a1 Documentation: add clientv3 links to libraries 2016-05-23 12:01:38 -07:00
d57164d0c8 README: throughput number in v3, add Doorman
Our v3 benchmark shows etcd v3 can do 40k writes per second.
1k throughput number is for etcd v2. Also adds YouTube's doorman
to example project lists.
2016-05-23 12:00:03 -07:00
3351ea1ae2 Procfile: v3 as default 2016-05-23 11:59:23 -07:00
ad9d18faa9 Merge pull request #5411 from xiang90/m_doc
doc: add app migration doc
2016-05-23 11:56:34 -07:00
a62e4e1e3a doc: add app migration doc 2016-05-23 11:53:44 -07:00
a3a4f51d90 Merge pull request #5434 from gyuho/log_integration
integration: add logs for debugging
2016-05-23 11:52:08 -07:00
4df91ae755 Merge pull request #5424 from gyuho/slice_pre_alloc
rafthttp: replace append with pre-allocated slice
2016-05-23 11:30:07 -07:00
ddbe46543d integration: add logs for debugging 2016-05-23 11:23:41 -07:00
f20573b576 Merge pull request #5426 from gyuho/log_compaction_done
mvcc: log when compaction is done
2016-05-21 09:33:50 -07:00
bf8cf39daf mvcc: use capnslog 2016-05-20 22:31:22 -07:00
4882330fd7 Merge pull request #5417 from heyitsanthony/watcher-victims
mvcc: reuse watcher batch from notify on blocked watch channel
2016-05-20 19:59:38 -07:00
394ce5f3b8 mvcc: move blocked unsynced watchers to victim list 2016-05-20 15:56:02 -07:00
5984e46364 mvcc: move blocked sync watcher work to victim list
Instead of holding the store lock while doing a lot of work like when syncung
unsynced watchers, the work from a blocked synced notify can be reused and
dispatched without holding the store lock for long.
2016-05-20 15:56:02 -07:00
c9264c5e65 rafthttp: replace append with pre-allocated slice 2016-05-20 15:20:55 -07:00
1226946e2d Merge pull request #5423 from purpleidea/feat/typos3
clientv3: fix typo
2016-05-20 14:45:20 -07:00
374b3ee40b clientv3: fix typo 2016-05-20 17:18:52 -04:00
4c36054610 Merge pull request #5420 from purpleidea/feat/typos2
Fix typos
2016-05-20 11:30:38 -07:00
edca3cbe44 clientv3: Fix typos
Found randomly when going through docs. HTH
2016-05-20 14:06:29 -04:00
0b34b236d6 mvcc: benchmark for synced watchers 2016-05-19 23:31:27 -07:00
751d5fa486 Merge pull request #5414 from swingbach/master
raft: fix tiny mistake of message type
2016-05-19 23:15:15 -07:00
ff9d16a2e0 raft: fix tiny mistake of message type 2016-05-20 14:04:08 +08:00
4ee60d6671 Merge pull request #5413 from mitake/test
test: remove a directory correctly
2016-05-19 21:58:14 -07:00
1727f278f2 test: remove a directory correctly
Current rm in the test script cannot the gopath/src correctly and
results test failure.
2016-05-20 13:42:36 +09:00
e9f3e809a6 Merge pull request #5409 from xiang90/doc
etcdctl: add migrate command into readme
2016-05-19 16:54:10 -07:00
628a38d906 etcdctl: add migrate command into readme 2016-05-19 16:53:47 -07:00
82c6408f38 Merge pull request #5406 from gyuho/clientv3_slice
clientv3/concurrency: preallocate slice in stm
2016-05-19 14:57:19 -07:00
fa1e40c120 clientv3/concurrency: preallocate slice in stm 2016-05-19 14:42:19 -07:00
8c17674cda Merge pull request #5404 from gyuho/watch_optimize
mvcc: remove defer in watchable store
2016-05-19 14:08:37 -07:00
be4fb634a1 Merge pull request #5279 from gyuho/demo
Documentation: add animated quick demo
2016-05-19 14:03:27 -07:00
aa85cf037f mvcc: remove defer in watchable store 2016-05-19 13:51:51 -07:00
54536af135 Merge pull request #5405 from gyuho/watch_client
clientv3: preallocate watch streams slice
2016-05-19 13:21:44 -07:00
f9306fb817 clientv3: preallocate watch streams slice
To avoid slice growth when appending
2016-05-19 12:55:55 -07:00
edb11881f8 Merge pull request #5391 from xiang90/migrate
etcdctl: add migrate command
2016-05-19 12:33:11 -07:00
6f2e7875aa etcdctl: add migrate command
Migrate command accepts a datadir and an optional user-provided
transformer function that transform v2 keys to v2 keys.

Migrate command then builds a v3 backend state based on the existing
v2 keys and the output of the transformer function.
2016-05-19 12:17:15 -07:00
61a7d3efb3 Merge pull request #5392 from gyuho/watch_bench
benchmark: fix watch command
2016-05-19 10:12:24 -07:00
9ca84e814f benchmark: fix watch command
Fix https://github.com/coreos/etcd/issues/5099.
2016-05-19 09:57:35 -07:00
8e4a83c830 Merge pull request #5400 from rkrambovitis/patch-2
doc: fix https omission in documentation.
2016-05-19 08:07:27 -07:00
38ebb6b475 doc: fix https omission in documentation.
doc: added missing (http)s to tls setup guide

This fixes a minor documentation omission, where the 1st initial-advertise-peer-url for tls setup appears to be http.

fixes documentation
2016-05-19 18:04:52 +03:00
9ea181e561 Merge pull request #5388 from swingbach/master
raft: add more assertions on dueling candidates test case
2016-05-19 06:59:35 -07:00
1e54117580 raft: add more comments for dueling candidates test case 2016-05-19 13:51:20 +08:00
c703ccab63 raft: add more assertions for dueling candidates test case 2016-05-19 13:50:14 +08:00
62b4d1cef7 Merge pull request #5394 from heyitsanthony/clientv3-no-close-conn
clientv3: don't reuse closed connection and ignore "transport is closing"
2016-05-18 15:52:21 -07:00
e4a2dcad9e clientv3/integration: ignore closing transport in TestKVPutStoppedServerAndClose
The grpc "transport is closing" error is rasied when the host is unreachable;
there's no good way to avoid it for a Put.

Fixes #5343
2016-05-18 14:49:39 -07:00
782a8802c0 clientv3: avoid reusing closed connection in KV 2016-05-18 14:46:17 -07:00
26783f51b1 Documentation: add animated quick demo 2016-05-18 11:28:27 -07:00
dc073e1aa7 Merge pull request #5383 from gyuho/kvstore_byte_pool
mvcc: use buffer bytes to encode consistent index
2016-05-18 10:32:33 -07:00
77775e8e92 mvcc: preallocate bytes buffer for saveIndex 2016-05-18 10:01:57 -07:00
90498b3756 Merge pull request #5385 from gyuho/fix_backup_test
e2e: wait for member publishing after backup
2016-05-17 21:57:52 -07:00
f2b2e0761a e2e: wait for member publishing after backup 2016-05-17 21:39:04 -07:00
81b4e6d332 Merge pull request #5384 from mitake/genproto
scripts: pass -u to go get in genproto.sh
2016-05-17 20:49:36 -07:00
db9ccb75bf scripts: pass -u to go get in genproto.sh
Current genproto.sh doesn't pass -u option to go get. It is
problematic because the script depends on a specific version of
gogoproto. Actually it causes build error if a repository already have
an old version of gogoproto that doesn't have a specified commit
($SHA). This commit lets the script pass -u to go get for avoid the
error.
2016-05-18 11:38:51 +09:00
7678fc153a Merge pull request #5382 from gyuho/rafthttp_timeout
rafthttp: fix TestSendMessageWhenStreamIsBroken
2016-05-17 16:22:02 -07:00
d20cb40f4f rafthttp: fix TestSendMessageWhenStreamIsBroken
Fix https://github.com/coreos/etcd/issues/5381.

In case CI being slow that taking more than 10ms.
2016-05-17 16:03:54 -07:00
ecf192556e Merge pull request #5380 from gyuho/backup_e2e_test
e2e: v2 backup test
2016-05-17 15:56:24 -07:00
06950e41b4 e2e: v2 backup test
Fix https://github.com/coreos/etcd/issues/5367.
2016-05-17 15:35:39 -07:00
fb8d12a9cd Merge pull request #5379 from heyitsanthony/fix-snapshot-close-wal
etcdserver: wait for snapshots before closing raft
2016-05-17 15:19:41 -07:00
73204e9637 etcdserver: wait for snapshots before closing raft
Fixes #5374
2016-05-17 15:04:25 -07:00
1a06f5dab5 Merge pull request #5359 from mischief/bolt-openbsd
mvcc: set bolt options to nil for non-linux systems
2016-05-17 13:32:37 -07:00
f65331b456 Merge pull request #5376 from gyuho/e2e_typo
e2e: add 'force-new-cluster' flag, fix typo
2016-05-17 13:29:58 -07:00
00a2dca619 Merge pull request #5378 from gyuho/boltdb_update
vendor: update boltdb to v1.2.1
2016-05-17 13:26:29 -07:00
86c85b88ad Merge pull request #5377 from purpleidea/bug/typos
clientv3: fix typos
2016-05-17 12:51:13 -07:00
dd8e81070a e2e: add force-new-cluster flag 2016-05-17 12:48:26 -07:00
63e6228a0b e2e: fix typo(isClientAuthTLS to isClientAutoTLS) 2016-05-17 12:47:21 -07:00
e4e4c9dc2c mvcc: set bolt options to nil for non-linux systems 2016-05-17 12:46:44 -07:00
bc5f626e56 vendor: update boltdb to v1.2.1 2016-05-17 12:42:38 -07:00
42f3b4964f clientv3: fix typos 2016-05-17 15:39:56 -04:00
0269afd643 Merge pull request #5375 from gyuho/admin_guide_typo
Documentation/v2: fix typo for updating a member
2016-05-17 11:47:09 -07:00
e2fe80393e Documentation/v2: fix typo for updating a member
Fix https://github.com/coreos/etcd/issues/5358.
2016-05-17 11:44:39 -07:00
3c78523643 Merge pull request #5373 from gyuho/table-write-out
Documentation: write-out=table for v3 commands
2016-05-17 10:46:50 -07:00
6a0148e214 Documentation: write-out=table for v3 commands 2016-05-17 10:45:18 -07:00
3c8301358c Merge pull request #5371 from gyuho/auth_doc
Documentation/v2: fix auth_api.md bug
2016-05-17 10:22:12 -07:00
21c9da1ed4 Documentation/v2: fix auth_api.md bug
role guest read and write is "/*", not "*", same with other roles.
2016-05-17 09:42:38 -07:00
7014f6861d Merge pull request #5361 from mitake/auth-v3-token-credential
RFC: *: attach auth token as a gRPC credential
2016-05-16 21:45:44 -07:00
6259318521 *: attach auth token as a gRPC credential
This commit adds a functionality of attaching an auth token to gRPC
connection as a per RPC credential.

For doing this, this commit lets clientv3.Client.Dial() create a
dedicated gRPC connection for doing authentication. With the dedicated
connection, the client calls Authenticate() RPC and obtain its
token. The token is attached to the main gRPC connection with
grpc.WithPerRPCCredentials().

This commit also adds a new option --username to etcdctl (v3). With
this option, etcdctl attaches its auth token to the main gRPC
connection (currently it is not used at all).
2016-05-17 13:26:12 +09:00
327b01169c Merge pull request #5353 from heyitsanthony/clientv3-throttle-reconn
clientv3: throttle reconnection rate
2016-05-16 13:41:28 -07:00
f6e5fe6877 Merge pull request #5368 from heyitsanthony/sshot-hash
v3rpc, etcdctl: snapshot integrity hash
2016-05-16 13:09:02 -07:00
798718c49b etcdctl: verify snapshot hash on restore
Fixes #4097
2016-05-16 12:08:08 -07:00
ac2e3e43bf v3rpc: add sha trailer to snapshot 2016-05-16 11:15:03 -07:00
e8101ddf09 clientv3: throttle reconnection rate
Client was reconnecting after establishing connections because the lease
and watch APIs were thrashing. Instead, wait a little before accepting
new reconnect requests.
2016-05-16 11:14:45 -07:00
3c3bb3f97c godep: add golang.org/x/time/rate 2016-05-16 11:14:45 -07:00
a663828a32 Merge pull request #5366 from xiang90/fix_restore
raft: do not panic when removing all the nodes from cluster
2016-05-16 10:45:48 -07:00
29c77dee74 Merge pull request #5298 from purpleidea/feat/newurlsmap
pkg/types: Build a urls map from a string map
2016-05-16 10:39:14 -07:00
8ffbaef502 Merge pull request #5364 from heyitsanthony/fix-election-wait
integration: fix TestElectionWait
2016-05-16 10:30:17 -07:00
e52fc2d07e Merge pull request #5363 from heyitsanthony/fix-test-wait
test: fix wait on integration tests
2016-05-16 10:28:45 -07:00
910781ef5b raft: do not panic when removing all the nodes from cluster 2016-05-16 10:04:17 -07:00
c21b885dd5 integration: fix TestElectionWait
elections are now per-session so waiting on the same election with the
same client will not block like before

Fixes #5362
2016-05-16 07:32:42 -07:00
e312bb675c test: fix wait on integration tests
Typo was causing failed tests to look like they passed on CI.
2016-05-16 06:32:38 -07:00
46481b17fc Merge pull request #5356 from xiang90/grpc-proxy
proxy: initial grpc kv service proxy
2016-05-14 12:31:06 -07:00
2d3a8541d0 Merge pull request #5355 from heyitsanthony/cluster-security-doc
doc: add TLS examples to clustering guide
2016-05-14 10:44:06 -07:00
d41ce0a97c pkg/types: Add tests for NewURLsMapFromStringMap 2016-05-14 10:48:56 -04:00
17e23769d9 pkg/types: gofmt existing code 2016-05-14 09:33:58 -04:00
029fe6bf47 pkg/types: Build a urls map from a string map
This adds a simple transformation function which is helpful when
manipulating the different etcd internal data representations.
2016-05-14 09:33:58 -04:00
ec2ac72585 proxy: initial grpc kv service proxy 2016-05-13 23:00:29 -07:00
25850e0070 doc: add TLS examples to clustering guide
Fixes #3595
2016-05-13 17:10:41 -07:00
deb21d3da5 Merge pull request #5352 from xiang90/p
integration: remove parallel testing
2016-05-13 13:24:36 -07:00
410c5cd828 Merge pull request #5351 from gyuho/allow_null_key
etcdctl/ctlv3: allow empty key
2016-05-13 12:26:59 -07:00
c7c0e1eb7a integration: remove parallel testing
We cannot do testing in parallel since leak testing will detect the goroutines
in other tests running in parallel.
2016-05-13 12:01:25 -07:00
002090daec e2e: test empty key for get command 2016-05-13 11:30:36 -07:00
3ec627d1a8 etcdctl/ctlv3: allow empty key
Fix https://github.com/coreos/etcd/issues/5323.
2016-05-13 11:29:58 -07:00
8c953499fa Merge pull request #5349 from heyitsanthony/clientv3-conc-fixups
clientv3/concurrency: ctx-izations and session leader ids
2016-05-13 10:33:55 -07:00
120020fa9c clientv3/concurrency: use session id for election keys to avoid deadlock 2016-05-13 10:07:35 -07:00
393725fe5f clientv3/concurrency: ctx-ize Leader(), Resign(), and Unlock() 2016-05-13 10:07:35 -07:00
2e93c65c96 bridge: fix command line flag handling
flag package expects flags in Argv[1:] and stops on non-flag arguments
but bridge was expecting the forwarding address in os.Argv[1]
2016-05-13 10:07:35 -07:00
4d2424210f Merge pull request #5313 from xiang90/fix_raft_abort
raft: simplify leadership transfer
2016-05-13 09:26:01 -07:00
4612e2d59a Merge pull request #5340 from heyitsanthony/etcd-runner-election
etcd-runner: election mode
2016-05-12 22:53:35 -07:00
4fe91ed1e2 etcd-runner: election mode 2016-05-12 22:32:33 -07:00
215afb9b1d etcd-runner: refactor round code 2016-05-12 22:32:33 -07:00
66e5e4f298 Merge pull request #5344 from gyuho/license_authors
*: update LICENSE header
2016-05-12 21:18:35 -07:00
71e6c4b06a .header: update to 'etcd Authors' 2016-05-12 20:56:50 -07:00
ef44f71da9 *: update LICENSE header 2016-05-12 20:51:48 -07:00
c538e0f9a9 etcdctl: update LICENSE header 2016-05-12 20:51:39 -07:00
2a44b9636a auth: update LICENSE header 2016-05-12 20:51:14 -07:00
fd9e07a529 clientv3: update LICENSE header 2016-05-12 20:50:58 -07:00
9d9f02c1ee mvcc: update LICENSE header 2016-05-12 20:50:33 -07:00
3d523e34b1 tools: update LICENSE header 2016-05-12 20:50:17 -07:00
4a5befc2de wal: update LICENSE header 2016-05-12 20:50:04 -07:00
abb4cd5646 etcdserver: update LICENSE header 2016-05-12 20:49:40 -07:00
bd71a60875 rafthttp: update LICENSE header 2016-05-12 20:49:28 -07:00
fe884f8209 raft: update LICENSE header 2016-05-12 20:49:15 -07:00
8b77de4e99 pkg: update LICENSE header 2016-05-12 20:48:53 -07:00
a880e9c7cb Merge pull request #5332 from xiang90/sl
*: cancel required leader streams when memeber lost its leader
2016-05-12 20:24:34 -07:00
15c5259e2d Merge pull request #5328 from gyuho/require_leader
requireHasLeader client side
2016-05-12 19:53:43 -07:00
9c103dd0de *: cancel required leader streams when memeber lost its leader 2016-05-12 19:42:21 -07:00
68eaf4083a clientv3: WithRequireLeader 2016-05-12 19:25:42 -07:00
431c4e7b3b Merge pull request #5342 from gyuho/grpc_dep
cmd/vendor: update grpc (upstream)
2016-05-12 19:23:31 -07:00
711be0a567 cmd/vendor: update grpc (upstream) 2016-05-12 19:02:30 -07:00
f4d1501198 Merge pull request #5337 from gyuho/configurable_monitor_interval
etcdmain: gateway monitor-interval flag
2016-05-12 18:58:52 -07:00
a32aabc377 proxy/tcpproxy: add more logs 2016-05-12 17:48:36 -07:00
750273afd9 Merge pull request #5339 from gyuho/protodoc_fix
*: fix protodoc, consistent casing in api doc
2016-05-12 17:39:06 -07:00
78d46b71fa Merge pull request #5336 from heyitsanthony/fix-clientv3-failput-close-crash
clientv3: fix Close after failed Put
2016-05-12 17:32:49 -07:00
9a6daefb3e etcdmain: add retry-delay flag 2016-05-12 17:03:00 -07:00
62e5ffac13 Merge pull request #5338 from gyuho/proxy_log
httpproxy: fix capnslog log path
2016-05-12 16:58:32 -07:00
b1f95c314b *: fix protodoc, consistent casing in api doc
There was a bug in protodoc.
This changes git SHA to use the latest protodoc.
And make the letter casing consistent with original
Protocol Buffer. Go capitalizes the member variables,
but the protocol buffer documentation should be same as
original proto files.
2016-05-12 16:23:29 -07:00
527aa1a499 clientv3: fix Close after failed Put
Was crashing on a nil connection. Reworked the shutdown path a little so
there's only one connection close site.
2016-05-12 16:16:27 -07:00
25d9169e9a httpproxy: fix capnslog log path
We changed the package path, so log paths needs to be updated as well.
2016-05-12 15:56:40 -07:00
fb65d04291 Merge pull request #5329 from gyuho/typo_integration
integration: fix NewClientV3 error messages
2016-05-12 10:49:14 -07:00
78ae4b92a6 integration: fix NewClientV3 error messages 2016-05-12 10:26:27 -07:00
2e011053b1 Merge pull request #5326 from mortonfox/patch-1
README: Update link to configuration.md
2016-05-11 22:33:54 -07:00
9c05f92f2e README: Update link to configuration.md
The file, along with all other documentation files, has moved into the Documentation folder.
2016-05-12 00:57:30 -04:00
9acb7ab41c Merge pull request #5325 from heyitsanthony/fix-partial-wal-init
wal: atomically initialize wal directory
2016-05-11 18:01:04 -07:00
6fc3106e68 Merge pull request #5324 from xiang90/partitioned
*: etcd member rejects unary call with leader requirement when it does not have leader
2016-05-11 17:48:06 -07:00
17391336af wal: atomically initialize wal directory
Fixes #5270
2016-05-11 16:50:17 -07:00
19221b33cc *: etcd member rejects unary call with leader requirement when it does not have leader 2016-05-11 16:34:34 -07:00
be0c38ec2b Merge pull request #5322 from heyitsanthony/port-docs
scrub legacy ports and update tls information
2016-05-11 16:32:45 -07:00
dcb3b7aecf *: scrub legacy ports from code and scripts 2016-05-11 13:46:30 -07:00
db8f5771f1 doc: scrub legacy ports and TLS information for v3 2016-05-11 13:46:29 -07:00
b03a2f0323 Merge pull request #5318 from heyitsanthony/watcher-latency
batch watcher sync to reduce request latency
2016-05-11 12:53:20 -07:00
080272be17 mvcc: limit total watchers synced per sync
Fixes #4567
2016-05-11 11:16:43 -07:00
f5165a0149 benchmark: make number of watcher streams configurable in watch-get
Each stream uses a client goroutine and a grpc stream; the setup causes
considerable client-side latency on the first get requests.
2016-05-11 11:16:43 -07:00
2aa4dd52cc benchmark: use separate connection for get in watch-get
The watcher traffic interferes with the get latency when sharing connections.
2016-05-11 11:16:43 -07:00
ca105a1c89 Merge pull request #5319 from xiang90/fix_rafthttp_test
*: fix TestTransportErrorc
2016-05-11 11:01:43 -07:00
e90313c9c2 Merge pull request #5321 from gyuho/doc_fix
*: fix minor typos
2016-05-11 10:58:36 -07:00
3104507eb2 *: fix minor typos 2016-05-11 10:55:38 -07:00
b2eb90024f Merge pull request #5320 from gyuho/issue518
v2/README: add known bugs
2016-05-11 10:45:40 -07:00
aaefd52afa Merge pull request #5092 from xiang90/etcdlet
*: gateway initial commit
2016-05-11 10:36:02 -07:00
5023996d02 v2/README: add known bugs
For https://github.com/coreos/etcd/issues/518.
2016-05-11 10:35:41 -07:00
00b660cc53 Merge pull request #5309 from xiang90/d_metrics
*: add disk operation metrics for monitoring
2016-05-11 10:18:39 -07:00
4d0f474034 *: fix TestTransportErrorc
CI can be slow. We should just wait longer.
2016-05-11 10:09:40 -07:00
a300be92dc *: initial support for gatway
etcd gatway is a simple l4 gateway that forwards tcp connections to
the given endpoints.
2016-05-11 09:44:50 -07:00
0fb7cb8b00 *: add disk operation metrics for monitoring 2016-05-11 09:36:45 -07:00
5ddb532072 Merge pull request #5314 from gyuho/test-script
test: fix typo, clean-up print statements
2016-05-10 23:51:05 -07:00
fd7e2b20b0 test: fix typo, clean-up print statements 2016-05-10 23:05:58 -07:00
82a6de8b69 raft: simplify leadership transfer 2016-05-10 20:03:42 -07:00
62d4c6d357 Merge pull request #5312 from ajityagaty/backup
etcdctl: Add --wal-dir and --backup-wal-dir options to backup command.
2016-05-10 19:51:30 -07:00
23f9d72870 etcdctl: Add --wal-dir and --backup-wal-dir options to backup command.
If the WAL is stored in a separate directory then the backup command
would need a --wal-dir option to pick the path to the WAL directory.
The user might also want to store the backup of data and wal separately
for which --backup-wal-dir option is provided.
2016-05-10 18:38:56 -07:00
d8215c8892 Merge pull request #5310 from gyuho/timeout_v2
etcdctl/ctlv2: total-timeout for Sync
2016-05-10 15:02:33 -07:00
62a9209088 etcdctl/ctlv2: total-timeout for Sync
Fix https://github.com/coreos/etcd/issues/4897.
2016-05-10 14:20:05 -07:00
6b2d7f9412 Merge pull request #5308 from heyitsanthony/fix-init-notify
etcdmain: notify systemd when etcd is ready to accept requests
2016-05-10 13:55:06 -07:00
8c4958dd60 etcdmain: notify systemd when etcd is ready to accept requests
Fixes #5151
2016-05-10 13:36:46 -07:00
5cbd8cefc9 Merge pull request #5291 from xiang90/c_i
*: add proposalsCommitted metrics
2016-05-10 12:51:28 -07:00
ab11415d25 *: add proposalsCommitted metrics 2016-05-10 10:56:25 -07:00
dad1197c89 Merge pull request #5303 from heyitsanthony/bench-watch-unsync
benchmark: watch-get for testing unsynced watcher/get contention
2016-05-10 10:31:45 -07:00
467de8cb4f benchmark: watch-get for testing unsynced watcher/get contention 2016-05-10 10:24:40 -07:00
efcba23d21 Merge pull request #5301 from gyuho/simple_member
etcdctl/ctlv3: make 'table' printer configurable
2016-05-10 10:12:54 -07:00
3e088b3b40 etcdctl/ctlv3: make 'table' printer configurable
Fix https://github.com/coreos/etcd/issues/5296.
2016-05-10 10:02:02 -07:00
8daad8e06e Merge pull request #5305 from ajityagaty/conf_file
Doc: Add the new '--config-file' detail to configuration.md file
2016-05-10 07:58:55 -07:00
97a2ebe3a2 Doc: Add the new '--config-file' detail to configuration.md file
Add a description about the --config-file option into the
configuration.md file.
2016-05-10 07:50:37 -07:00
fa6670488d Merge pull request #5302 from xiang90/conf-file
*: move sample config file to root directory
2016-05-10 07:46:38 -07:00
4ae47ad934 Merge pull request #5294 from xiang90/r_metrics
*: simplify network metrics
2016-05-09 22:50:45 -07:00
98dbdd5fbb *: simplify network metrics 2016-05-09 22:37:12 -07:00
00398ec98d *: move sample config file to root directory 2016-05-09 21:36:09 -07:00
07c04c7c75 Merge pull request #5280 from ajityagaty/server_config_file
etcd: Configuration file for etcd server.
2016-05-09 19:52:09 -07:00
8bc5ab9f8d etcd: Configuration file for etcd server.
Added a new command line option to etcd server to read in a YAML
based configuration file. I've also added an example configuration
file with comments and a set of test cases.
2016-05-09 18:17:27 -07:00
0d43a2b7e7 Merge pull request #5295 from ajityagaty/auth_disable
auth: Adding support for "auth disable" command.
2016-05-07 23:09:37 -07:00
adc981c53d auth: Adding support for "auth disable" command.
Added support for the auth disable command in the server, added the
etcdctl command and a respective testcase.
2016-05-07 19:21:49 -07:00
53491aac0a Merge pull request #5250 from heyitsanthony/fix-wal-write-tear
wal: repair torn writes
2016-05-06 17:14:56 -07:00
cd9e6a1d4f wal: lock WAL file while repairing 2016-05-06 16:57:55 -07:00
774030e1b2 wal: repair torn writes
Fixes #5230
2016-05-06 16:54:08 -07:00
c9c2cdfeaf Merge pull request #5293 from heyitsanthony/fix-compact-cancel-crash
etcdserver: fix nil dereference in physical Compact on proposal timeout
2016-05-06 16:25:03 -07:00
824ffded12 etcdserver: fix nil dereference in physical Compact on proposal timeout
Fixes #5292
2016-05-06 15:38:18 -07:00
34fbec118a Merge pull request #5289 from xiang90/has_leader_metrics
*: add has leader metrics
2016-05-06 14:45:49 -07:00
4481016953 Merge pull request #5290 from coreos/vv
*: bump to v3.0.0-beta.0+git
2016-05-06 14:10:52 -07:00
ebaa54bf6e *: bump to v3.0.0-beta.0+git 2016-05-06 14:04:01 -07:00
824478be5f *: add has leader metrics 2016-05-06 13:59:19 -07:00
784 changed files with 33669 additions and 8637 deletions

1
.gitignore vendored
View File

@ -10,3 +10,4 @@
/hack/insta-discovery/.env
*.test
tools/functional-tester/docker/bin
hack/tls-setup/certs

View File

@ -1,4 +1,4 @@
// Copyright 2016 CoreOS, Inc.
// Copyright 2016 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.

View File

@ -4,7 +4,6 @@ go_import_path: github.com/coreos/etcd
sudo: false
go:
- 1.5
- 1.6
- tip
@ -14,10 +13,22 @@ env:
matrix:
- TARGET=amd64
- TARGET=arm64
- TARGET=arm
- TARGET=ppc64le
matrix:
fast_finish: true
allow_failures:
- go: tip
exclude:
- go: 1.6
env: TARGET=arm64
- go: tip
env: TARGET=arm
- go: tip
env: TARGET=arm64
- go: tip
env: TARGET=ppc64le
addons:
apt:
@ -37,8 +48,8 @@ install:
script:
- >
if [ "${TARGET}" == "amd64" ]; then
GOARCH="${TARGET}" ./test;
elif [ "${TARGET}" == "arm64" ]; then
GOARCH="${TARGET}" ./build;
fi
if [ "${TARGET}" == "amd64" ]; then
GOARCH="${TARGET}" ./test;
else
GOARCH="${TARGET}" ./build;
fi

View File

@ -12,7 +12,7 @@ etcd is Apache 2.0 licensed and accepts contributions via GitHub pull requests.
- Fork the repository on GitHub
- Read the README.md for build instructions
## Reporting Bugs and Creating Issues
## 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
@ -39,7 +39,7 @@ The coding style suggested by the Golang community is used in etcd. See the [sty
Please follow this style to make etcd easy to review, maintain and develop.
### Format of the Commit Message
### Format of the commit message
We follow a rough convention for commit messages that is designed to answer two
questions: what changed and why. The subject line should feature the what and

View File

@ -1,2 +1,6 @@
FROM golang:onbuild
EXPOSE 4001 7001 2379 2380
FROM golang
ADD . /go/src/github.com/coreos/etcd
ADD cmd/vendor /go/src/github.com/coreos/etcd/vendor
RUN go install github.com/coreos/etcd
EXPOSE 2379 2380
ENTRYPOINT ["etcd"]

11
Dockerfile-release Normal file
View File

@ -0,0 +1,11 @@
FROM alpine:latest
ADD etcd /usr/local/bin/
ADD etcdctl /usr/local/bin/
RUN mkdir -p /var/etcd/
RUN mkdir -p /var/lib/etcd/
EXPOSE 2379 2380
# Define default command.
CMD ["/usr/local/bin/etcd"]

View File

@ -1,146 +0,0 @@
# etcd3 API
TODO: finish API doc
## Response Header
All Responses from etcd API have a [response header][response_header] attached. The response header includes the metadata of the response.
```proto
message ResponseHeader {
uint64 cluster_id = 1;
uint64 member_id = 2;
int64 revision = 3;
uint64 raft_term = 4;
}
```
* 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
An application may read the Cluster_ID (Member_ID) field to ensure it is communicating with the intended cluster (member).
Applications can use the `Revision` to know the latest revision of the key-value store. This is especially useful when applications specify a historical revision to make time `travel query` and wishes to know the latest revision at the time of the request.
Applications can use `Raft_Term` to detect when the cluster completes a new leader election.
## 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].
### 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:
```protobuf
message KeyValue {
bytes key = 1;
int64 create_revision = 2;
int64 mod_revision = 3;
int64 version = 4;
bytes value = 5;
int64 lease = 6;
}
```
* Key - key in bytes. An empty key is not allowed.
* Value - value in bytes.
* Version - version is the version of the key. A deletion resets the version to zero and any modification of the key increases its version.
* Create_Revision - revision of the last creation on the key.
* 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.
## Data Model
etcd is designed to reliably store infrequently updated data and provide reliable watch queries. etcd exposes previous versions of key-value pairs to support inexpensive snapshots and watch history events (“time travel queries”). A persistent, multi-version, concurrency-control data model is a good fit for these use cases.
etcd stores data in a multiversion [persistent][persistent-ds] key-value store. The persistent key-value store preserves the previous version of a key-value pair when its value is superseded with new data. The key-value store is effectively immutable; its operations do not update the structure in-place, but instead always generates a new updated structure. All past versions of keys are still accessible and watchable after modification. To prevent the data store from growing indefinitely over time from maintaining old versions, the store may be compacted to shed the oldest versions of superseded data.
### Logical View
The stores logical view is a flat binary key space. The key space has a lexically sorted index on byte string keys so range queries are inexpensive.
The key space maintains multiple revisions. Each atomic mutative operation (e.g., a transaction operation may contain multiple operations) creates a new revision on the key space. All data held by previous revisions remains unchanged. Old versions of key can still be accessed through previous revisions. Likewise, revisions are indexed as well; ranging over revisions with watchers is efficient. If the store is compacted to recover space, revisions before the compact revision will be removed.
A keys lifetime spans a generation. Each key may have one or multiple generations. Creating a key increments the generation of that key, starting at 1 if the key never existed. Deleting a key generates a key tombstone, concluding the keys current generation. Each modification of a key creates a new version of the key. Once a compaction happens, any generation ended before the given revision will be removed and values set before the compaction revision except the latest one will be removed.
### 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.
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.
etcd also keeps a secondary in-memory [btree][btree] index to speed up range queries over keys. The keys in the btree index are the keys of the store exposed to user. The value is a pointer to the modification of the persistent b+tree. Compaction removes dead pointers.
## 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.
### APIs to consider
* Read APIs
* range
* watch
* Write APIs
* put
* delete
* Combination (read-modify-write) APIs
* txn
### etcd Specific Definitions
#### operation completed
An etcd operation is considered complete when it is committed through consensus, and therefore “executed” -- permanently stored -- by the etcd storage engine. The client knows an operation is completed when it receives a response from the etcd server. Note that the client may be uncertain about the status of an operation if it times out, or there is a network disruption between the client and the etcd member. etcd may also abort operations when there is a leader election. etcd does not send `abort` responses to clients outstanding requests in this event.
#### 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".
### Guarantees Provided
#### Atomicity
All API requests are atomic; an operation either completes entirely or not at all. For watch requests, all events generated by one operation will be in one watch response. Watch never observes partial events for a single operation.
#### Consistency
All API calls ensure [sequential consistency][seq_consistency], the strongest consistency guarantee available from distributed systems. No matter which etcd member server a client makes requests to, a client reads the same events in the same order. If two members complete the same number of operations, the state of the two members is consistent.
For watch operations, etcd guarantees to return the same value for the same key across all members for the same revision. For range operations, etcd has a similar guarantee for [linearized][Linearizability] access; serialized access may be behind the quorum state, so that the later revision is not yet available.
As with all distributed systems, it is impossible for etcd to ensure [strict consistency][strict_consistency]. etcd does not guarantee that it will return to a read the “most recent” value (as measured by a wall clock when a request is completed) available on any cluster member.
#### Isolation
etcd ensures [serializable isolation][serializable_isolation], which is the highest isolation level available in distributed systems. Read operations will never observe any intermediate data.
#### Durability
Any completed operations are durable. All accessible data is also durable data. A read will never return data that has not been made durable.
#### Linearizability
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.
For example, consider a client completing a write at time point 1 (*t1*). A client issuing a read at *t2* (for *t2* > *t1*) should receive a value at least as recent as the previous write, completed at *t1*. However, the read might actually complete only by *t3*, and the returned value, current at *t2* when the read began, might be "stale" by *t3*.
etcd does not ensure linearizability for watch operations. Users are expected to verify the revision of watch responses to ensure correct ordering.
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
[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

View File

@ -1,4 +1,4 @@
# Branch Management
# Branch management
## Guide
@ -13,7 +13,7 @@ The etcd team has adopted a *rolling release model* and supports one stable vers
The `master` branch is our development branch. All new features land here first.
If you want to try new features, pull `master` and play with it. Note that `master` may not be stable because new features may introduce bugs.
To try new and experimental features, pull `master` and play with it. Note that `master` may not be stable because new features may introduce bugs.
Before the release of the next stable version, feature PRs will be frozen. We will focus on the testing, bug-fix and documentation for one to two weeks.

454
Documentation/demo.md Normal file
View File

@ -0,0 +1,454 @@
# Demo
This series of examples shows the basic procedures for working with an etcd cluster.
## Set up a cluster
<img src="https://storage.googleapis.com/etcd/demo/01_etcd_clustering_2016051001.gif" alt="01_etcd_clustering_2016050601"/>
On each etcd node, specify the cluster members:
```
TOKEN=token-01
CLUSTER_STATE=new
NAME_1=machine-1
NAME_2=machine-2
NAME_3=machine-3
HOST_1=10.240.0.17
HOST_2=10.240.0.18
HOST_3=10.240.0.19
CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_3}=http://${HOST_3}:2380
```
Run this on each machine:
```
# For machine 1
THIS_NAME=${NAME_1}
THIS_IP=${HOST_1}
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}
# For machine 2
THIS_NAME=${NAME_2}
THIS_IP=${HOST_2}
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}
# For machine 3
THIS_NAME=${NAME_3}
THIS_IP=${HOST_3}
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}
```
Or use our public discovery service:
```
curl https://discovery.etcd.io/new?size=3
https://discovery.etcd.io/a81b5818e67a6ea83e9d4daea5ecbc92
# grab this token
TOKEN=token-01
CLUSTER_STATE=new
NAME_1=machine-1
NAME_2=machine-2
NAME_3=machine-3
HOST_1=10.240.0.17
HOST_2=10.240.0.18
HOST_3=10.240.0.19
DISCOVERY=https://discovery.etcd.io/a81b5818e67a6ea83e9d4daea5ecbc92
THIS_NAME=${NAME_1}
THIS_IP=${HOST_1}
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 \
--discovery ${DISCOVERY} \
--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}
THIS_NAME=${NAME_2}
THIS_IP=${HOST_2}
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 \
--discovery ${DISCOVERY} \
--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}
THIS_NAME=${NAME_3}
THIS_IP=${HOST_3}
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 \
--discovery ${DISCOVERY} \
--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}
```
Now etcd is ready! To connect to etcd with etcdctl:
```
export ETCDCTL_API=3
HOST_1=10.240.0.17
HOST_2=10.240.0.18
HOST_3=10.240.0.19
ENDPOINTS=$HOST_1:2379,$HOST_2:2379,$HOST_3:2379
etcdctl --endpoints=$ENDPOINTS member list
```
## Access etcd
<img src="https://storage.googleapis.com/etcd/demo/02_etcdctl_access_etcd_2016051001.gif" alt="02_etcdctl_access_etcd_2016051001"/>
`put` command to write:
```
etcdctl --endpoints=$ENDPOINTS put foo "Hello World!"
```
`get` to read from etcd:
```
etcdctl --endpoints=$ENDPOINTS get foo
etcdctl --endpoints=$ENDPOINTS --write-out="json" get foo
```
## Get by prefix
<img src="https://storage.googleapis.com/etcd/demo/03_etcdctl_get_by_prefix_2016050501.gif" alt="03_etcdctl_get_by_prefix_2016050501"/>
```
etcdctl --endpoints=$ENDPOINTS put web1 value1
etcdctl --endpoints=$ENDPOINTS put web2 value2
etcdctl --endpoints=$ENDPOINTS put web3 value3
etcdctl --endpoints=$ENDPOINTS get web --prefix
```
## Delete
<img src="https://storage.googleapis.com/etcd/demo/04_etcdctl_delete_2016050601.gif" alt="04_etcdctl_delete_2016050601"/>
```
etcdctl --endpoints=$ENDPOINTS put key myvalue
etcdctl --endpoints=$ENDPOINTS del key
etcdctl --endpoints=$ENDPOINTS put k1 value1
etcdctl --endpoints=$ENDPOINTS put k2 value2
etcdctl --endpoints=$ENDPOINTS del k --prefix
```
## Transactional write
`txn` to wrap multiple requests into one transaction:
<img src="https://storage.googleapis.com/etcd/demo/05_etcdctl_transaction_2016050501.gif" alt="05_etcdctl_transaction_2016050501"/>
```
etcdctl --endpoints=$ENDPOINTS put user1 bad
etcdctl --endpoints=$ENDPOINTS txn --interactive
compares:
value("user1") = "bad"
success requests (get, put, delete):
del user1
failure requests (get, put, delete):
put user1 good
```
## Watch
`watch` to get notified of future changes:
<img src="https://storage.googleapis.com/etcd/demo/06_etcdctl_watch_2016050501.gif" alt="06_etcdctl_watch_2016050501"/>
```
etcdctl --endpoints=$ENDPOINTS watch stock1
etcdctl --endpoints=$ENDPOINTS put stock1 1000
etcdctl --endpoints=$ENDPOINTS watch stock --prefix
etcdctl --endpoints=$ENDPOINTS put stock1 10
etcdctl --endpoints=$ENDPOINTS put stock2 20
```
## Lease
`lease` to write with TTL:
<img src="https://storage.googleapis.com/etcd/demo/07_etcdctl_lease_2016050501.gif" alt="07_etcdctl_lease_2016050501"/>
```
etcdctl --endpoints=$ENDPOINTS lease grant 300
# lease 2be7547fbc6a5afa granted with TTL(300s)
etcdctl --endpoints=$ENDPOINTS put sample value --lease=2be7547fbc6a5afa
etcdctl --endpoints=$ENDPOINTS get sample
etcdctl --endpoints=$ENDPOINTS lease keep-alive 2be7547fbc6a5afa
etcdctl --endpoints=$ENDPOINTS lease revoke 2be7547fbc6a5afa
# or after 300 seconds
etcdctl --endpoints=$ENDPOINTS get sample
```
## Distributed locks
`lock` for distributed lock:
<img src="https://storage.googleapis.com/etcd/demo/08_etcdctl_lock_2016050501.gif" alt="08_etcdctl_lock_2016050501"/>
```
etcdctl --endpoints=$ENDPOINTS lock mutex1
# another client with the same name blocks
etcdctl --endpoints=$ENDPOINTS lock mutex1
```
## Elections
`elect` for leader election:
<img src="https://storage.googleapis.com/etcd/demo/09_etcdctl_elect_2016050501.gif" alt="09_etcdctl_elect_2016050501"/>
```
etcdctl --endpoints=$ENDPOINTS elect one p1
# another client with the same name blocks
etcdctl --endpoints=$ENDPOINTS elect one p2
```
## Cluster status
Specify the initial cluster configuration for each machine:
<img src="https://storage.googleapis.com/etcd/demo/10_etcdctl_endpoint_2016050501.gif" alt="10_etcdctl_endpoint_2016050501"/>
```
etcdctl --write-out=table --endpoints=$ENDPOINTS endpoint status
+------------------+------------------+---------+---------+-----------+-----------+------------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | RAFT TERM | RAFT INDEX |
+------------------+------------------+---------+---------+-----------+-----------+------------+
| 10.240.0.17:2379 | 4917a7ab173fabe7 | 3.0.0 | 45 kB | true | 4 | 16726 |
| 10.240.0.18:2379 | 59796ba9cd1bcd72 | 3.0.0 | 45 kB | false | 4 | 16726 |
| 10.240.0.19:2379 | 94df724b66343e6c | 3.0.0 | 45 kB | false | 4 | 16726 |
+------------------+------------------+---------+---------+-----------+-----------+------------+
```
```
etcdctl --endpoints=$ENDPOINTS endpoint health
10.240.0.17:2379 is healthy: successfully committed proposal: took = 3.345431ms
10.240.0.19:2379 is healthy: successfully committed proposal: took = 3.767967ms
10.240.0.18:2379 is healthy: successfully committed proposal: took = 4.025451ms
```
## Snapshot
`snapshot` to save point-in-time snapshot of etcd database:
<img src="https://storage.googleapis.com/etcd/demo/11_etcdctl_snapshot_2016051001.gif" alt="11_etcdctl_snapshot_2016051001"/>
```
etcdctl --endpoints=$ENDPOINTS snapshot save my.db
Snapshot saved at my.db
```
```
etcdctl --write-out=table --endpoints=$ENDPOINTS snapshot status my.db
+---------+----------+------------+------------+
| HASH | REVISION | TOTAL KEYS | TOTAL SIZE |
+---------+----------+------------+------------+
| c55e8b8 | 9 | 13 | 25 kB |
+---------+----------+------------+------------+
```
## Migrate
`migrate` to transform etcd v2 to v3 data:
<img src="https://storage.googleapis.com/etcd/demo/12_etcdctl_migrate_2016061602.gif" alt="12_etcdctl_migrate_2016061602"/>
```
# write key in etcd version 2 store
export ETCDCTL_API=2
etcdctl --endpoints=http://$ENDPOINT set foo bar
# read key in etcd v2
etcdctl --endpoints=$ENDPOINTS --output="json" get foo
# stop etcd node to migrate, one by one
# migrate v2 data
export ETCDCTL_API=3
etcdctl --endpoints=$ENDPOINT migrate --data-dir="default.etcd" --wal-dir="default.etcd/member/wal"
# restart etcd node after migrate, one by one
# confirm that the key got migrated
etcdctl --endpoints=$ENDPOINTS get /foo
```
## Member
`member` to add,remove,update membership:
<img src="https://storage.googleapis.com/etcd/demo/13_etcdctl_member_2016062301.gif" alt="13_etcdctl_member_2016062301"/>
```
# For each machine
TOKEN=my-etcd-token-1
CLUSTER_STATE=new
NAME_1=etcd-node-1
NAME_2=etcd-node-2
NAME_3=etcd-node-3
HOST_1=10.240.0.13
HOST_2=10.240.0.14
HOST_3=10.240.0.15
CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_3}=http://${HOST_3}:2380
# For node 1
THIS_NAME=${NAME_1}
THIS_IP=${HOST_1}
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}
# For node 2
THIS_NAME=${NAME_2}
THIS_IP=${HOST_2}
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}
# For node 3
THIS_NAME=${NAME_3}
THIS_IP=${HOST_3}
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}
```
Then replace a member with `member remove` and `member add` commands:
```
# get member ID
export ETCDCTL_API=3
HOST_1=10.240.0.13
HOST_2=10.240.0.14
HOST_3=10.240.0.15
etcdctl --endpoints=${HOST_1}:2379,${HOST_2}:2379,${HOST_3}:2379 member list
# remove the member
MEMBER_ID=278c654c9a6dfd3b
etcdctl --endpoints=${HOST_1}:2379,${HOST_2}:2379,${HOST_3}:2379 \
member remove ${MEMBER_ID}
# add a new member (node 4)
export ETCDCTL_API=3
NAME_1=etcd-node-1
NAME_2=etcd-node-2
NAME_4=etcd-node-4
HOST_1=10.240.0.13
HOST_2=10.240.0.14
HOST_4=10.240.0.16 # new member
etcdctl --endpoints=${HOST_1}:2379,${HOST_2}:2379 \
member add ${NAME_4} \
--peer-urls=http://${HOST_4}:2380
```
Next, start the new member with `--initial-cluster-state existing` flag:
```
# [WARNING] If the new member starts from the same disk space,
# make sure to remove the data directory of the old member
#
# restart with 'existing' flag
TOKEN=my-etcd-token-1
CLUSTER_STATE=existing
NAME_1=etcd-node-1
NAME_2=etcd-node-2
NAME_4=etcd-node-4
HOST_1=10.240.0.13
HOST_2=10.240.0.14
HOST_4=10.240.0.16 # new member
CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_4}=http://${HOST_4}:2380
THIS_NAME=${NAME_4}
THIS_IP=${HOST_4}
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}
```
## Auth
`auth`,`user`,`role` for authentication:
<img src="https://storage.googleapis.com/etcd/demo/14_etcdctl_auth_2016062301.gif" alt="14_etcdctl_auth_2016062301"/>
```
export ETCDCTL_API=3
ENDPOINTS=localhost:2379
etcdctl --endpoints=${ENDPOINTS} role add root
etcdctl --endpoints=${ENDPOINTS} role grant-permission root readwrite foo
etcdctl --endpoints=${ENDPOINTS} role get root
etcdctl --endpoints=${ENDPOINTS} user add root
etcdctl --endpoints=${ENDPOINTS} user grant-role root root
etcdctl --endpoints=${ENDPOINTS} user get root
etcdctl --endpoints=${ENDPOINTS} auth enable
# now all client requests go through auth
etcdctl --endpoints=${ENDPOINTS} --user=root:123 put foo bar
etcdctl --endpoints=${ENDPOINTS} get foo
etcdctl --endpoints=${ENDPOINTS} --user=root:123 get foo
etcdctl --endpoints=${ENDPOINTS} --user=root:123 get foo1
```

View File

@ -0,0 +1,38 @@
## Why grpc-gateway
etcd v3 uses [gRPC][grpc] for its messaging protocol. The etcd project includes a gRPC-based [Go client][go-client] and a command line utility, [etcdctl][etcdctl], for communicating with an etcd cluster through gRPC. For languages with no gRPC support, etcd provides a JSON [grpc-gateway][grpc-gateway]. This gateway serves a RESTful proxy that translates HTTP/JSON requests into gRPC messages.
## Using grpc-gateway
The gateway accepts a [JSON mapping][json-mapping] for etcd's [protocol buffer][api-ref] message definitions. Note that `key` and `value` fields are defined as byte arrays and therefore must be base64 encoded in JSON.
```bash
<<COMMENT
https://www.base64encode.org/
foo is 'Zm9v' in Base64
bar is 'YmFy'
COMMENT
curl -L http://localhost:2379/v3alpha/kv/put \
-X POST -d '{"key": "Zm9v", "value": "YmFy"}'
curl -L http://localhost:2379/v3alpha/kv/range \
-X POST -d '{"key": "Zm9v"}'
```
## Swagger
Generated [Swagger][swagger] API definitions can be found at [rpc.swagger.json][swagger-doc].
[api-ref]: ./api_reference_v3.md
[go-client]: https://github.com/coreos/etcd/tree/master/clientv3
[etcdctl]: https://github.com/coreos/etcd/tree/master/etcdctl
[grpc]: http://www.grpc.io/
[grpc-gateway]: https://github.com/grpc-ecosystem/grpc-gateway
[json-mapping]: https://developers.google.com/protocol-buffers/docs/proto3#json
[swagger]: http://swagger.io/
[swagger-doc]: apispec/swagger/rpc.swagger.json

View File

@ -1,6 +1,9 @@
### etcd API Reference
This is a generated documentation. Please read the proto files for more.
##### service `Auth` (etcdserver/etcdserverpb/rpc.proto)
| Method | Request Type | Response Type | Description |
@ -9,16 +12,18 @@
| AuthDisable | AuthDisableRequest | AuthDisableResponse | AuthDisable disables authentication. |
| Authenticate | AuthenticateRequest | AuthenticateResponse | Authenticate processes an authenticate request. |
| UserAdd | AuthUserAddRequest | AuthUserAddResponse | UserAdd adds a new user. |
| UserGet | AuthUserGetRequest | AuthUserGetResponse | UserGet gets detailed user information or lists all users. |
| UserGet | AuthUserGetRequest | AuthUserGetResponse | UserGet gets detailed user information. |
| UserList | AuthUserListRequest | AuthUserListResponse | UserList gets a list of all users. |
| UserDelete | AuthUserDeleteRequest | AuthUserDeleteResponse | UserDelete deletes a specified user. |
| UserChangePassword | AuthUserChangePasswordRequest | AuthUserChangePasswordResponse | UserChangePassword changes the password of a specified user. |
| UserGrant | AuthUserGrantRequest | AuthUserGrantResponse | UserGrant grants a role to a specified user. |
| UserRevoke | AuthUserRevokeRequest | AuthUserRevokeResponse | UserRevoke revokes a role of specified user. |
| UserGrantRole | AuthUserGrantRoleRequest | AuthUserGrantRoleResponse | UserGrant grants a role to a specified user. |
| UserRevokeRole | AuthUserRevokeRoleRequest | AuthUserRevokeRoleResponse | UserRevokeRole revokes a role of specified user. |
| RoleAdd | AuthRoleAddRequest | AuthRoleAddResponse | RoleAdd adds a new role. |
| RoleGet | AuthRoleGetRequest | AuthRoleGetResponse | RoleGet gets detailed role information or lists all roles. |
| RoleGet | AuthRoleGetRequest | AuthRoleGetResponse | RoleGet gets detailed role information. |
| RoleList | AuthRoleListRequest | AuthRoleListResponse | RoleList gets lists of all roles. |
| RoleDelete | AuthRoleDeleteRequest | AuthRoleDeleteResponse | RoleDelete deletes a specified role. |
| RoleGrant | AuthRoleGrantRequest | AuthRoleGrantResponse | RoleGrant grants a permission of a specified key or range to a specified role. |
| RoleRevoke | AuthRoleRevokeRequest | AuthRoleRevokeResponse | RoleRevoke revokes a key or range permission of a specified role. |
| RoleGrantPermission | AuthRoleGrantPermissionRequest | AuthRoleGrantPermissionResponse | RoleGrantPermission grants a permission of a specified key or range to a specified role. |
| RoleRevokePermission | AuthRoleRevokePermissionRequest | AuthRoleRevokePermissionResponse | RoleRevokePermission revokes a key or range permission of a specified role. |
@ -35,11 +40,13 @@
##### 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. |
| Put | PutRequest | PutResponse | Put puts the given key into the key-value store. A put request increments the revision of the key-value store and generates one event in the event history. |
| DeleteRange | DeleteRangeRequest | DeleteRangeResponse | Delete deletes the given range from the key-value store. A delete request increments the revision of the key-value store and generates a delete event in the event history for every deleted key. |
| DeleteRange | DeleteRangeRequest | DeleteRangeResponse | DeleteRange deletes the given range from the key-value store. A delete request increments the revision of the key-value store and generates a delete event in the event history for every deleted key. |
| Txn | TxnRequest | TxnResponse | Txn processes multiple requests in a single transaction. A txn request increments the revision of the key-value store and generates events with the same revision for every completed request. It is not allowed to modify the same key several times within one txn. |
| Compact | CompactionRequest | CompactionResponse | Compact compacts the event history in the etcd key-value store. The key-value store should be periodically compacted or the event history will continue to grow indefinitely. |
@ -86,6 +93,8 @@
##### 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 |
@ -149,7 +158,9 @@ Empty field.
##### message `AuthRoleDeleteRequest` (etcdserver/etcdserverpb/rpc.proto)
Empty field.
| Field | Description | Type |
| ----- | ----------- | ---- |
| role | | string |
@ -163,7 +174,9 @@ Empty field.
##### message `AuthRoleGetRequest` (etcdserver/etcdserverpb/rpc.proto)
Empty field.
| Field | Description | Type |
| ----- | ----------- | ---- |
| role | | string |
@ -172,10 +185,11 @@ Empty field.
| Field | Description | Type |
| ----- | ----------- | ---- |
| header | | ResponseHeader |
| perm | | (slice of) authpb.Permission |
##### message `AuthRoleGrantRequest` (etcdserver/etcdserverpb/rpc.proto)
##### message `AuthRoleGrantPermissionRequest` (etcdserver/etcdserverpb/rpc.proto)
| Field | Description | Type |
| ----- | ----------- | ---- |
@ -184,7 +198,7 @@ Empty field.
##### message `AuthRoleGrantResponse` (etcdserver/etcdserverpb/rpc.proto)
##### message `AuthRoleGrantPermissionResponse` (etcdserver/etcdserverpb/rpc.proto)
| Field | Description | Type |
| ----- | ----------- | ---- |
@ -192,13 +206,32 @@ Empty field.
##### message `AuthRoleRevokeRequest` (etcdserver/etcdserverpb/rpc.proto)
##### message `AuthRoleListRequest` (etcdserver/etcdserverpb/rpc.proto)
Empty field.
##### message `AuthRoleRevokeResponse` (etcdserver/etcdserverpb/rpc.proto)
##### message `AuthRoleListResponse` (etcdserver/etcdserverpb/rpc.proto)
| Field | Description | Type |
| ----- | ----------- | ---- |
| header | | ResponseHeader |
| roles | | (slice of) string |
##### message `AuthRoleRevokePermissionRequest` (etcdserver/etcdserverpb/rpc.proto)
| Field | Description | Type |
| ----- | ----------- | ---- |
| role | | string |
| key | | string |
| range_end | | string |
##### message `AuthRoleRevokePermissionResponse` (etcdserver/etcdserverpb/rpc.proto)
| Field | Description | Type |
| ----- | ----------- | ---- |
@ -258,7 +291,9 @@ Empty field.
##### message `AuthUserGetRequest` (etcdserver/etcdserverpb/rpc.proto)
Empty field.
| Field | Description | Type |
| ----- | ----------- | ---- |
| name | | string |
@ -267,10 +302,11 @@ Empty field.
| Field | Description | Type |
| ----- | ----------- | ---- |
| header | | ResponseHeader |
| roles | | (slice of) string |
##### message `AuthUserGrantRequest` (etcdserver/etcdserverpb/rpc.proto)
##### message `AuthUserGrantRoleRequest` (etcdserver/etcdserverpb/rpc.proto)
| Field | Description | Type |
| ----- | ----------- | ---- |
@ -279,7 +315,7 @@ Empty field.
##### message `AuthUserGrantResponse` (etcdserver/etcdserverpb/rpc.proto)
##### message `AuthUserGrantRoleResponse` (etcdserver/etcdserverpb/rpc.proto)
| Field | Description | Type |
| ----- | ----------- | ---- |
@ -287,13 +323,31 @@ Empty field.
##### message `AuthUserRevokeRequest` (etcdserver/etcdserverpb/rpc.proto)
##### message `AuthUserListRequest` (etcdserver/etcdserverpb/rpc.proto)
Empty field.
##### message `AuthUserRevokeResponse` (etcdserver/etcdserverpb/rpc.proto)
##### message `AuthUserListResponse` (etcdserver/etcdserverpb/rpc.proto)
| Field | Description | Type |
| ----- | ----------- | ---- |
| header | | ResponseHeader |
| users | | (slice of) string |
##### message `AuthUserRevokeRoleRequest` (etcdserver/etcdserverpb/rpc.proto)
| Field | Description | Type |
| ----- | ----------- | ---- |
| name | | string |
| role | | string |
##### message `AuthUserRevokeRoleResponse` (etcdserver/etcdserverpb/rpc.proto)
| Field | Description | Type |
| ----- | ----------- | ---- |
@ -381,7 +435,7 @@ Empty field.
| Field | Description | Type |
| ----- | ----------- | ---- |
| header | | ResponseHeader |
| deleted | Deleted is the number of keys deleted by the delete range request. | int64 |
| deleted | deleted is the number of keys deleted by the delete range request. | int64 |
@ -552,13 +606,15 @@ Empty field.
| Field | Description | Type |
| ----- | ----------- | ---- |
| 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. | bytes |
| 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 |
| 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, ErrCompaction is returned as a response. | 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 |
| serializable | serializable sets the range request to use serializable member-local reads. Range requests are linearizable by default; linearizable requests have higher latency and lower throughput than serializable requests but reflect the current consensus of the cluster. For better performance, in exchange for possible stale reads, a serializable range request is served locally without needing to reach consensus with other nodes in the cluster. | bool |
| keys_only | keys_only when set returns only the keys and not the values. | bool |
| count_only | count_only when set returns only the count of the keys in the range. | bool |
@ -567,12 +623,13 @@ Empty field.
| Field | Description | Type |
| ----- | ----------- | ---- |
| header | | ResponseHeader |
| kvs | kvs is the list of key-value pairs matched by the range request. | (slice of) mvccpb.KeyValue |
| kvs | kvs is the list of key-value pairs matched by the range request. kvs is empty when count is requested. | (slice of) mvccpb.KeyValue |
| more | more indicates if there are more keys to return in the requested range. | bool |
| count | count is set to the number of keys within the range when requested. | int64 |
##### message `RequestUnion` (etcdserver/etcdserverpb/rpc.proto)
##### message `RequestOp` (etcdserver/etcdserverpb/rpc.proto)
| Field | Description | Type |
| ----- | ----------- | ---- |
@ -594,7 +651,7 @@ Empty field.
##### message `ResponseUnion` (etcdserver/etcdserverpb/rpc.proto)
##### message `ResponseOp` (etcdserver/etcdserverpb/rpc.proto)
| Field | Description | Type |
| ----- | ----------- | ---- |
@ -646,9 +703,9 @@ From google paxosdb paper: Our implementation hinges around a powerful primitive
| Field | Description | Type |
| ----- | ----------- | ---- |
| compare | Compare is a list of predicates representing a conjunction of terms. If the comparisons succeed, then the success requests will be processed in order, and the response will contain their respective responses in order. If the comparisons fail, then the failure requests will be processed in order, and the response will contain their respective responses in order. | (slice of) Compare |
| success | success is a list of requests which will be applied when compare evaluates to true. | (slice of) RequestUnion |
| failure | failure is a list of requests which will be applied when compare evaluates to false. | (slice of) RequestUnion |
| compare | compare is a list of predicates representing a conjunction of terms. If the comparisons succeed, then the success requests will be processed in order, and the response will contain their respective responses in order. If the comparisons fail, then the failure requests will be processed in order, and the response will contain their respective responses in order. | (slice of) Compare |
| success | success is a list of requests which will be applied when compare evaluates to true. | (slice of) RequestOp |
| failure | failure is a list of requests which will be applied when compare evaluates to false. | (slice of) RequestOp |
@ -658,7 +715,7 @@ From google paxosdb paper: Our implementation hinges around a powerful primitive
| ----- | ----------- | ---- |
| header | | ResponseHeader |
| succeeded | succeeded is set to true if the compare evaluated to true or false otherwise. | bool |
| responses | responses is a list of responses corresponding to the results from applying success if succeeded is true or failure if succeeded is false. | (slice of) ResponseUnion |
| responses | responses is a list of responses corresponding to the results from applying success if succeeded is true or failure if succeeded is false. | (slice of) ResponseOp |
@ -741,8 +798,9 @@ Permission is a single entity
| Field | Description | Type |
| ----- | ----------- | ---- |
| key | | bytes |
| permType | | Type |
| key | | bytes |
| range_end | | bytes |

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
# 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.
## 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

View File

@ -1,8 +1,8 @@
# Setup a Local Cluster
# Setup a local cluster
For testing and development deployments, the quickest and easiest way is to set up a local cluster. For a production deployment, refer to the [clustering][clustering] section.
## Local Standalone Cluster
## Local standalone cluster
Deploying an etcd cluster as a standalone cluster is straightforward. Start it with just one command:
@ -26,7 +26,7 @@ $ ./etcdctl get foo
bar
```
## Local Multi-member Cluster
## Local multi-member cluster
A Procfile is provided to easily set up a local multi-member cluster. Start a multi-member cluster with a few commands:
@ -45,7 +45,7 @@ To interact with the started cluster by using etcdctl:
# use API version 3
$ export ETCDCTL_API=3
$ etcdctl --endpoints=localhost:12379 member list
$ etcdctl --write-out=table --endpoints=localhost:12379 member list
+------------------+---------+--------+------------------------+------------------------+
| ID | STATUS | NAME | PEER ADDRS | CLIENT ADDRS |
+------------------+---------+--------+------------------------+------------------------+
@ -86,5 +86,5 @@ hello
To learn more about interacting with etcd, read [interacting with etcd section][interacting].
[interacting]: ./interacting_v3.md
[clustering]: ./clustering.md
[clustering]: ../op-guide/clustering.md

View File

@ -1,4 +1,4 @@
# Discovery Service Protocol
# Discovery service protocol
Discovery service protocol helps new etcd member to discover all other members in cluster bootstrap phase using a shared discovery URL.
@ -8,7 +8,7 @@ The protocol uses a new discovery token to bootstrap one _unique_ etcd cluster.
The rest of this article will walk through the discovery process with examples that correspond to a self-hosted discovery cluster. The public discovery service, discovery.etcd.io, functions the same way, but with a layer of polish to abstract away ugly URLs, generate UUIDs automatically, and provide some protections against excessive requests. At its core, the public discovery service still uses an etcd cluster as the data store as described in this document.
## The Protocol Workflow
## Protocol workflow
The idea of discovery protocol is to use an internal etcd cluster to coordinate bootstrap of a new cluster. First, all new members interact with discovery service and help to generate the expected member list. Then each new member bootstraps its server using this list, which performs the same functionality as -initial-cluster flag.
@ -16,7 +16,7 @@ In the following example workflow, we will list each step of protocol in curl fo
By convention the etcd discovery protocol uses the key prefix `_etcd/registry`. If `http://example.com` hosts an etcd cluster for discovery service, a full URL to discovery keyspace will be `http://example.com/v2/keys/_etcd/registry`. We will use this as the URL prefix in the example.
### Creating a New Discovery Token
### Creating a new discovery token
Generate a unique token that will identify the new cluster. This will be used as a unique prefix in discovery keyspace in the following steps. An easy way to do this is to use `uuidgen`:
@ -24,9 +24,9 @@ Generate a unique token that will identify the new cluster. This will be used as
UUID=$(uuidgen)
```
### Specifying the Expected Cluster Size
### Specifying the expected cluster size
You need to specify the expected cluster size for this discovery token. The size is used by the discovery service to know when it has found all members that will initially form the cluster.
The discovery token expects a cluster size that must be specified. The size is used by the discovery service to know when it has found all members that will initially form the cluster.
```
curl -X PUT http://example.com/v2/keys/_etcd/registry/${UUID}/_config/size -d value=${cluster_size}
@ -34,9 +34,9 @@ curl -X PUT http://example.com/v2/keys/_etcd/registry/${UUID}/_config/size -d va
Usually the cluster size is 3, 5 or 7. Check [optimal cluster size][cluster-size] for more details.
### Bringing up etcd Processes
### Bringing up etcd processes
Now that you have your discovery URL, you can use it as `-discovery` flag and bring up etcd processes. Every etcd process will follow this next few steps internally if given a `-discovery` flag.
Given the discovery URL, use it as `-discovery` flag and bring up etcd processes. Every etcd process will follow this next few steps internally if given a `-discovery` flag.
### Registering itself
@ -46,7 +46,7 @@ The first thing for etcd process is to register itself into the discovery URL as
curl -X PUT http://example.com/v2/keys/_etcd/registry/${UUID}/${member_id}?prevExist=false -d value="${member_name}=${member_peer_url_1}&${member_name}=${member_peer_url_2}"
```
### Checking the Status
### Checking the status
It checks the expected cluster size and registration status in discovery URL, and decides what the next action is.
@ -61,8 +61,7 @@ If the number of registered members is bigger than the expected size N, it treat
In etcd implementation, the member may check the cluster status even before registering itself. So it could fail quickly if the cluster has been full.
### Waiting for All Members
### Waiting for all members
The wait process is described in detail in the [etcd API documentation][api].
@ -72,11 +71,11 @@ curl -X GET http://example.com/v2/keys/_etcd/registry/${UUID}?wait=true&waitInde
It keeps waiting until finding all members.
## Public Discovery Service
## Public discovery service
CoreOS Inc. hosts a public discovery service at https://discovery.etcd.io/ , which provides some nice features for ease of use.
### Mask Key Prefix
### Mask key prefix
Public discovery service will redirect `https://discovery.etcd.io/${UUID}` to etcd cluster behind for the key at `/v2/keys/_etcd/registry`. It masks register key prefix for short and readable discovery url.
@ -96,17 +95,17 @@ Possible status codes:
The generation process in the service follows the steps from [Creating a New Discovery Token][new-discovery-token] to [Specifying the Expected Cluster Size][expected-cluster-size].
### Check Discovery Status
### Check discovery status
```
GET /${UUID}
```
You can check the status for this discovery token, including the machines that have been registered, by requesting the value of the UUID.
The status for this discovery token, including the machines that have been registered, can be checked by requesting the value of the UUID.
### Open-source repository
The repository is located at https://github.com/coreos/discovery.etcd.io. You could use it to build your own public discovery service.
The repository is located at https://github.com/coreos/discovery.etcd.io. It could be used to build a custom discovery service.
[api]: ../v2/api.md#waiting-for-a-change
[cluster-size]: ../v2/admin_guide.md#optimal-cluster-size

View File

@ -1,4 +1,4 @@
# Logging Conventions
# Logging conventions
etcd uses the [capnslog][capnslog] library for logging application output categorized into *levels*. A log message's level is determined according to these conventions:
@ -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,9 +2,9 @@
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 you want to make 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
## Prepare release
Set desired version as environment variable for following steps. Here is an example to release 2.3.0:
@ -15,7 +15,7 @@ export PREV_VERSION=v2.2.5
All releases version numbers follow the format of [semantic versioning 2.0.0](http://semver.org/).
### Major, Minor Version Release, or its Pre-release
### Major, minor version release, or its pre-release
- Ensure the relevant milestone on GitHub is complete. All referenced issues should be closed, or moved elsewhere.
- Remove this release from [roadmap](https://github.com/coreos/etcd/blob/master/ROADMAP.md), if necessary.
@ -23,18 +23,18 @@ All releases version numbers follow the format of [semantic versioning 2.0.0](ht
- Bump [hardcoded MinClusterVerion in the repository](https://github.com/coreos/etcd/blob/master/version/version.go#L29), if necessary.
- Add feature capability maps for the new version, if necessary.
### Patch Version Release
### Patch version release
- Discuss about commits that are backported to the patch release. The commits should not include merge commits.
- Cherry-pick these commits starting from the oldest one into stable branch.
## Write Release Note
## Write release note
- Write introduction for the new release. For example, what major bug we fix, what new features we introduce or what performance improvement we make.
- Write changelog for the last release. ChangeLog should be straightforward and easy to understand for the end-user.
- Put `[GH XXXX]` at the head of change line to reference Pull Request that introduces the change. Moreover, add a link on it to jump to the Pull Request.
## Tag Version
## Tag version
- Bump [hardcoded Version in the repository](https://github.com/coreos/etcd/blob/master/version/version.go#L30) to the latest version `${VERSION}`.
- Ensure all tests on CI system are passed.
@ -45,7 +45,7 @@ All releases version numbers follow the format of [semantic versioning 2.0.0](ht
- Sanity check tag correctness through `git show tags/$VERSION`.
- Push the tag to GitHub through `git push origin tags/$VERSION`. This assumes `origin` corresponds to "https://github.com/coreos/etcd".
## Build Release Binaries and Images
## Build release binaries and images
- Ensure `actool` is available, or installing it through `go get github.com/appc/spec/actool`.
- Ensure `docker` is available.
@ -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 and images
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.
@ -66,14 +66,14 @@ The following commands are used for public release sign:
```
cd release
for i in etcd-*{.zip,.tar.gz}; do gpg2 --default-key $SUBKEYID --output ${i}.asc --detach-sign ${i}; done
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
```
The public key for GPG signing can be found at [CoreOS Application Signing Key](https://coreos.com/security/app-signing-key)
## Publish Release Page in GitHub
## Publish release page in GitHub
- Set release title as the version name.
- Follow the format of previous release pages.
@ -81,7 +81,7 @@ The public key for GPG signing can be found at [CoreOS Application Signing Key](
- Select whether it is a pre-release.
- Publish the release!
## Publish Docker Image in Quay.io
## Publish docker image in Quay.io
- Push docker image:
@ -92,7 +92,7 @@ docker push quay.io/coreos/etcd:${VERSION}
- 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.
## Announce to etcd-dev Googlegroup
## Announce to the etcd-dev Googlegroup
- Follow the format of [previous release emails](https://groups.google.com/forum/#!forum/etcd-dev).
- Make sure to include a list of authors that contributed since the previous release - something like the following might be handy:
@ -103,7 +103,7 @@ git log ...${PREV_VERSION} --pretty=format:"%an" | sort | uniq | tr '\n' ',' | s
- Send email to etcd-dev@googlegroups.com
## Post Release
## Post release
- Create new stable branch through `git push origin ${VERSION_MAJOR}.${VERSION_MINOR}` if this is a major stable release. This assumes `origin` corresponds to "https://github.com/coreos/etcd".
- Bump [hardcoded Version in the repository](https://github.com/coreos/etcd/blob/master/version/version.go#L30) to the version `${VERSION}+git`.

View File

@ -1,17 +1,17 @@
# Download and Build
# Download and build
## System Requirements
## System requirements
TODO
The etcd performance benchmarks run etcd on 8 vCPU, 16GB RAM, 50GB SSD GCE instances, but any relatively modern machine with low latency storage and a few gigabytes of memory should suffice for most use cases. Applications with large v2 data stores will require more memory than a large v3 data store since data is kept in anonymous memory instead of memory mapped from a file. than For running etcd on a cloud provider, we suggest at least a medium instance on AWS or a standard-1 instance on GCE.
## Download the Pre-built Binary
## Download the pre-built binary
The easiest way to get etcd is to use one of the pre-built release binaries which are available for OSX, Linux, Windows, appc, and Docker. Instructions for using these binaries are on the [GitHub releases page][github-release].
## Build the Latest Version
## Build the latest version
For those wanting to try the very latest version, you can build the latest version of etcd from the `master` branch.
[Go](https://golang.org/) version 1.5+ is required to build the latest version of etcd.
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.
Here are the commands to build an etcd binary from the `master` branch:
@ -33,7 +33,7 @@ $ ./bin/etcd
...
```
## Test your Installation
## Test the installation
Check the etcd binary is built correctly by starting etcd and setting a key.
@ -53,4 +53,4 @@ OK
If OK is printed, then etcd is working!
[github-release]: https://github.com/coreos/etcd/releases/
[go]: https://golang.org/doc/install
[go]: https://golang.org/doc/install

View File

@ -4,45 +4,59 @@ etcd is a distributed key-value store designed to reliably and quickly preserve
## Getting started
New etcd users and developers should get started by [downloading and building][download_build] etcd.
New etcd users and developers should get started by [downloading and building][download_build] etcd. After getting etcd, follow this [quick demo][demo] to see the basics of creating and working with an etcd cluster.
## Developing with etcd
The easiest way to get started using etcd as a distributed key-value store for your applications is to [set up a local cluster][local_cluster].
The easiest way to get started using etcd as a distributed key-value store is to [set up a local cluster][local_cluster].
- [Setting up local clusters][local_cluster]
- [Interacting with etcd][interacting]
- [API references][api_ref]
- [gRPC gateway][api_grpc_gateway]
- [Experimental features and APIs][experimental]
## Operating etcd clusters
Administrators who need to create reliable and scalable key-value stores for the developers they support should begin with a [cluster on multiple machines][clustering].
- [Setting up clusters][clustering]
- [Run etcd clusters inside containers][container]
- [Configuration][conf]
- [Security][security]
- Monitoring
- [Maintenance][maintenance]
- [Understand failures][failures]
- [Disaster recovery][recovery]
- [Performance][performance]
- [Versioning][versioning]
- [Supported platform][supported_platform]
## Learning
To learn more about the concepts and internals behind etcd, read the following pages:
- Why etcd
- Concepts
- Internals
- Why etcd (TODO)
- [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]
## Troubleshooting
[api_ref]: dev-guide/api_reference_v3.md
[api_grpc_gateway]: dev-guide/api_grpc_gateway.md
[clustering]: op-guide/clustering.md
[conf]: op-guide/configuration.md
[data_model]: learning/data_model.md
[demo]: demo.md
[download_build]: dl_build.md
[failures]: op-guide/failures.md
[glossary]: learning/glossary.md
[interacting]: dev-guide/interacting_v3.md
[local_cluster]: dev-guide/local_cluster.md
@ -50,3 +64,10 @@ To learn more about the concepts and internals behind etcd, read the following p
[recovery]: op-guide/recovery.md
[maintenance]: op-guide/maintenance.md
[security]: op-guide/security.md
[v2_migration]: op-guide/v2-migration.md
[container]: op-guide/container.md
[understand_apis]: learning/api.md
[versioning]: op-guide/versioning.md
[supported_platform]: op-guide/supported-platform.md
[experimental]: dev-guide/experimental_apis.md
[v3_upgrade]: upgrades/upgrade_3_0.md

View File

@ -0,0 +1,57 @@
# etcd3 API
NOTE: this doc is not finished!
## Response header
All Responses from etcd API have a [response header][response_header] attached. The response header includes the metadata of the response.
```proto
message ResponseHeader {
uint64 cluster_id = 1;
uint64 member_id = 2;
int64 revision = 3;
uint64 raft_term = 4;
}
```
* 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
An application may read the Cluster_ID (Member_ID) field to ensure it is communicating with the intended cluster (member).
Applications can use the `Revision` to know the latest revision of the key-value store. This is especially useful when applications specify a historical revision to make time `travel query` and wishes to know the latest revision at the time of the request.
Applications can use `Raft_Term` to detect when the cluster completes a new leader election.
## 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].
### 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:
```protobuf
message KeyValue {
bytes key = 1;
int64 create_revision = 2;
int64 mod_revision = 3;
int64 version = 4;
bytes value = 5;
int64 lease = 6;
}
```
* Key - key in bytes. An empty key is not allowed.
* Value - value in bytes.
* Version - version is the version of the key. A deletion resets the version to zero and any modification of the key increases its version.
* Create_Revision - revision of the last creation on the key.
* 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.
[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

View File

@ -0,0 +1,63 @@
# 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.
### APIs to consider
* Read APIs
* range
* watch
* Write APIs
* put
* delete
* Combination (read-modify-write) APIs
* txn
### etcd specific definitions
#### Operation completed
An etcd operation is considered complete when it is committed through consensus, and therefore “executed” -- permanently stored -- by the etcd storage engine. The client knows an operation is completed when it receives a response from the etcd server. Note that the client may be uncertain about the status of an operation if it times out, or there is a network disruption between the client and the etcd member. etcd may also abort operations when there is a leader election. etcd does not send `abort` responses to clients outstanding requests in this event.
#### 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".
### Guarantees provided
#### Atomicity
All API requests are atomic; an operation either completes entirely or not at all. For watch requests, all events generated by one operation will be in one watch response. Watch never observes partial events for a single operation.
#### Consistency
All API calls ensure [sequential consistency][seq_consistency], the strongest consistency guarantee available from distributed systems. No matter which etcd member server a client makes requests to, a client reads the same events in the same order. If two members complete the same number of operations, the state of the two members is consistent.
For watch operations, etcd guarantees to return the same value for the same key across all members for the same revision. For range operations, etcd has a similar guarantee for [linearized][Linearizability] access; serialized access may be behind the quorum state, so that the later revision is not yet available.
As with all distributed systems, it is impossible for etcd to ensure [strict consistency][strict_consistency]. etcd does not guarantee that it will return to a read the “most recent” value (as measured by a wall clock when a request is completed) available on any cluster member.
#### Isolation
etcd ensures [serializable isolation][serializable_isolation], which is the highest isolation level available in distributed systems. Read operations will never observe any intermediate data.
#### Durability
Any completed operations are durable. All accessible data is also durable data. A read will never return data that has not been made durable.
#### Linearizability
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.
For example, consider a client completing a write at time point 1 (*t1*). A client issuing a read at *t2* (for *t2* > *t1*) should receive a value at least as recent as the previous write, completed at *t1*. However, the read might actually complete only by *t3*, and the returned value, current at *t2* when the read began, might be "stale" by *t3*.
etcd does not ensure linearizability for watch operations. Users are expected to verify the revision of watch responses to ensure correct ordering.
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.
[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

@ -0,0 +1,25 @@
# Data model
etcd is designed to reliably store infrequently updated data and provide reliable watch queries. etcd exposes previous versions of key-value pairs to support inexpensive snapshots and watch history events (“time travel queries”). A persistent, multi-version, concurrency-control data model is a good fit for these use cases.
etcd stores data in a multiversion [persistent][persistent-ds] key-value store. The persistent key-value store preserves the previous version of a key-value pair when its value is superseded with new data. The key-value store is effectively immutable; its operations do not update the structure in-place, but instead always generates a new updated structure. All past versions of keys are still accessible and watchable after modification. To prevent the data store from growing indefinitely over time from maintaining old versions, the store may be compacted to shed the oldest versions of superseded data.
### Logical view
The stores logical view is a flat binary key space. The key space has a lexically sorted index on byte string keys so range queries are inexpensive.
The key space maintains multiple revisions. Each atomic mutative operation (e.g., a transaction operation may contain multiple operations) creates a new revision on the key space. All data held by previous revisions remains unchanged. Old versions of key can still be accessed through previous revisions. Likewise, revisions are indexed as well; ranging over revisions with watchers is efficient. If the store is compacted to recover space, revisions before the compact revision will be removed.
A keys lifetime spans a generation. Each key may have one or multiple generations. Creating a key increments the generation of that key, starting at 1 if the key never existed. Deleting a key generates a key tombstone, concluding the keys current generation. Each modification of a key creates a new version of the key. Once a compaction happens, any generation ended before the given revision will be removed and values set before the compaction revision except the latest one will be removed.
### 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.
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.
etcd also keeps a secondary in-memory [btree][btree] index to speed up range queries over keys. The keys in the btree index are the keys of the store exposed to user. The value is a pointer to the modification of the persistent b+tree. Compaction removes dead pointers.
[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

View File

@ -1,4 +1,4 @@
# Libraries and Tools
# Libraries and tools
**Tools**
@ -17,7 +17,8 @@
**Go libraries**
- [etcd/client](https://github.com/coreos/etcd/blob/master/client) - the officially maintained Go client
- [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.
**Java libraries**
@ -92,6 +93,10 @@
- [efrecon/etcd-tcl](https://github.com/efrecon/etcd-tcl) - Supports v2, except wait.
**Gradle Plugins**
- [gradle-etcd-rest-plugin](https://github.com/cdancy/gradle-etcd-rest-plugin) - Supports v2
**Chef Integration**
- [coderanger/etcd-chef](https://github.com/coderanger/etcd-chef)
@ -127,3 +132,4 @@
- [spf13/viper](https://github.com/spf13/viper) - Go configuration library, reads values from ENV, pflags, files, and etcd with optional encryption
- [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

View File

@ -14,18 +14,70 @@ The metrics under the `etcd` prefix are for monitoring and alerting. They are st
Metrics that are etcd2 related are documented [v2 metrics guide][v2-http-metrics].
### server
### Server
These metrics describe the status of the etcd server. In order to detect outages or problems for troubleshooting, the server metrics of every production etcd cluster should be closely monitored.
All these metrics are prefixed with `etcd_server_`
| Name | Description | Type |
|---------------------------|-----------------------------------|---------|
| leader_changes_seen_total | The number of leader changes seen | Counter |
| Name | Description | Type |
|---------------------------|----------------------------------------------------------|---------|
| has_leader | Whether or not a leader exists. 1 is existence, 0 is not.| Gauge |
| leader_changes_seen_total | The number of leader changes seen. | Counter |
| proposals_committed_total | The total number of consensus proposals committed. | Gauge |
| proposals_applied_total | The total number of consensus proposals applied. | Gauge |
| proposals_pending | The current number of pending proposals. | Gauge |
| proposals_failed_total | The total number of failed proposals seen. | Counter |
`has_leader` indicates whether the member has a leader. If a member does not have a leader, it is
totally unavailable. If all the members in the cluster do not have any leader, the entire cluster
is totally unavailable.
`leader_changes_seen_total` counts the number of leader changes the member has seen since its start. Rapid leadership changes impact the performance of etcd significantly. It also signals that the leader is unstable, perhaps due to network connectivity issues or excessive load hitting the etcd cluster.
`proposals_committed_total` records the total number of consensus proposals committed. This gauge should increase over time if the cluster is healthy. Several healthy members of an etcd cluster may have different total committed proposals at once. This discrepancy may be due to recovering from peers after starting, lagging behind the leader, or being the leader and therefore having the most commits. It is important to monitor this metric across all the members in the cluster; a consistently large lag between a single member and its leader indicates that member is slow or unhealthy.
`proposals_applied_total` records the total number of consensus proposals applied. The etcd server applies every committed proposal asynchronously. The difference between `proposals_committed_total` and `proposals_applied_total` should usually be small (within a few thousands even under high load). If the difference between them continues to rise, it indicates that the etcd server is overloaded. This might happen when applying expensive queries like heavy range queries or large txn operations.
`proposals_pending` indicates how many proposals are queued to commit. Rising pending proposals suggests there is a high client load or the member cannot commit proposals.
`proposals_failed_total` are normally related to two issues: temporary failures related to a leader election or longer downtime caused by a loss of quorum in the cluster.
### Disk
These metrics describe the status of the disk operations.
All these metrics are prefixed with `etcd_disk_`.
| Name | Description | Type |
|------------------------------------|-------------------------------------------------------|-----------|
| wal_fsync_duration_seconds | The latency distributions of fsync called by wal | Histogram |
| backend_commit_duration_seconds | The latency distributions of commit called by backend.| Histogram |
A `wal_fsync` is called when etcd persists its log entries to disk before applying them.
A `backend_commit` is called when etcd commits an incremental snapshot of its most recent changes to disk.
High disk operation latencies (`wal_fsync_duration_seconds` or `backend_commit_duration_seconds`) often indicate disk issues. It may cause high request latency or make the cluster unstable.
### Network
These metrics describe the status of the network.
All these metrics are prefixed with `etcd_network_`
| Name | Description | Type |
|---------------------------|--------------------------------------------------------------------|---------------|
| peer_sent_bytes_total | The total number of bytes sent to the peer with ID `To`. | Counter(To) |
| peer_received_bytes_total | The total number of bytes received from the peer with ID `From`. | Counter(From) |
| peer_round_trip_time_seconds | Round-Trip-Time histogram between peers. | Histogram(To) |
| client_grpc_sent_bytes_total | The total number of bytes sent to grpc clients. | Counter |
| client_grpc_received_bytes_total| The total number of bytes received to grpc clients. | Counter |
`peer_sent_bytes_total` counts the total number of bytes sent to a specific peer. Usually the leader member sends more data than other members since it is responsible for transmitting replicated data.
`peer_received_bytes_total` counts the total number of bytes received from a specific peer. Usually follower members receive data only from the leader member.
### gRPC requests
These metrics describe the requests served by a specific etcd member: total received requests, total failed requests, and processing latency. They are useful for tracking user-generated traffic hitting the etcd cluster.
@ -57,30 +109,8 @@ Example Prometheus queries that may be useful from these metrics (across all etc
The metrics under the `etcd_debugging` prefix are for debugging. They are very implementation dependent and volatile. They might be changed or removed without any warning in new etcd releases. Some of the metrics might be moved to the `etcd` prefix when they become more stable.
### etcdserver
| Name | Description | Type |
|-----------------------------------------|--------------------------------------------------|-----------|
| proposal_duration_seconds | The latency distributions of committing proposal | Histogram |
| proposals_pending | The current number of pending proposals | Gauge |
| proposals_failed_total | The total number of failed proposals | Counter |
[Proposal][glossary-proposal] duration (`proposal_duration_seconds`) provides a proposal commit latency histogram. The reported latency reflects network and disk IO delays in etcd.
Proposals pending (`proposals_pending`) indicates how many proposals are queued for commit. Rising pending proposals suggests there is a high client load or the cluster is unstable.
Failed proposals (`proposals_failed_total`) are normally related to two issues: temporary failures related to a leader election or longer duration downtime caused by a loss of quorum in the cluster.
### wal
| Name | Description | Type |
|------------------------------------|--------------------------------------------------|-----------|
| fsync_duration_seconds | The latency distributions of fsync called by wal | Histogram |
| last_index_saved | The index of the last entry saved by wal | Gauge |
Abnormally high fsync duration (`fsync_duration_seconds`) indicates disk issues and might cause the cluster to be unstable.
### snapshot
### Snapshot
| Name | Description | Type |
|--------------------------------------------|------------------------------------------------------------|-----------|
@ -88,24 +118,6 @@ Abnormally high fsync duration (`fsync_duration_seconds`) indicates disk issues
Abnormally high snapshot duration (`snapshot_save_total_duration_seconds`) indicates disk issues and might cause the cluster to be unstable.
### rafthttp
| Name | Description | Type | Labels |
|-----------------------------------|--------------------------------------------|--------------|--------------------------------|
| message_sent_latency_seconds | The latency distributions of messages sent | HistogramVec | sendingType, msgType, remoteID |
| message_sent_failed_total | The total number of failed messages sent | Summary | sendingType, msgType, remoteID |
Abnormally high message duration (`message_sent_latency_seconds`) indicates network issues and might cause the cluster to be unstable.
An increase in message failures (`message_sent_failed_total`) indicates more severe network issues and might cause the cluster to be unstable.
Label `sendingType` is the connection type to send messages. `message`, `msgapp` and `msgappv2` use HTTP streaming, while `pipeline` does HTTP request for each message.
Label `msgType` is the type of raft message. `MsgApp` is log replication messages; `MsgSnap` is snapshot install messages; `MsgProp` is proposal forward messages; the others maintain internal raft status. Given large snapshots, a lengthy msgSnap transmission latency should be expected. For other types of messages, given enough network bandwidth, latencies comparable to ping latency should be expected.
Label `remoteID` is the member ID of the message destination.
## Prometheus supplied metrics
The Prometheus client library provides a number of metrics under the `go` and `process` namespaces. There are a few that are particlarly interesting.

View File

@ -2,9 +2,9 @@
## Overview
Starting an etcd cluster statically requires that each member knows another in the cluster. In a number of cases, you might not know the IPs of your cluster members ahead of time. In these cases, you can bootstrap an etcd cluster with the help of a discovery service.
Starting an etcd cluster statically requires that each member knows another in the cluster. In a number of cases, the IPs of the cluster members may be unknown ahead of time. In these cases, the etcd cluster can be bootstrapped with the help of a discovery service.
Once an etcd cluster is up and running, adding or removing members is done via [runtime reconfiguration][runtime-conf]. To better understand the design behind runtime reconfiguration, we suggest you read [the runtime configuration design document][runtime-reconf-design].
Once an etcd cluster is up and running, adding or removing members is done via [runtime reconfiguration][runtime-conf]. To better understand the design behind runtime reconfiguration, we suggest reading [the runtime configuration design document][runtime-reconf-design].
This guide will cover the following mechanisms for bootstrapping an etcd cluster:
@ -22,7 +22,7 @@ Each of the bootstrapping mechanisms will be used to create a three machine etcd
## Static
As we know the cluster members, their addresses and the size of the cluster before starting, we can use an offline bootstrap configuration by setting the `initial-cluster` flag. Each machine will get either the following command line or environment variables:
As we know the cluster members, their addresses and the size of the cluster before starting, we can use an offline bootstrap configuration by setting the `initial-cluster` flag. Each machine will get either the following environment variables or command line:
```
ETCD_INITIAL_CLUSTER="infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380"
@ -36,11 +36,11 @@ ETCD_INITIAL_CLUSTER_STATE=new
Note that the URLs specified in `initial-cluster` are the _advertised peer URLs_, i.e. they should match the value of `initial-advertise-peer-urls` on the respective nodes.
If you are spinning up multiple clusters (or creating and destroying a single cluster) with same configuration for testing purpose, it is highly recommended that you specify a unique `initial-cluster-token` for the different clusters. By doing this, etcd can generate unique cluster IDs and member IDs for the clusters even if they otherwise have the exact same configuration. This can protect you from cross-cluster-interaction, which might corrupt your clusters.
If spinning up multiple clusters (or creating and destroying a single cluster) with same configuration for testing purpose, it is highly recommended that each cluster is given a unique `initial-cluster-token`. By doing this, etcd can generate unique cluster IDs and member IDs for the clusters even if they otherwise have the exact same configuration. This can protect etcd from cross-cluster-interaction, which might corrupt the clusters.
etcd listens on [`listen-client-urls`][conf-listen-client] to accept client traffic. etcd member advertises the URLs specified in [`advertise-client-urls`][conf-adv-client] to other members, proxies, clients. Please make sure the `advertise-client-urls` are reachable from intended clients. A common mistake is setting `advertise-client-urls` to localhost or leave it as default when you want the remote clients to reach etcd.
etcd listens on [`listen-client-urls`][conf-listen-client] to accept client traffic. etcd member advertises the URLs specified in [`advertise-client-urls`][conf-adv-client] to other members, proxies, clients. Please make sure the `advertise-client-urls` are reachable from intended clients. A common mistake is setting `advertise-client-urls` to localhost or leave it as default if the remote clients should reach etcd.
On each machine you would start etcd with these flags:
On each machine, start etcd with these flags:
```
$ etcd --name infra0 --initial-advertise-peer-urls http://10.0.1.10:2380 \
@ -70,9 +70,99 @@ $ etcd --name infra2 --initial-advertise-peer-urls http://10.0.1.12:2380 \
--initial-cluster-state new
```
The command line parameters starting with `--initial-cluster` will be ignored on subsequent runs of etcd. You are free to remove the environment variables or command line flags after the initial bootstrap process. If you need to make changes to the configuration later (for example, adding or removing members to/from the cluster), see the [runtime configuration][runtime-conf] guide.
The command line parameters starting with `--initial-cluster` will be ignored on subsequent runs of etcd. Feel free to remove the environment variables or command line flags after the initial bootstrap process. If the configuration needs changes later (for example, adding or removing members to/from the cluster), see the [runtime configuration][runtime-conf] guide.
### Error Cases
### TLS
etcd supports encrypted communication through the TLS protocol. TLS channels can be used for encrypted internal cluster communication between peers as well as encrypted client traffic. This section provides examples for setting up a cluster with peer and client TLS. Additional information detailing etcd's TLS support can be found in the [security guide][security-guide].
#### Self-signed certificates
A cluster using self-signed certificates both encrypts traffic and authenticates its connections. To start a cluster with self-signed certificates, each cluster member should have a unique key pair (`member.crt`, `member.key`) signed by a shared cluster CA certificate (`ca.crt`) for both peer connections and client connections. Certificates may be generated by following the etcd [TLS setup][tls-setup] example.
On each machine, etcd would be started with these flags:
```
$ etcd --name infra0 --initial-advertise-peer-urls http://10.0.1.10:2380 \
--listen-peer-urls https://10.0.1.10:2380 \
--listen-client-urls https://10.0.1.10:2379,https://127.0.0.1:2379 \
--advertise-client-urls https://10.0.1.10:2379 \
--initial-cluster-token etcd-cluster-1 \
--initial-cluster infra0=https://10.0.1.10:2380,infra1=https://10.0.1.11:2380,infra2=https://10.0.1.12:2380 \
--initial-cluster-state new \
--client-cert-auth --trusted-ca-file=/path/to/ca-client.crt \
--cert-file=/path/to/infra0-client.crt --key-file=/path/to/infra0-client.key \
--peer-client-cert-auth --peer-trusted-ca-file=ca-peer.crt \
--peer-cert-file=/path/to/infra0-peer.crt --peer-key-file=/path/to/infra0-peer.key
```
```
$ etcd --name infra1 --initial-advertise-peer-urls https://10.0.1.11:2380 \
--listen-peer-urls https://10.0.1.11:2380 \
--listen-client-urls https://10.0.1.11:2379,https://127.0.0.1:2379 \
--advertise-client-urls https://10.0.1.11:2379 \
--initial-cluster-token etcd-cluster-1 \
--initial-cluster infra0=https://10.0.1.10:2380,infra1=https://10.0.1.11:2380,infra2=https://10.0.1.12:2380 \
--initial-cluster-state new \
--client-cert-auth --trusted-ca-file=/path/to/ca-client.crt \
--cert-file=/path/to/infra1-client.crt --key-file=/path/to/infra1-client.key \
--peer-client-cert-auth --peer-trusted-ca-file=ca-peer.crt \
--peer-cert-file=/path/to/infra1-peer.crt --peer-key-file=/path/to/infra1-peer.key
```
```
$ etcd --name infra2 --initial-advertise-peer-urls https://10.0.1.12:2380 \
--listen-peer-urls https://10.0.1.12:2380 \
--listen-client-urls https://10.0.1.12:2379,https://127.0.0.1:2379 \
--advertise-client-urls https://10.0.1.12:2379 \
--initial-cluster-token etcd-cluster-1 \
--initial-cluster infra0=https://10.0.1.10:2380,infra1=https://10.0.1.11:2380,infra2=https://10.0.1.12:2380 \
--initial-cluster-state new \
--client-cert-auth --trusted-ca-file=/path/to/ca-client.crt \
--cert-file=/path/to/infra2-client.crt --key-file=/path/to/infra2-client.key \
--peer-client-cert-auth --peer-trusted-ca-file=ca-peer.crt \
--peer-cert-file=/path/to/infra2-peer.crt --peer-key-file=/path/to/infra2-peer.key
```
#### Automatic certificates
If the cluster needs encrypted communication but does not require authenticated connections, etcd can be configured to automatically generate its keys. On initialization, each member creates its own set of keys based on its advertised IP addresses and hosts.
On each machine, etcd would be started with these flag:
```
$ etcd --name infra0 --initial-advertise-peer-urls https://10.0.1.10:2380 \
--listen-peer-urls https://10.0.1.10:2380 \
--listen-client-urls https://10.0.1.10:2379,https://127.0.0.1:2379 \
--advertise-client-urls https://10.0.1.10:2379 \
--initial-cluster-token etcd-cluster-1 \
--initial-cluster infra0=https://10.0.1.10:2380,infra1=https://10.0.1.11:2380,infra2=https://10.0.1.12:2380 \
--initial-cluster-state new \
--auto-tls \
--peer-auto-tls
```
```
$ etcd --name infra1 --initial-advertise-peer-urls https://10.0.1.11:2380 \
--listen-peer-urls https://10.0.1.11:2380 \
--listen-client-urls https://10.0.1.11:2379,https://127.0.0.1:2379 \
--advertise-client-urls https://10.0.1.11:2379 \
--initial-cluster-token etcd-cluster-1 \
--initial-cluster infra0=https://10.0.1.10:2380,infra1=https://10.0.1.11:2380,infra2=https://10.0.1.12:2380 \
--initial-cluster-state new \
--auto-tls \
--peer-auto-tls
```
```
$ etcd --name infra2 --initial-advertise-peer-urls https://10.0.1.12:2380 \
--listen-peer-urls https://10.0.1.12:2380 \
--listen-client-urls https://10.0.1.12:2379,https://127.0.0.1:2379 \
--advertise-client-urls https://10.0.1.12:2379 \
--initial-cluster-token etcd-cluster-1 \
--initial-cluster infra0=https://10.0.1.10:2380,infra1=https://10.0.1.11:2380,infra2=https://10.0.1.12:2380 \
--initial-cluster-state new \
--auto-tls \
--peer-auto-tls
```
### Error cases
In the following example, 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.
@ -100,7 +190,7 @@ etcd: error setting up initial cluster: infra0 has different advertised URLs in
exit 1
```
If you configure a peer with a different set of configuration and attempt to join this cluster you will get a cluster ID mismatch and etcd will exit.
If a peer is configured with a different set of configuration arguments and attempts to join this cluster, etcd will report a cluster ID mismatch will exit.
```
$ etcd --name infra3 --initial-advertise-peer-urls http://10.0.1.13:2380 \
@ -115,34 +205,34 @@ exit 1
## Discovery
In a number of cases, you might not know the IPs of your cluster peers ahead of time. This is common when utilizing cloud providers or when your network uses DHCP. In these cases, rather than specifying a static configuration, you can use an existing etcd cluster to bootstrap a new one. We call this process "discovery".
In a number of cases, the IPs of the cluster peers may not be known ahead of time. This is common when utilizing cloud providers or when the network uses DHCP. In these cases, rather than specifying a static configuration, use an existing etcd cluster to bootstrap a new one. We call this process "discovery".
There two methods that can be used for discovery:
* etcd discovery service
* DNS SRV records
### etcd Discovery
### etcd discovery
To better understand the design about discovery service protocol, we suggest you read [this][discovery-proto].
To better understand the design about discovery service protocol, we suggest reading the discovery service protocol [documentation][discovery-proto].
#### Lifetime of a Discovery URL
#### Lifetime of a discovery URL
A discovery URL identifies a unique etcd cluster. Instead of reusing a discovery URL, you should always create discovery URLs for new clusters.
A discovery URL identifies a unique etcd cluster. Instead of reusing a discovery URL, always create discovery URLs for new clusters.
Moreover, discovery URLs should ONLY be used for the initial bootstrapping of a cluster. To change cluster membership after the cluster is already running, see the [runtime reconfiguration][runtime-conf] guide.
#### Custom etcd Discovery Service
#### Custom etcd discovery service
Discovery uses an existing cluster to bootstrap itself. If you are using your own etcd cluster you can create a URL like so:
Discovery uses an existing cluster to bootstrap itself. If using a private etcd cluster, can create a URL like so:
```
$ curl -X PUT https://myetcd.local/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83/_config/size -d value=3
```
By setting the size key to the URL, you create a discovery URL with an expected cluster size of 3.
By setting the size key to the URL, a discovery URL is created with an expected cluster size of 3.
The URL you will use in this case will be `https://myetcd.local/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83` and the etcd members will use the `https://myetcd.local/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83` directory for registration as they start.
The URL to use in this case will be `https://myetcd.local/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83` and the etcd members will use the `https://myetcd.local/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83` directory for registration as they start.
**Each member must have a different name flag specified. `Hostname` or `machine-id` can be a good choice. Or discovery will fail due to duplicated name.**
@ -172,16 +262,16 @@ $ etcd --name infra2 --initial-advertise-peer-urls http://10.0.1.12:2380 \
This will cause each member to register itself with the custom etcd discovery service and begin the cluster once all machines have been registered.
#### Public etcd Discovery Service
#### Public etcd discovery service
If you do not have access to an existing cluster, you can use the public discovery service hosted at `discovery.etcd.io`. You can create a private discovery URL using the "new" endpoint like so:
If no exiting cluster is available, use the public discovery service hosted at `discovery.etcd.io`. To create a private discovery URL using the "new" endpoint, use the command:
```
$ curl https://discovery.etcd.io/new?size=3
https://discovery.etcd.io/3e86b59982e49066c5d813af1c2e2579cbf573de
```
This will create the cluster with an initial expected size of 3 members. If you do not specify a size, a default of 3 will be used.
This will create the cluster with an initial expected size of 3 members. If no size is specified, a default of 3 is used.
```
ETCD_DISCOVERY=https://discovery.etcd.io/3e86b59982e49066c5d813af1c2e2579cbf573de
@ -219,11 +309,11 @@ $ etcd --name infra2 --initial-advertise-peer-urls http://10.0.1.12:2380 \
This will cause each member to register itself with the discovery service and begin the cluster once all members have been registered.
You can use the environment variable `ETCD_DISCOVERY_PROXY` to cause etcd to use an HTTP proxy to connect to the discovery service.
Use the environment variable `ETCD_DISCOVERY_PROXY` to cause etcd to use an HTTP proxy to connect to the discovery service.
#### Error and Warning Cases
#### Error and warning cases
##### Discovery Server Errors
##### Discovery server errors
```
@ -238,8 +328,7 @@ exit 1
##### Warnings
This is a harmless warning notifying you that the discovery URL will be
ignored on this machine.
This is a harmless warning indicating the discovery URL will be ignored on this machine.
```
$ etcd --name infra0 --initial-advertise-peer-urls http://10.0.1.10:2380 \
@ -250,7 +339,7 @@ $ etcd --name infra0 --initial-advertise-peer-urls http://10.0.1.10:2380 \
etcdserver: discovery token ignored since a cluster has already been initialized. Valid log found at /var/lib/etcd
```
### DNS Discovery
### DNS discovery
DNS [SRV records][rfc-srv] can be used as a discovery mechanism.
The `-discovery-srv` flag can be used to set the DNS domain name where the discovery SRV records can be found.
@ -259,14 +348,16 @@ The following DNS SRV records are looked up in the listed order:
* _etcd-server-ssl._tcp.example.com
* _etcd-server._tcp.example.com
If `_etcd-server-ssl._tcp.example.com` is found then etcd will attempt the bootstrapping process over SSL.
If `_etcd-server-ssl._tcp.example.com` is found then etcd will attempt the bootstrapping process over TLS.
To help clients discover the etcd cluster, the following DNS SRV records are looked up in the listed order:
* _etcd-client._tcp.example.com
* _etcd-client-ssl._tcp.example.com
If `_etcd-client-ssl._tcp.example.com` is found, clients will attempt to communicate with the etcd cluster over SSL.
If `_etcd-client-ssl._tcp.example.com` is found, clients will attempt to communicate with the etcd cluster over SSL/TLS.
If etcd is using TLS without a custom certificate authority, the discovery domain (e.g., example.com) must match the SRV record domain (e.g., infra1.example.com). This is to mitigate attacks that forge SRV records to point to a different domain; the domain would have a valid certificate under PKI but be controlled by an unknown third party.
#### Create DNS SRV records
@ -290,6 +381,7 @@ infra0.example.com. 300 IN A 10.0.1.10
infra1.example.com. 300 IN A 10.0.1.11
infra2.example.com. 300 IN A 10.0.1.12
```
#### Bootstrap the etcd cluster using DNS
etcd cluster members can listen on domain names or IP address, the bootstrap process will resolve DNS A records.
@ -329,7 +421,7 @@ $ etcd --name infra2 \
--listen-peer-urls http://infra2.example.com:2380
```
You can also bootstrap the cluster using IP addresses instead of domain names:
The cluster can also bootstrap using IP addresses instead of domain names:
```
$ etcd --name infra0 \
@ -370,11 +462,13 @@ When the `--proxy` flag is set, etcd runs in [proxy mode][proxy]. This proxy mod
To setup an etcd cluster with proxies of v2 API, please read the the [clustering doc in etcd 2.3 release][clustering_etcd2].
[conf-adv-client]: configuration.md#-advertise-client-urls
[conf-listen-client]: configuration.md#-listen-client-urls
[discovery-proto]: dev-internal/discovery_protocol.md
[conf-adv-client]: configuration.md#--advertise-client-urls
[conf-listen-client]: configuration.md#--listen-client-urls
[discovery-proto]: ../dev-internal/discovery_protocol.md
[rfc-srv]: http://www.ietf.org/rfc/rfc2052.txt
[runtime-conf]: runtime-configuration.md
[runtime-reconf-design]: runtime-reconf-design.md
[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

View File

@ -1,22 +1,20 @@
# Configuration Flags
# Configuration flags
etcd is configurable through command-line flags and environment variables. Options set on the command line take precedence over those from the environment.
The format of environment variable for flag `--my-flag` is `ETCD_MY_FLAG`. It applies to all flags.
The format of environment variable for flag `--my-flag` is `ETCD_MY_FLAG`. It applies to all flags.
The [official etcd ports][iana-ports] are 2379 for client requests, and 2380 for peer communication. Some legacy code and documentation still references ports 4001 and 7001, but all new etcd use and discussion should adopt the assigned ports.
The [official etcd ports][iana-ports] are 2379 for client requests and 2380 for peer communication. The etcd ports can be set to accept TLS traffic, non-TLS traffic, or both TLS and non-TLS traffic.
To start etcd automatically using custom settings at startup in Linux, using a [systemd][systemd-intro] unit is highly recommended.
[systemd-intro]: http://freedesktop.org/wiki/Software/systemd/
## Member Flags
## Member flags
### --name
+ Human-readable name for this member.
+ default: "default"
+ env variable: ETCD_NAME
+ This value is referenced as this node's own entries listed in the `--initial-cluster` flag (Ex: `default=http://localhost:2380` or `default=http://localhost:2380,default=http://localhost:7001`). This needs to match the key used in the flag if you're using [static bootstrapping][build-cluster]. When using discovery, each member must have a unique name. `Hostname` or `machine-id` can be a good choice.
+ This value is referenced as this node's own entries listed in the `--initial-cluster` flag (e.g., `default=http://localhost:2380`). This needs to match the key used in the flag if using [static bootstrapping][build-cluster]. When using discovery, each member must have a unique name. `Hostname` or `machine-id` can be a good choice.
### --data-dir
+ Path to the data directory.
@ -39,20 +37,20 @@ To start etcd automatically using custom settings at startup in Linux, using a [
+ env variable: ETCD_HEARTBEAT_INTERVAL
### --election-timeout
+ Time (in milliseconds) for an election to timeout. See [Documentation/tuning.md](tuning.md#time-parameters) for details.
+ Time (in milliseconds) for an election to timeout. See [Documentation/tuning.md][tuning] for details.
+ default: "1000"
+ env variable: ETCD_ELECTION_TIMEOUT
### --listen-peer-urls
+ List of URLs to listen on for peer traffic. This flag tells the etcd to accept incoming requests from its peers on the specified scheme://IP:port combinations. Scheme can be either http or https.If 0.0.0.0 is specified as the IP, etcd listens to the given port on all interfaces. If an IP address is given as well as a port, etcd will listen on the given port and interface. Multiple URLs may be used to specify a number of addresses and ports to listen on. The etcd will respond to requests from any of the listed addresses and ports.
+ default: "http://localhost:2380,http://localhost:7001"
+ default: "http://localhost:2380"
+ env variable: ETCD_LISTEN_PEER_URLS
+ example: "http://10.0.0.1:2380"
+ invalid example: "http://example.com:2380" (domain name is invalid for binding)
### --listen-client-urls
+ List of URLs to listen on for client traffic. This flag tells the etcd to accept incoming requests from the clients on the specified scheme://IP:port combinations. Scheme can be either http or https. If 0.0.0.0 is specified as the IP, etcd listens to the given port on all interfaces. If an IP address is given as well as a port, etcd will listen on the given port and interface. Multiple URLs may be used to specify a number of addresses and ports to listen on. The etcd will respond to requests from any of the listed addresses and ports.
+ default: "http://localhost:2379,http://localhost:4001"
+ default: "http://localhost:2379"
+ env variable: ETCD_LISTEN_CLIENT_URLS
+ example: "http://10.0.0.1:2379"
+ invalid example: "http://example.com:2379" (domain name is invalid for binding)
@ -61,20 +59,20 @@ To start etcd automatically using custom settings at startup in Linux, using a [
+ Maximum number of snapshot files to retain (0 is unlimited)
+ default: 5
+ env variable: ETCD_MAX_SNAPSHOTS
+ The default for users on Windows is unlimited, and manual purging down to 5 (or your preference for safety) is recommended.
+ The default for users on Windows is unlimited, and manual purging down to 5 (or some preference for safety) is recommended.
### --max-wals
+ Maximum number of wal files to retain (0 is unlimited)
+ default: 5
+ env variable: ETCD_MAX_WALS
+ The default for users on Windows is unlimited, and manual purging down to 5 (or your preference for safety) is recommended.
+ The default for users on Windows is unlimited, and manual purging down to 5 (or some preference for safety) is recommended.
### --cors
+ Comma-separated white list of origins for CORS (cross-origin resource sharing).
+ default: none
+ env variable: ETCD_CORS
## Clustering Flags
## Clustering flags
`--initial` prefix flags are used in bootstrapping ([static bootstrap][build-cluster], [discovery-service bootstrap][discovery] or [runtime reconfiguration][reconfig]) a new member, and ignored when restarting an existing member.
@ -83,13 +81,13 @@ To start etcd automatically using custom settings at startup in Linux, using a [
### --initial-advertise-peer-urls
+ List of this member's peer URLs to advertise to the rest of the cluster. These addresses are used for communicating etcd data around the cluster. At least one must be routable to all cluster members. These URLs can contain domain names.
+ default: "http://localhost:2380,http://localhost:7001"
+ default: "http://localhost:2380"
+ env variable: ETCD_INITIAL_ADVERTISE_PEER_URLS
+ example: "http://example.com:2380, http://10.0.0.1:2380"
### --initial-cluster
+ Initial cluster configuration for bootstrapping.
+ default: "default=http://localhost:2380,default=http://localhost:7001"
+ default: "default=http://localhost:2380"
+ env variable: ETCD_INITIAL_CLUSTER
+ The key is the value of the `--name` flag for each node provided. The default uses `default` for the key because this is the default for the `--name` flag.
@ -107,10 +105,10 @@ To start etcd automatically using custom settings at startup in Linux, using a [
### --advertise-client-urls
+ List of this member's client URLs to advertise to the rest of the cluster. These URLs can contain domain names.
+ default: "http://localhost:2379,http://localhost:4001"
+ default: "http://localhost:2379"
+ env variable: ETCD_ADVERTISE_CLIENT_URLS
+ example: "http://example.com:2379, http://10.0.0.1:2379"
+ Be careful if you are advertising URLs such as http://localhost:2379 from a cluster member and are using the proxy feature of etcd. This will cause loops, because the proxy will be forwarding requests to itself until its resources (memory, file descriptors) are eventually depleted.
+ Be careful if advertising URLs such as http://localhost:2379 from a cluster member and are using the proxy feature of etcd. This will cause loops, because the proxy will be forwarding requests to itself until its resources (memory, file descriptors) are eventually depleted.
### --discovery
+ Discovery URL used to bootstrap the cluster.
@ -123,7 +121,7 @@ To start etcd automatically using custom settings at startup in Linux, using a [
+ env variable: ETCD_DISCOVERY_SRV
### --discovery-fallback
+ Expected behavior ("exit" or "proxy") when discovery services fails.
+ Expected behavior ("exit" or "proxy") when discovery services fails. "proxy" supports v2 API only.
+ default: "proxy"
+ env variable: ETCD_DISCOVERY_FALLBACK
@ -137,9 +135,14 @@ To start etcd automatically using custom settings at startup in Linux, using a [
+ default: false
+ env variable: ETCD_STRICT_RECONFIG_CHECK
## Proxy Flags
### --auto-compaction-retention
+ Auto compaction retention for mvcc key value store in hour. 0 means disable auto compaction.
+ default: 0
+ env variable: ETCD_AUTO_COMPACTION_RETENTION
`--proxy` prefix flags configures etcd to run in [proxy mode][proxy].
## Proxy flags
`--proxy` prefix flags configures etcd to run in [proxy mode][proxy]. "proxy" supports v2 API only.
### --proxy
+ Proxy mode setting ("off", "readonly" or "on").
@ -168,11 +171,11 @@ To start etcd automatically using custom settings at startup in Linux, using a [
### --proxy-read-timeout
+ Time (in milliseconds) for a read to timeout or 0 to disable the timeout.
+ Don't change this value if you use watches because they are using long polling requests.
+ Don't change this value if using watches because use long polling requests.
+ default: 0
+ env variable: ETCD_PROXY_READ_TIMEOUT
## Security Flags
## Security flags
The security flags help to [build a secure etcd cluster][security].
@ -236,7 +239,7 @@ The security flags help to [build a secure etcd cluster][security].
+ default: false
+ env variable: ETCD_PEER_AUTO_TLS
## Logging Flags
## Logging flags
### --debug
+ Drop the default log level to DEBUG for all subpackages.
@ -249,7 +252,7 @@ The security flags help to [build a secure etcd cluster][security].
+ env variable: ETCD_LOG_PACKAGE_LEVELS
## Unsafe Flags
## Unsafe flags
Please be CAUTIOUS when using unsafe flags because it will break the guarantees given by the consensus protocol.
For example, it may panic if other members in the cluster are still alive.
@ -260,12 +263,16 @@ Follow the instructions when using these flags.
+ default: false
+ env variable: ETCD_FORCE_NEW_CLUSTER
## Miscellaneous Flags
## Miscellaneous flags
### --version
+ Print the version and exit.
+ default: false
### --config-file
+ Load server configuration from a file.
+ default: none
## Profiling flags
### --enable-pprof
@ -277,9 +284,7 @@ Follow the instructions when using these flags.
[discovery]: clustering.md#discovery
[iana-ports]: https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=etcd
[proxy]: ../v2/proxy.md
[reconfig]: runtime-configuration.md
[restore]: ../v2/admin_guide.md#restoring-a-backup
[rfc-v3]: rfc/v3api.md
[security]: security.md
[systemd-intro]: http://freedesktop.org/wiki/Software/systemd/
[tuning]: tuning.md#time-parameters
[tuning]: ../tuning.md#time-parameters

View File

@ -0,0 +1,61 @@
# Run etcd clusters inside containers
The following guide shows how to run etcd with rkt and Docker using the [static bootstrap process](clustering.md#static).
## Docker
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.
```
# For each machine
ETCD_VERSION=v3.0.0
TOKEN=my-etcd-token
CLUSTER_STATE=new
NAME_1=etcd-node-0
NAME_2=etcd-node-1
NAME_3=etcd-node-2
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
# 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}
# 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}
# 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}
```
To run `etcdctl` using API version 3:
```
docker exec etcd /bin/sh -c "export ETCDCTL_API=3 && /usr/local/bin/etcdctl put foo bar"
```

View File

@ -0,0 +1,44 @@
# Understand failures
Failures are common in a large deployment of machines. A machine fails when its hardware or software malfunctions. Multiple machines fail together when there are power failures or network issues. Multiple kinds of failures can also happen at once; it is almost impossible to enumerate all possible failure cases.
In this section, we catalog kinds of failures and discuss how etcd is designed to tolerate these failures. Most users, if not all, can map a particular failure into one kind of failure. To prepare for rare or [unrecoverable failures][unrecoverable], always [back up][backup] the etcd cluster.
## Minor followers failure
When fewer than half of the followers fail, the etcd cluster can still accept requests and make progress without any major disruption. For example, two follower failures will not affect a five member etcd clusters operation. However, clients will lose connectivity to the failed members. Client libraries should hide these interruptions from users for read requests by automatically reconnecting to other members. Operators should expect the system load on the other members to increase due to the reconnections.
## Leader failure
When a leader fails, the etcd cluster automatically elects a new leader. The election does not happen instantly once the leader fails. It takes about an election timeout to elect a new leader since the failure detection model is timeout based.
During the leader election the cluster cannot process any writes. Write requests sent during the election are queued for processing until a new leader is elected.
Writes already sent to the old leader but not yet committed may be lost. The new leader has the power to rewrite any uncommitted entries from the previous leader. From the user perspective, some write requests might time out after a new leader election. However, no committed writes are ever lost.
The new leader extends timeouts automatically for all leases. This mechanism ensures a lease will not expire before the granted TTL even if it was granted by the old leader.
## Majority failure
When the majority members of the cluster fail, the etcd cluster fails and cannot accept more writes.
The etcd cluster can only recover from a majority failure once the majority of members become available. If a majority of members cannot come back online, then the operator must start [disaster recovery][unrecoverable] to recover the cluster.
Once a majority of members works, the etcd cluster elects a new leader automatically and returns to a healthy state. The new leader extends timeouts automatically for all leases. This mechanism ensures no lease expires due to server side unavailability.
## Network partition
A network partition is similar to a minor followers failure or a leader failure. A network partition divides the etcd cluster into two parts; one with a member majority and the other with a member minority. The majority side becomes the available cluster and the minority side is unavailable; there is no “split-brain” in etcd.
If the leader is on the majority side, then from the majority point of view the failure is a minority follower failure. If the leader is on the minority side, then it is a leader failure. The leader on the minority side steps down and the majority side elects a new leader.
Once the network partition clears, the minority side automatically recognizes the leader from the majority side and recovers its state.
## Failure during bootstrapping
A cluster bootstrap is only successful if all required members successfully start. If any failure happens during bootstrapping, remove the data directories on all members and re-bootstrap the cluster with a new cluster-token or new discovery token.
Of course, it is possible to recover a failed bootstrapped cluster like recovering a running cluster. However, it almost always takes more time and resources to recover that cluster than bootstrapping a new one, since there is no data to recover.
[backup]: maintenance.md#snapshot-backup
[unrecoverable]: recovery.md#disaster-recovery

View File

@ -12,11 +12,11 @@ Since etcd keeps an exact history of its keyspace, this history should be period
The keyspace can be compacted automatically with `etcd`'s time windowed history retention policy, or manually with `etcdctl`. The `etcdctl` method provides fine-grained control over the compacting process whereas automatic compacting fits applications that only need key history for some length of time.
`etcd` can be set to automatically compact the keyspace with the `--experimental-auto-compaction` option with a period of hours:
`etcd` can be set to automatically compact the keyspace with the `--auto-compaction` option with a period of hours:
```sh
# keep one hour of history
$ etcd --experimental-auto-compaction-retention=1
$ etcd --auto-compaction-retention=1
```
An `etcdctl` initiated compaction works as follows:
@ -66,7 +66,7 @@ $ while [ 1 ]; do dd if=/dev/urandom bs=1024 count=1024 | etcdctl put key || b
...
Error: rpc error: code = 8 desc = etcdserver: mvcc: database space exceeded
# confirm quota space is exceeded
$ etcdctl endpoint status
$ etcdctl --write-out=table endpoint status
+----------------+------------------+-----------+---------+-----------+-----------+------------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | RAFT TERM | RAFT INDEX |
+----------------+------------------+-----------+---------+-----------+-----------+------------+
@ -105,7 +105,7 @@ A snapshot is taken with `etcdctl`:
```sh
$ etcdctl snapshot save backup.db
$ etcdctl snapshot status backup.db
$ etcdctl --write-out=table snapshot status backup.db
+----------+----------+------------+------------+
| HASH | REVISION | TOTAL KEYS | TOTAL SIZE |
+----------+----------+------------+------------+

View File

@ -10,4 +10,65 @@ There are other sub-systems which impact the overall performance of etcd. Each s
## Benchmarks
TODO
Benchmarking etcd performance can be done with the [benchmark](https://github.com/coreos/etcd/tree/master/tools/benchmark) CLI tool included with etcd.
For some baseline performance numbers, we consider a three member etcd cluster with the following hardware configuration:
- 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
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 |
Sample commands are:
```
# assuming IP_1 is leader, write requests to the leader
benchmark --endpoints={IP_1} --conns=1 --clients=1 \
put --key-size=8 --sequential-keys --total=10000 --val-size=256
benchmark --endpoints={IP_1} --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 \
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 |
Sample commands are:
```
# Linearizable read requests
benchmark --endpoints={IP_1},{IP_2},{IP_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
# 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
```
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,9 +2,9 @@
etcd is designed to withstand machine failures. An etcd cluster automatically recovers from temporary failures (e.g., machine reboots) and tolerates up to *(N-1)/2* permanent failures for a cluster of N members. When a member permanently fails, whether due to hardware failure or disk corruption, it loses access to the cluster. If the cluster permanently loses more than *(N-1)/2* members then it disastrously fails, irrevocably losing quorum. Once quorum is lost, the cluster cannot reach consensus and therefore cannot continue accepting updates.
To recover from disastrous failure, etcd provides snapshot and restore facilities to recreate the cluster without data loss.
To recover from disastrous failure, etcd v3 provides snapshot and restore facilities to recreate the cluster without v3 key data loss. To recover v2 keys, refer to the [v2 admin guide][v2_recover].
TODO(xiangli): add note to clarify this only recovers for the kv store of etcd3.
[v2_recover]: ../v2/admin_guide.md#disaster-recovery
### Snapshotting the keyspace
@ -18,6 +18,8 @@ $ etcdctl --endpoints $ENDPOINT snapshot save snapshot.db
To restore a cluster, all that is needed is a single snapshot "db" file. A cluster restore with `etcdctl snapshot restore` creates new etcd data directories; all members should restore using the same snapshot. Restoring overwrites some snapshot metadata (specifically, the member ID and cluster ID); the member loses its former identity. This metadata overwrite prevents the new member from inadvertently joining an existing cluster. Therefore in order to start a cluster from a snapshot, the restore must start a new logical cluster.
Snapshot integrity may be optionally verified at restore time. If the snapshot is taken with `etcdctl snapshot save`, it will have an integrity hash that is checked by `etcdctl snapshot restore`. If the snapshot is copied from the data directory, there is no integrity hash and it will only restore by using `--skip-hash-check`.
A restore initializes a new member of a new cluster, with a fresh cluster configuration using `etcd`'s cluster configuration flags, but preserves the contents of the etcd keyspace. Continuing from the previous example, the following creates new etcd data directories (`m1.etcd`, `m2.etcd`, `m3.etcd`) for a three member cluster:
```sh

View File

@ -1,39 +1,39 @@
# Runtime Reconfiguration
# Runtime reconfiguration
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].
To better understand the design behind runtime reconfiguration, we suggest you read [the runtime reconfiguration document][runtime-reconf].
To better understand the design behind runtime reconfiguration, we suggest reading [the runtime reconfiguration document][runtime-reconf].
## Reconfiguration Use Cases
## 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].
### Cycle or Upgrade Multiple Machines
### Cycle or upgrade multiple machines
If you need to move multiple members of your cluster due to planned maintenance (hardware upgrades, network downtime, etc.), it is recommended to modify members one at a time.
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 your 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, it is recommended to [migrate the member's data directory][member migration].
### Change the Cluster Size
### 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.
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.
### Replace A Failed Machine
### Replace a failed machine
If a machine fails due to hardware failure, data directory corruption, or some other fatal situation, it should be replaced as soon as possible. Machines that have failed but haven't been removed adversely affect your quorum and reduce the tolerance for an additional failure.
If a machine fails due to hardware failure, data directory corruption, or some other fatal situation, it should be replaced as soon as possible. Machines that have failed but haven't been removed adversely affect the quorum and reduce the tolerance for an additional failure.
To replace the machine, follow the instructions for [removing the member][remove member] from the cluster, and then [add a new member][add member] in its place. If your cluster holds more than 50MB, it is recommended to [migrate the failed member's data directory][member migration] if you can still access it.
To replace the machine, follow the instructions for [removing the member][remove member] from the cluster, and then [add a new member][add member] in its place. If the cluster holds more than 50MB, it is recommended to [migrate the failed member's data directory][member migration] if it is still accessible.
### Restart Cluster from Majority Failure
### Restart cluster from majority failure
If the majority of your cluster is lost or all of your nodes have changed IP addresses, then you need to take manual action in order to recover safely.
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
## Cluster reconfiguration operations
Now that we have the use cases in mind, let us lay out the operations involved in each.
@ -42,32 +42,30 @@ This is essentially the same requirement as for any other write to etcd.
All changes to the cluster are done one at a time:
* To update a single member peerURLs you will make an update operation
* To replace a single member you will make an add then a remove operation
* To increase from 3 to 5 members you will make two add operations
* To decrease from 5 to 3 you will make two remove operations
* 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
All of these examples will use the `etcdctl` command line tool that ships with etcd.
If you want to use the members API directly you can find the documentation [here][member-api].
To change membership without `etcdctl`, use the [v2 HTTP members API][member-api] or the [v3 gRPC members API][member-api-grpc].
TODO: v3 member API documentation
### Update a Member
### Update a member
#### Update advertise client URLs
If you would like to update the advertise client URLs of a member, you can simply restart
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
If you would like to update the advertise peer URLs of a member, you have to first update
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. You can list all members with `etcdctl`:
To update the peer URLs, first, we need to find the target member's ID. To list all members with `etcdctl`:
```sh
$ etcdctl member list
@ -83,7 +81,7 @@ $ etcdctl member update a8266ecf031671f3 http://10.0.1.10:2380
Updated member with ID a8266ecf031671f3 in cluster
```
### Remove a Member
### 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:
@ -101,11 +99,11 @@ etcd: this member has been permanently removed from the cluster. Exiting.
It is safe to remove the leader, however the cluster will be inactive while a new leader is elected. This duration is normally the period of election timeout plus the voting process.
### Add a New Member
### Add a new member
Adding a member is a two step process:
* Add the new member to the cluster via the [members API][member-api] or the `etcdctl member add` command.
* 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]:
@ -131,10 +129,10 @@ $ 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 you are 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 you add 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. You will only see this behavior 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
#### 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.
@ -165,7 +163,7 @@ etcd: this member has been permanently removed from the cluster. Exiting.
exit 1
```
### Strict Reconfiguration Check Mode (`-strict-reconfig-check`)
### Strict reconfiguration check mode (`-strict-reconfig-check`)
As described in the above, the best practice of adding new members is to configure a single member at a time and verify it starts correctly before adding more new members. This step by step approach is very important because if newly added members is not configured correctly (for example the peer URLs are incorrect), the cluster can lose quorum. The quorum loss happens since the newly added member are counted in the quorum even if that member is not reachable from other existing members. Also quorum loss might happen if there is a connectivity issue or there are operational issues.
@ -181,6 +179,7 @@ It is recommended to enable this option. However, it is disabled by default beca
[fault tolerance table]: ../v2/admin_guide.md#fault-tolerance-table
[majority failure]: #restart-cluster-from-majority-failure
[member-api]: ../v2/members_api.md
[member-api-grpc]: ../dev-guide/api_reference_v3.md#service-cluster-etcdserveretcdserverpbrpcproto
[member migration]: ../v2/admin_guide.md#member-migration
[remove member]: #remove-a-member
[runtime-reconf]: runtime-reconf-design.md

View File

@ -1,50 +1,50 @@
# Design of Runtime Reconfiguration
# Design of runtime reconfiguration
Runtime reconfiguration is one of the hardest and most error prone features in a distributed system, especially in a consensus based system like etcd.
Read on to learn about the design of etcd's runtime reconfiguration commands and how we tackled these problems.
## Two Phase Config Changes Keep you Safe
## Two phase config changes keep the cluster safe
In etcd, every runtime reconfiguration has to go through [two phases][add-member] for safety reasons. For example, to add a member you need to first inform cluster of new configuration and then start the new member.
In etcd, every runtime reconfiguration has to go through [two phases][add-member] for safety reasons. For example, to add a member, first inform cluster of new configuration and then start the new member.
Phase 1 - Inform cluster of new configuration
To add a member into etcd cluster, you need to make an API call to request a new member to be added to the cluster. And this is only way that you can add a new member into an existing cluster. The API call returns when the cluster agrees on the configuration change.
To add a member into etcd cluster, make an API call to request a new member to be added to the cluster. This is only way to add a new member into an existing cluster. The API call returns when the cluster agrees on the configuration change.
Phase 2 - Start new member
To join the etcd member into the existing cluster, you need to specify the correct `initial-cluster` and set `initial-cluster-state` to `existing`. When the member starts, it will contact the existing cluster first and verify the current cluster configuration matches the expected one specified in `initial-cluster`. When the new member successfully starts, you know your cluster reached the expected configuration.
To join the etcd member into the existing cluster, specify the correct `initial-cluster` and set `initial-cluster-state` to `existing`. When the member starts, it will contact the existing cluster first and verify the current cluster configuration matches the expected one specified in `initial-cluster`. When the new member successfully starts, the cluster has reached the expected configuration.
By splitting the process into two discrete phases users are forced to be explicit regarding cluster membership changes. This actually gives users more flexibility and makes things easier to reason about. For example, if there is an attempt to add a new member with the same ID as an existing member in an etcd cluster, the action will fail immediately during phase one without impacting the running cluster. Similar protection is provided to prevent adding new members by mistake. If a new etcd member attempts to join the cluster before the cluster has accepted the configuration change,, it will not be accepted by the cluster.
Without the explicit workflow around cluster membership etcd would be vulnerable to unexpected cluster membership changes. For example, if etcd is running under an init system such as systemd, etcd would be restarted after being removed via the membership API, and attempt to rejoin the cluster on startup. This cycle would continue every time a member is removed via the API and systemd is set to restart etcd after failing, which is unexpected.
We think runtime reconfiguration should be a low frequent operation. We made the decision to keep it explicit and user-driven to ensure configuration safety and keep your cluster always running smoothly under your control.
We expect runtime reconfiguration to be an infrequent operation. We decided to keep it explicit and user-driven to ensure configuration safety and keep the cluster always running smoothly under explicit control.
## Permanent Loss of Quorum Requires New Cluster
## Permanent loss of quorum requires new cluster
If a cluster permanently loses a majority of its members, a new cluster will need to be started from an old data directory to recover the previous state.
It is entirely possible to force removing the failed members from the existing cluster to recover. However, we decided not to support this method since it bypasses the normal consensus committing phase, which is unsafe. If the member to remove is not actually dead or you force to remove different members through different members in the same cluster, you will end up with diverged cluster with same clusterID. This is very dangerous and hard to debug/fix afterwards.
It is entirely possible to force removing the failed members from the existing cluster to recover. However, we decided not to support this method since it bypasses the normal consensus committing phase, which is unsafe. If the member to remove is not actually dead or force removed through different members in the same cluster, etcd will end up with a diverged cluster with same clusterID. This is very dangerous and hard to debug/fix afterwards.
If you have a correct deployment, the possibility of permanent majority lose is very low. But it is a severe enough problem that worth special care. We strongly suggest you to read the [disaster recovery documentation][disaster-recovery] and prepare for permanent majority lose before you put etcd into production.
With a correct deployment, the possibility of permanent majority lose is very low. But it is a severe enough problem that worth special care. We strongly suggest reading the [disaster recovery documentation][disaster-recovery] and prepare for permanent majority lose before putting etcd into production.
## Do Not Use Public Discovery Service For Runtime Reconfiguration
## Do not use public discovery service for runtime reconfiguration
The public discovery service should only be used for bootstrapping a cluster. To join member into an existing cluster, you should use runtime reconfiguration API.
The public discovery service should only be used for bootstrapping a cluster. To join member into an existing cluster, use runtime reconfiguration API.
Discovery service is designed for bootstrapping an etcd cluster in the cloud environment, when you do not know the IP addresses of all the members beforehand. After you successfully bootstrap a cluster, the IP addresses of all the members are known. Technically, you should not need the discovery service any more.
Discovery service is designed for bootstrapping an etcd cluster in the cloud environment, when the IP addresses of all the members are not known beforehand. After successfully bootstrapping a cluster, the IP addresses of all the members are known. Technically, the discovery service should no longer be needed.
It seems that using public discovery service is a convenient way to do runtime reconfiguration, after all discovery service already has all the cluster configuration information. However relying on public discovery service brings troubles:
1. it introduces external dependencies for the entire life-cycle of your cluster, not just bootstrap time. If there is a network issue between your cluster and public discovery service, your cluster will suffer from it.
1. it introduces external dependencies for the entire life-cycle of the cluster, not just bootstrap time. If there is a network issue between the cluster and public discovery service, the cluster will suffer from it.
2. public discovery service must reflect correct runtime configuration of your cluster during it life-cycle. It has to provide security mechanism to avoid bad actions, and it is hard.
2. public discovery service must reflect correct runtime configuration of the cluster during it life-cycle. It has to provide security mechanism to avoid bad actions, and it is hard.
3. public discovery service has to keep tens of thousands of cluster configurations. Our public discovery service backend is not ready for that workload.
If you want to have a discovery service that supports runtime reconfiguration, the best choice is to build your private one.
To have a discovery service that supports runtime reconfiguration, the best choice is to build a private one.
[add-member]: runtime-configuration.md#add-a-new-member
[disaster-recovery]: recovery.md

View File

@ -1,10 +1,10 @@
# Security Model
# Security model
etcd supports SSL/TLS as well as authentication through client certificates, both for clients to server as well as peer (server to server / cluster) communication.
etcd supports automatic TLS as well as authentication through client certificates for both clients to server as well as peer (server to server / cluster) communication.
To get up and running you first need to have a CA certificate and a signed key pair for one member. It is recommended to create and sign a new key pair for every member in a cluster.
To get up and running, first have a CA certificate and a signed key pair for one member. It is recommended to create and sign a new key pair for every member in a cluster.
For convenience, the [cfssl] tool provides an easy interface to certificate generation, and we provide an example using the tool [here][tls-setup]. You can also examine this [alternative guide to generating self-signed key pairs][tls-guide].
For convenience, the [cfssl] tool provides an easy interface to certificate generation, and we provide an example using the tool [here][tls-setup]. Alternatively, try this [guide to generating self-signed key pairs][tls-guide].
## Basic setup
@ -12,7 +12,7 @@ etcd takes several certificate related configuration options, either through com
**Client-to-server communication:**
`--cert-file=<path>`: Certificate used for SSL/TLS connections **to** etcd. When this option is set, you can set advertise-client-urls using HTTPS schema.
`--cert-file=<path>`: Certificate used for SSL/TLS connections **to** etcd. When this option is set, advertise-client-urls can use the HTTPS schema.
`--key-file=<path>`: Key for the certificate. Must be unencrypted.
@ -20,6 +20,8 @@ etcd takes several certificate related configuration options, either through com
`--trusted-ca-file=<path>`: Trusted certificate authority.
`--auto-tls`: Use automatically generated self-signed certificates for TLS connections with clients.
**Peer (server-to-server / cluster) communication:**
The peer options work the same way as the client-to-server options:
@ -32,11 +34,13 @@ The peer options work the same way as the client-to-server options:
`--peer-trusted-ca-file=<path>`: Trusted certificate authority.
`--peer-auto-tls`: Use automatically generated self-signed certificates for TLS connections between peers.
If either a client-to-server or peer certificate is supplied the key must also be set. All of these configuration options are also available through the environment variables, `ETCD_CA_FILE`, `ETCD_PEER_CA_FILE` and so on.
## Example 1: Client-to-server transport security with HTTPS
For this you need your CA certificate (`ca.crt`) and signed key pair (`server.crt`, `server.key`) ready.
For this, have a CA certificate (`ca.crt`) and signed key pair (`server.crt`, `server.key`) ready.
Let us configure etcd to provide simple HTTPS transport security step by step:
@ -46,19 +50,19 @@ $ etcd --name infra0 --data-dir infra0 \
--advertise-client-urls=https://127.0.0.1:2379 --listen-client-urls=https://127.0.0.1:2379
```
This should start up fine and you can now test the configuration by speaking HTTPS to etcd:
This should start up fine and it will be possible to test the configuration by speaking HTTPS to etcd:
```sh
$ curl --cacert /path/to/ca.crt https://127.0.0.1:2379/v2/keys/foo -XPUT -d value=bar -v
```
You should be able to see the handshake succeed. Because we use self-signed certificates with our own certificate authorities you need to provide the CA to curl using the `--cacert` option. Another possibility would be to add your CA certificate to the trusted certificates on your system (usually in `/etc/ssl/certs`).
The command should show that the handshake succeed. Since we use self-signed certificates with our own certificate authority, the CA must be passed to curl using the `--cacert` option. Another possibility would be to add the CA certificate to the system's trusted certificates directory (usually in `/etc/pki/tls/certs` or `/etc/ssl/certs`).
**OSX 10.9+ Users**: curl 7.30.0 on OSX 10.9+ doesn't understand certificates passed in on the command line.
Instead you must import the dummy ca.crt directly into the keychain or add the `-k` flag to curl to ignore errors.
If you want to test without the `-k` flag run `open ./fixtures/ca/ca.crt` and follow the prompts.
Please remove this certificate after you are done testing!
If you know of a workaround let us know.
Instead, import the dummy ca.crt directly into the keychain or add the `-k` flag to curl to ignore errors.
To test without the `-k` flag, run `open ./fixtures/ca/ca.crt` and follow the prompts.
Please remove this certificate after testing!
If there is a workaround, let us know.
## Example 2: Client-to-server authentication with HTTPS client certificates
@ -66,7 +70,7 @@ For now we've given the etcd client the ability to verify the server identity an
The clients will provide their certificates to the server and the server will check whether the cert is signed by the supplied CA and decide whether to serve the request.
You need the same files mentioned in the first example for this, as well as a key pair for the client (`client.crt`, `client.key`) signed by the same certificate authority.
The same files mentioned in the first example are needed for this, as well as a key pair for the client (`client.crt`, `client.key`) signed by the same certificate authority.
```sh
$ etcd --name infra0 --data-dir infra0 \
@ -95,7 +99,7 @@ $ curl --cacert /path/to/ca.crt --cert /path/to/client.crt --key /path/to/client
-L https://127.0.0.1:2379/v2/keys/foo -XPUT -d value=bar -v
```
You should be able to see:
The output should include:
```
...
@ -141,9 +145,43 @@ $ etcd --name infra2 --data-dir infra2 \
--discovery ${DISCOVERY_URL}
```
The etcd members will form a cluster and all communication between members in the cluster will be encrypted and authenticated using the client certificates. You will see in the output of etcd that the addresses it connects to use HTTPS.
The etcd members will form a cluster and all communication between members in the cluster will be encrypted and authenticated using the client certificates. The output of etcd will show that the addresses it connects to use HTTPS.
## Notes For etcd Proxy
## Example 4: Automatic self-signed transport security
For cases where communication encryption, but not authentication, is needed, etcd supports encrypting its messages with automatically generated self-signed certificates. This simplifies deployment because there is no need for managing certificates and keys outside of etcd.
Configure etcd to use self-signed certificates for client and peer connections with the flags `--auto-tls` and `--peer-auto-tls`:
```sh
DISCOVERY_URL=... # from https://discovery.etcd.io/new
# member1
$ etcd --name infra1 --data-dir infra1 \
--auto-tls --peer-auto-tls \
--initial-advertise-peer-urls=https://10.0.1.10:2380 --listen-peer-urls=https://10.0.1.10:2380 \
--discovery ${DISCOVERY_URL}
# member2
$ etcd --name infra2 --data-dir infra2 \
--auto-tls --peer-auto-tls \
--initial-advertise-peer-urls=https://10.0.1.11:2380 --listen-peer-urls=https://10.0.1.11:2380 \
--discovery ${DISCOVERY_URL}
```
Self-signed certificates do not authenticate identity so curl will return an error:
```sh
curl: (60) SSL certificate problem: Invalid certificate chain
```
To disable certificate chain checking, invoke curl with the `-k` flag:
```sh
$ curl -k https://127.0.0.1:2379/v2/keys/foo -Xput -d value=bar -v
```
## Notes for etcd proxy
etcd proxy terminates the TLS from its client if the connection is secure, and uses proxy's own key/cert specified in `--peer-key-file` and `--peer-cert-file` to communicate with etcd members.
@ -151,23 +189,16 @@ The proxy communicates with etcd members through both the `--advertise-client-ur
When client authentication is enabled for an etcd member, the administrator must ensure that the peer certificate specified in the proxy's `--peer-cert-file` option is valid for that authentication. The proxy's peer certificate must also be valid for peer authentication if peer authentication is enabled.
## Frequently Asked Questions
## Frequently asked questions
### My cluster is not working with peer tls configuration?
The internal protocol of etcd v2.0.x uses a lot of short-lived HTTP connections.
So, when enabling TLS you may need to increase the heartbeat interval and election timeouts to reduce internal cluster connection churn.
A reasonable place to start are these values: ` --heartbeat-interval 500 --election-timeout 2500`.
These issues are resolved in the etcd v2.1.x series of releases which uses fewer connections.
### I'm seeing a SSLv3 alert handshake failure when using SSL client authentication?
### I'm seeing a SSLv3 alert handshake failure when using TLS client authentication?
The `crypto/tls` package of `golang` checks the key usage of the certificate public key before using it.
To use the certificate public key to do client auth, we need to add `clientAuth` to `Extended Key Usage` when creating the certificate public key.
Here is how to do it:
Add the following section to your openssl.cnf:
Add the following section to openssl.cnf:
```
[ ssl_client ]
@ -183,9 +214,9 @@ $ openssl ca -config openssl.cnf -policy policy_anything -extensions ssl_client
```
### With peer certificate authentication I receive "certificate is valid for 127.0.0.1, not $MY_IP"
Make sure that you sign your certificates with a Subject Name your member's public IP address. The `etcd-ca` tool for example provides an `--ip=` option for its `new-cert` command.
Make sure to sign the certificates with a Subject Name the member's public IP address. The `etcd-ca` tool for example provides an `--ip=` option for its `new-cert` command.
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.
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

View File

@ -0,0 +1,14 @@
## Supported platform
### 32-bit and other unsupported systems
etcd has known issues on 32-bit systems due to a bug in the Go runtime. See #[358][358] for more information.
To avoid inadvertently running a possibly unstable etcd server, `etcd` on 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`.
[358]: https://github.com/coreos/etcd/issues/358

View File

@ -0,0 +1,47 @@
# Migrate applications from using API v2 to API v3
The data store v2 is still accessible from the API v2 after upgrading to etcd3. Thus, it will work as before and require no application changes. With etcd 3, applications use the new grpc API v3 to access the mvcc store, which provides more features and improved performance. The mvcc store and the old store v2 are separate and isolated; writes to the store v2 will not affect the mvcc store and, similarly, writes to the mvcc store will not affect the store v2.
Migrating an application from the API v2 to the API v3 involves two steps: 1) migrate the client library and, 2) migrate the data. If the application can rebuild the data, then migrating the data is unnecessary.
## Migrate client library
API v3 is different from API v2, thus application developers need to use a new client library to send requests to etcd API v3. The documentation of the client v3 is available at https://godoc.org/github.com/coreos/etcd/clientv3.
There are some notable differences between API v2 and API v3:
- Transaction: In v3, etcd provides multi-key conditional transactions. Applications should use transactions in place of `Compare-And-Swap` operations.
- Flat key space: There are no directories in API v3, only keys. For example, "/a/b/c/" is a key. Range queries support getting all keys matching a given prefix.
- Compacted responses: Operations like `Delete` no longer return previous values. To get the deleted value, a transaction can be used to atomically get the key and then delete its value.
- Leases: A replacement for v2 TTLs; the TTL is bound to a lease and keys attach to the lease. When the TTL expires, the lease is revoked and all attached keys are removed.
## Migrate data
Application data can be migrated either offline or online. Offline migration is much simpler than online migration and is recommended.
### 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.
First, all members in the etcd cluster must converge to the same state. This can be achieved by stopping all applications that write keys to etcd. Alternatively, if the applications must remain running, configure etcd to listen on a different client URL and restart all etcd members. To check if the states converged, within a few seconds, use the `ETCDCTL_API=3 etcdctl endpoint status` command to confirm that the `raft index` of all members match (or differ by at most 1 due to an internal sync raft command).
Second, migrate the v2 keys into v3 with the [migrate][migrate_command] (`ETCDCTL_API=3 etcdctl migrate`) command. The migrate command writes keys in the v2 store to a user-provided transformer program and reads back transformed keys. It then writes transformed keys into the mvcc store. This usually takes at most tens of seconds.
Restart the etcd members and everything should just work.
### Online migration
If the application cannot tolerate any downtime, then it must migrate online. The implementation of online migration will vary from application to application but the overall idea is the same.
First, write application code using the v3 API. The application must support two modes: a migration mode and a normal mode. The application starts in migration mode. When running in migration mode, the application reads keys using the v3 API first, and, if it cannot find the key, it retries with the API v2. In normal mode, the application only reads keys using the v3 API. The application writes keys over the API v3 in both modes. To acknowledge a switch from migration mode to normal mode, the application watches on a switch mode key. When switch keys value turns to `true`, the application switches over from migration mode to normal mode.
Second, start a background job to migrate data from the store v2 to the mvcc store by reading keys from the API v2 and writing keys to the API v3.
After finishing data migration, the background job writes `true` into the switch mode key to notify the application that it may switch modes.
Online migration can be difficult when the application logic depends on store v2 indexes. Applications will need additional logic to convert mvcc store revisions to store v2 indexes.
[migrate_command]: ../../etcdctl/README.md#migrate-options

View File

@ -0,0 +1,17 @@
## Versioning
### Service versioning
etcd uses [semantic versioning](http://semver.org)
New minor versions may add additional features to the API.
Get the running etcd cluster version with `etcdctl`:
```sh
ETCDCTL_API=3 etcdctl --endpoints=127.0.0.1:2379 endpoint status
```
### API versioning
The `v3` API responses should not change after the 3.0.0 release but new features will be added over time.

View File

@ -1,6 +1,6 @@
# Production Users
# Production users
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 your experience and update this list.
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.
## discovery.etcd.io

View File

@ -1,24 +1,24 @@
# Reporting Bugs
# 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 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.
To make your bug report accurate and easy to understand, please try to create bug reports that are:
To make the bug report accurate and easy to understand, please try to create bug reports that are:
- Specific. Include as much details as possible: which version, what environment, what configuration, etc. You can also attach etcd log (the starting log with etcd configuration is especially important).
- Specific. Include as much details as possible: which version, what environment, what configuration, etc. If the bug is related to running the etcd server, please attach the etcd log (the starting log with etcd configuration is especially important).
- Reproducible. Include the steps to reproduce the problem. We understand some issues might be hard to reproduce, please includes the steps that might lead to the problem. You can also attach the affected etcd data dir and stack strace to the bug report.
- Reproducible. Include the steps to reproduce the problem. We understand some issues might be hard to reproduce, please includes the steps that might lead to the problem. If possible, please attach the affected etcd data dir and stack strace to the bug report.
- Isolated. Please try to isolate and reproduce the bug with minimum dependencies. It would significantly slow down the speed to fix a bug if too many dependencies are involved in a bug report. Debugging external systems that rely on etcd is out of scope, but we are happy to point you in the right direction or help you interact with etcd in the correct manner.
- Isolated. Please try to isolate and reproduce the bug with minimum dependencies. It would significantly slow down the speed to fix a bug if too many dependencies are involved in a bug report. Debugging external systems that rely on etcd is out of scope, but we are happy to provide guidance in the right direction or help with using etcd itself.
- Unique. Do not duplicate existing bug report.
- Scoped. One bug per report. Do not follow up with another bug inside one report.
You might also want to read [Elika Etemads article on filing good bug reports][filing-good-bugs] before creating a bug report.
It may be worthwhile to read [Elika Etemads article on filing good bug reports][filing-good-bugs] before creating a bug report.
We might ask you for further information to locate a bug. A duplicated bug report will be closed.
We might ask for further information to locate a bug. A duplicated bug report will be closed.
## Frequently Asked Questions
## Frequently asked questions
### How to get a stack trace
@ -39,7 +39,7 @@ $ sudo systemctl cat etcd2
$ sudo journalctl -u etcd2
```
Due to an upstream systemd bug, journald may miss the last few log lines when its process exit. If journalctl tells you that etcd stops without fatal or panic message, you could try `sudo journalctl -f -t etcd2` to get full log.
Due to an upstream systemd bug, journald may miss the last few log lines when its processes exit. If journalctl says etcd stopped without fatal or panic message, try `sudo journalctl -f -t etcd2` to get full log.
[etcd-issue]: https://github.com/coreos/etcd/issues/new
[filing-good-bugs]: http://fantasai.inkedblade.net/style/talks/filing-good-bugs/

View File

@ -1,11 +1,10 @@
# Tuning
The default settings in etcd should work well for installations on a local network where the average network latency is low.
However, when using etcd across multiple data centers or over networks with high latency you may need to tweak the heartbeat interval and election timeout settings.
The default settings in etcd should work well for installations on a local network where the average network latency is low. However, when using etcd across multiple data centers or over networks with high latency, the heartbeat interval and election timeout settings may need tuning.
The network isn't the only source of latency. Each request and response may be impacted by slow disks on both the leader and follower. Each of these timeouts represents the total time from request to successful response from the other machine.
## Time Parameters
## 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*.
@ -24,20 +23,20 @@ On the other side, a too high heartbeat interval leads to high election timeout.
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 your network.
For example, if the round-trip time between your members is 10ms then you should have at least a 100ms election timeout.
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.
You should also set your election timeout to at least 5 to 10 times your heartbeat interval to account for variance in leader replication.
For a heartbeat interval of 50ms you should set your election timeout to at least 250ms - 500ms.
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 your 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.
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.
You can override the default values on the command line:
The default values can be overridden on the command line:
```sh
# Command line arguments:
@ -58,11 +57,11 @@ A complete history works well for lightly used clusters but clusters that are he
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
### 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, you can lower the snapshot threshold by setting the following on the command line:
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:

View File

@ -0,0 +1,119 @@
## Upgrade etcd from 2.3 to 3.0
In the general case, upgrading from etcd 2.3 to 3.0 can be a zero-downtime, rolling upgrade:
- one by one, stop the etcd v2.3 processes and replace them with etcd v3.0 processes
- after running all v3.0 processes, new features in v3.0 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.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.
#### 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.
#### 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.
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.
#### Downgrade
If all members have been upgraded to v3.0, the cluster will be upgraded to v3.0, and downgrade from this completed state is **not possible**. If any single member is still v2.3, however, the cluster and its operations remains “v2.3”, and it is possible from this mixed cluster state to return to using a v2.3 etcd binary on all members.
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
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?
```
$ etcdctl cluster-health
member 6e3bd23ae5f1eae0 is healthy: got healthy result from http://localhost:22379
member 924e2e83e93f2560 is healthy: got healthy result from http://localhost:32379
member 8211f1d0f64f3269 is healthy: got healthy result from http://localhost:12379
cluster is healthy
$ curl http://localhost:2379/version
{"etcdserver":"2.3.x","etcdcluster":"2.3.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:
```
2016-06-27 15:21:48.624124 E | rafthttp: failed to dial 8211f1d0f64f3269 on stream Message (dial tcp 127.0.0.1:12380: getsockopt: connection refused)
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:
```
$ etcdctl backup \
--data-dir /var/lib/etcd \
--backup-dir /tmp/etcd_backup
```
#### 3. Drop-in etcd v3.0 binary and start the new etcd process
The new v3.0 etcd will publish its information to the cluster:
```
09:58:25.938673 I | etcdserver: published {Name:infra1 ClientURLs:[http://localhost:12379]} to cluster 524400597fb1d5f6
```
Verify that each member, and then the entire cluster, becomes healthy with the new v3.0 etcd binary:
```
$ etcdctl cluster-health
member 6e3bd23ae5f1eae0 is healthy: got healthy result from http://localhost:22379
member 924e2e83e93f2560 is healthy: got healthy result from http://localhost:32379
member 8211f1d0f64f3269 is healthy: got healthy result from http://localhost:12379
cluster is healthy
```
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.0:
```
2016-06-27 15:22:05.679644 W | etcdserver: the local etcd version 2.3.7 is not up-to-date
2016-06-27 15:22:05.679660 W | etcdserver: member 8211f1d0f64f3269 has a higher version 3.0.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.0 successfully:
```
2016-06-27 15:22:19.873751 N | membership: updated the cluster version from 2.3 to 3.0
2016-06-27 15:22:19.914574 I | api: enabled capabilities for version 3.0.0
```
```
$ ETCDCTL_API=3 etcdctl endpoint health
127.0.0.1:12379 is healthy: successfully committed proposal: took = 18.440155ms
127.0.0.1:32379 is healthy: successfully committed proposal: took = 13.651368ms
127.0.0.1:22379 is healthy: successfully committed proposal: took = 18.513301ms
```
[etcd-contact]: https://groups.google.com/forum/#!forum/etcd-dev

View File

@ -118,6 +118,17 @@ See [CONTRIBUTING](../../CONTRIBUTING.md) for details on submitting patches and
See [reporting bugs](reporting_bugs.md) for details about reporting any issue you may encounter.
## Known bugs
[GH518](https://github.com/coreos/etcd/issues/518) is a known bug. Issue is that:
```
curl http://127.0.0.1:2379/v2/keys/foo -XPUT -d value=bar
curl http://127.0.0.1:2379/v2/keys/foo -XPUT -d dir=true -d prevExist=true
```
If the previous node is a key and client tries to overwrite it with `dir=true`, it does not give warnings such as `Not a directory`. Instead, the key is set to empty value.
## Project Details
### Versioning
@ -141,7 +152,7 @@ The `v2` API responses should not change after the 2.0.0 release but new feature
etcd has known issues on 32-bit systems due to a bug in the Go runtime. See #[358][358] for more information.
To avoid inadvertantly running a possibly unstable etcd server, `etcd` on unsupported architectures will print
To avoid inadvertently running a possibly unstable etcd server, `etcd` on unsupported architectures will print
a warning message and immediately exit if the environment variable `ETCD_UNSUPPORTED_ARCH` is not set to
the target architecture.

View File

@ -113,7 +113,8 @@ It is recommended to have an odd number of members in a cluster. Having an odd c
| Cluster Size | Majority | Failure Tolerance |
|--------------|------------|-------------------|
| 1 | 1 | 0 |
| 3 | 2 | 1 |
| 2 | 2 | 0 |
| 3 | 2 | **1** |
| 4 | 3 | 1 |
| 5 | 3 | **2** |
| 6 | 4 | 2 |
@ -135,7 +136,7 @@ The data directory contains all the data to recover a member to its point-in-tim
* Stop the member process.
* Copy the data directory of the now-idle member to the new machine.
* Update the peer URLs for the replaced member to reflect the new machine according to the [runtime reconfiguration instructions][update-member].
* Update the peer URLs for the replaced member to reflect the new machine according to the [runtime reconfiguration instructions][update-a-member].
* Start etcd on the new machine, using the same configuration and the copy of the data directory.
This example will walk you through the process of migrating the infra1 member to a new machine:
@ -217,12 +218,14 @@ To recover from such scenarios, etcd provides functionality to backup and restor
**NB:** Windows users must stop etcd before running the backup command.
The first step of the recovery is to backup the data directory on a functioning etcd node. To do this, use the `etcdctl backup` command, passing in the original data directory used by etcd. For example:
The first step of the recovery is to backup the data directory and wal directory, if stored separately, on a functioning etcd node. To do this, use the `etcdctl backup` command, passing in the original data (and wal) directory used by etcd. For example:
```sh
etcdctl backup \
--data-dir %data_dir% \
[--wal-dir %wal_dir%] \
--backup-dir %backup_data_dir%
[--backup-wal-dir %backup_wal_dir%]
```
This command will rewrite some of the metadata contained in the backup (specifically, the node ID and cluster ID), which means that the node will lose its former identity. In order to recreate a cluster from the backup, you will need to start a new, single-node cluster. The metadata is rewritten to prevent the new node from inadvertently being joined onto an existing cluster.
@ -234,26 +237,30 @@ To restore a backup using the procedure created above, start etcd with the `-for
```sh
etcd \
-data-dir=%backup_data_dir% \
[-wal-dir=%backup_wal_dir%] \
-force-new-cluster \
...
```
Now etcd should be available on this node and serving the original datastore.
Once you have verified that etcd has started successfully, shut it down and move the data back to the previous location (you may wish to make another copy as well to be safe):
Once you have verified that etcd has started successfully, shut it down and move the data and wal, if stored separately, back to the previous location (you may wish to make another copy as well to be safe):
```sh
pkill etcd
rm -fr %data_dir%
rm -fr %wal_dir%
mv %backup_data_dir% %data_dir%
mv %backup_wal_dir% %wal_dir%
etcd \
-data-dir=%data_dir% \
[-wal-dir=%wal_dir%] \
...
```
#### Restoring the cluster
Now that the node is running successfully, [change its advertised peer URLs][update-member], as the `--force-new-cluster` option has set the peer URL to the default listening on localhost.
Now that the node is running successfully, [change its advertised peer URLs][update-a-member], as the `--force-new-cluster` option has set the peer URL to the default listening on localhost.
You can then add more nodes to the cluster and restore resiliency. See the [add a new member][add-a-member] guide for more details. **NB:** If you are trying to restore your cluster using old failed etcd nodes, please make sure you have stopped old etcd instances and removed their old data directories specified by the data-dir configuration parameter.

View File

@ -233,10 +233,11 @@ curl http://127.0.0.1:2379/v2/keys/foo -XPUT -d value=bar -d ttl= -d prevExist=t
### Refreshing key TTL
Keys in etcd can be refreshed without notifying watchers
this can be achieved by setting the refresh to true when updating a TTL
Keys in etcd can be refreshed without notifying current watchers.
You cannot update the value of a key when refreshing it
This can be achieved by setting the refresh to true when updating a TTL.
You cannot update the value of a key when refreshing it.
```sh
curl http://127.0.0.1:2379/v2/keys/foo -XPUT -d value=bar -d ttl=5

View File

@ -145,8 +145,8 @@ GET/HEAD /v2/auth/users
"role": "root",
"permissions": {
"kv": {
"read": ["*"],
"write": ["*"]
"read": ["/*"],
"write": ["/*"]
}
}
}
@ -159,8 +159,8 @@ GET/HEAD /v2/auth/users
"role": "guest",
"permissions": {
"kv": {
"read": ["*"],
"write": ["*"]
"read": ["/*"],
"write": ["/*"]
}
}
}
@ -198,8 +198,8 @@ GET/HEAD /v2/auth/users/alice
"role": "etcd",
"permissions" : {
"kv" : {
"read": [ "*" ],
"write": [ "*" ]
"read": [ "/*" ],
"write": [ "/*" ]
}
}
}
@ -311,8 +311,8 @@ GET/HEAD /v2/auth/roles
"role": "etcd",
"permissions": {
"kv": {
"read": ["*"],
"write": ["*"]
"read": ["/*"],
"write": ["/*"]
}
}
},
@ -320,8 +320,8 @@ GET/HEAD /v2/auth/roles
"role": "quay",
"permissions": {
"kv": {
"read": ["*"],
"write": ["*"]
"read": ["/*"],
"write": ["/*"]
}
}
}
@ -393,7 +393,7 @@ PUT /v2/auth/roles/guest
"revoke" : {
"kv" : {
"write": [
"*"
"/*"
]
}
}

View File

@ -309,6 +309,7 @@ infra0.example.com. 300 IN A 10.0.1.10
infra1.example.com. 300 IN A 10.0.1.11
infra2.example.com. 300 IN A 10.0.1.12
```
#### Bootstrap the etcd cluster using DNS
etcd cluster members can listen on domain names or IP address, the bootstrap process will resolve DNS A records.

View File

@ -49,7 +49,7 @@ To start a proxy that will connect to a statically defined etcd cluster, specify
```
etcd --proxy on \
--listen-client-urls http://127.0.0.1:8080 \
--listen-client-urls http://127.0.0.1:2379 \
--initial-cluster infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380
```
@ -60,7 +60,7 @@ To start a proxy using the discovery service, specify the `discovery` flag. The
```
etcd --proxy on \
--listen-client-urls http://127.0.0.1:8080 \
--listen-client-urls http://127.0.0.1:2379 \
--discovery https://discovery.etcd.io/3e86b59982e49066c5d813af1c2e2579cbf573de \
```

View File

@ -1,6 +1,7 @@
Anthony Romano <anthony.romano@coreos.com > (@heyitsanthony) pkg:*
Anthony Romano <anthony.romano@coreos.com> (@heyitsanthony) pkg:*
Brandon Philips <brandon.philips@coreos.com> (@philips) pkg:*
Gyu-Ho Lee <gyu_ho.lee@coreos.com> (@gyuho) pkg:*
Xiang Li <xiang.li@coreos.com> (@xiang90) pkg:*
Ben Darnell <ben@cockroachlabs.com> (@bdarnell) pkg:github.com/coreos/etcd/raft
Hitoshi Mitake <mitake.hitoshi@lab.ntt.co.jp> (@mitake) pkg:github.com/coreos/etcd/auth

View File

@ -1,5 +1,6 @@
# Use goreman to run `go get github.com/mattn/goreman`
etcd1: bin/etcd --name infra1 --listen-client-urls http://127.0.0.1:12379 --advertise-client-urls http://127.0.0.1:12379 --listen-peer-urls http://127.0.0.1:12380 --initial-advertise-peer-urls http://127.0.0.1:12380 --initial-cluster-token etcd-cluster-1 --initial-cluster 'infra1=http://127.0.0.1:12380,infra2=http://127.0.0.1:22380,infra3=http://127.0.0.1:32380' --initial-cluster-state new --enable-pprof
etcd1: bin/etcd --name infra1 --listen-client-urls http://127.0.0.1:2379 --advertise-client-urls http://127.0.0.1:2379 --listen-peer-urls http://127.0.0.1:12380 --initial-advertise-peer-urls http://127.0.0.1:12380 --initial-cluster-token etcd-cluster-1 --initial-cluster 'infra1=http://127.0.0.1:12380,infra2=http://127.0.0.1:22380,infra3=http://127.0.0.1:32380' --initial-cluster-state new --enable-pprof
etcd2: bin/etcd --name infra2 --listen-client-urls http://127.0.0.1:22379 --advertise-client-urls http://127.0.0.1:22379 --listen-peer-urls http://127.0.0.1:22380 --initial-advertise-peer-urls http://127.0.0.1:22380 --initial-cluster-token etcd-cluster-1 --initial-cluster 'infra1=http://127.0.0.1:12380,infra2=http://127.0.0.1:22380,infra3=http://127.0.0.1:32380' --initial-cluster-state new --enable-pprof
etcd3: bin/etcd --name infra3 --listen-client-urls http://127.0.0.1:32379 --advertise-client-urls http://127.0.0.1:32379 --listen-peer-urls http://127.0.0.1:32380 --initial-advertise-peer-urls http://127.0.0.1:32380 --initial-cluster-token etcd-cluster-1 --initial-cluster 'infra1=http://127.0.0.1:12380,infra2=http://127.0.0.1:22380,infra3=http://127.0.0.1:32380' --initial-cluster-state new --enable-pprof
proxy: bin/etcd --name infra-proxy1 --proxy=on --listen-client-urls http://127.0.0.1:2379 --initial-cluster 'infra1=http://127.0.0.1:12380,infra2=http://127.0.0.1:22380,infra3=http://127.0.0.1:32380' --enable-pprof
# in future, use proxy to listen on 2379
#proxy: bin/etcd --name infra-proxy1 --proxy=on --listen-client-urls http://127.0.0.1:2378 --initial-cluster 'infra1=http://127.0.0.1:12380,infra2=http://127.0.0.1:22380,infra3=http://127.0.0.1:32380' --enable-pprof

View File

@ -14,22 +14,24 @@
etcd is a distributed, consistent key-value store for shared configuration and service discovery, with a focus on being:
* *Simple*: well-defined, user-facing API (gRPC)
* *Secure*: optional SSL client cert authentication
* *Fast*: benchmarked 1000s of writes/s per instance
* *Secure*: automatic TLS with optional client cert authentication
* *Fast*: benchmarked 10,000 writes/sec
* *Reliable*: properly distributed using Raft
etcd is written in Go and uses the [Raft][raft] consensus algorithm to manage a highly-available replicated log.
etcd is used [in production by many companies](./Documentation/production-users.md), and the development team stands behind it in critical deployment scenarios, where etcd is frequently teamed with applications such as [Kubernetes][k8s], [fleet][fleet], [locksmith][locksmith], [vulcand][vulcand], and many others.
etcd is used [in production by many companies](./Documentation/production-users.md), and the development team stands behind it in critical deployment scenarios, where etcd is frequently teamed with applications such as [Kubernetes][k8s], [fleet][fleet], [locksmith][locksmith], [vulcand][vulcand], [Doorman][doorman], and many others. Reliability is further ensured by rigorous [testing][etcd-tests].
See [etcdctl][etcdctl] for a simple command line client.
[raft]: https://raft.github.io/
[k8s]: http://kubernetes.io/
[doorman]: https://github.com/youtube/doorman
[fleet]: https://github.com/coreos/fleet
[locksmith]: https://github.com/coreos/locksmith
[vulcand]: https://github.com/vulcand/vulcand
[etcdctl]: https://github.com/coreos/etcd/tree/master/etcdctl
[etcd-tests]: http://dash.etcd.io
## Getting started
@ -38,7 +40,7 @@ See [etcdctl][etcdctl] for a simple command line client.
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].
For those wanting to try the very latest version, you can build the latest version of etcd from the `master` branch.
You will first need [*Go*](https://golang.org/) installed on your machine (version 1.5+ is required).
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.
@ -62,7 +64,13 @@ ETCDCTL_API=3 etcdctl put mykey "this is awesome"
ETCDCTL_API=3 etcdctl get mykey
```
That's it-- etcd is running and serving keys.
That's it! etcd is now running and serving client requests. For more
- [Animated quick demo][demo-gif]
- [Interactive etcd playground][etcd-play]
[demo-gif]: ./Documentation/demo.md
[etcd-play]: http://play.etcd.io/
### etcd TCP ports
@ -99,7 +107,7 @@ Now it's time to dig into the full etcd API and other guides.
[fulldoc]: ./Documentation/docs.md
[api]: ./Documentation/dev-guide/api_reference_v3.md
[clustering]: ./Documentation/op-guide/clustering.md
[configuration]: op-guide/configuration.md
[configuration]: ./Documentation/op-guide/configuration.md
[libraries-and-tools]: ./Documentation/libraries-and-tools.md
[security]: ./Documentation/op-guide/security.md
[tuning]: ./Documentation/tuning.md
@ -119,37 +127,7 @@ See [CONTRIBUTING](CONTRIBUTING.md) for details on submitting patches and the co
See [reporting bugs](Documentation/reporting_bugs.md) for details about reporting any issue you may encounter.
## Project details
### Versioning
#### Service versioning
etcd uses [semantic versioning](http://semver.org)
New minor versions may add additional features to the API.
Get the running etcd cluster version with `etcdctl`:
```sh
ETCDCTL_API=3 etcdctl --endpoints=127.0.0.1:2379 endpoint status
```
#### API versioning
The `v3` API responses should not change after the 3.0.0 release but new features will be added over time.
#### 32-bit and other unsupported systems
etcd has known issues on 32-bit systems due to a bug in the Go runtime. See #[358][358] for more information.
To avoid inadvertantly running a possibly unstable etcd server, `etcd` on 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`.
[358]: https://github.com/coreos/etcd/issues/358
### License
etcd is under the Apache 2.0 license. See the [LICENSE](LICENSE) file for details.

View File

@ -1,6 +1,5 @@
# Use goreman to run `go get github.com/mattn/goreman`
etcd1: bin/etcd --name infra1 --listen-client-urls http://127.0.0.1:2379 --advertise-client-urls http://127.0.0.1:2379 --listen-peer-urls http://127.0.0.1:12380 --initial-advertise-peer-urls http://127.0.0.1:12380 --initial-cluster-token etcd-cluster-1 --initial-cluster 'infra1=http://127.0.0.1:12380,infra2=http://127.0.0.1:22380,infra3=http://127.0.0.1:32380' --initial-cluster-state new --enable-pprof
etcd1: bin/etcd --name infra1 --listen-client-urls http://127.0.0.1:12379 --advertise-client-urls http://127.0.0.1:12379 --listen-peer-urls http://127.0.0.1:12380 --initial-advertise-peer-urls http://127.0.0.1:12380 --initial-cluster-token etcd-cluster-1 --initial-cluster 'infra1=http://127.0.0.1:12380,infra2=http://127.0.0.1:22380,infra3=http://127.0.0.1:32380' --initial-cluster-state new --enable-pprof
etcd2: bin/etcd --name infra2 --listen-client-urls http://127.0.0.1:22379 --advertise-client-urls http://127.0.0.1:22379 --listen-peer-urls http://127.0.0.1:22380 --initial-advertise-peer-urls http://127.0.0.1:22380 --initial-cluster-token etcd-cluster-1 --initial-cluster 'infra1=http://127.0.0.1:12380,infra2=http://127.0.0.1:22380,infra3=http://127.0.0.1:32380' --initial-cluster-state new --enable-pprof
etcd3: bin/etcd --name infra3 --listen-client-urls http://127.0.0.1:32379 --advertise-client-urls http://127.0.0.1:32379 --listen-peer-urls http://127.0.0.1:32380 --initial-advertise-peer-urls http://127.0.0.1:32380 --initial-cluster-token etcd-cluster-1 --initial-cluster 'infra1=http://127.0.0.1:12380,infra2=http://127.0.0.1:22380,infra3=http://127.0.0.1:32380' --initial-cluster-state new --enable-pprof
# in future, use proxy to listen on 2379
#proxy: bin/etcd --name infra-proxy1 --proxy=on --listen-client-urls http://127.0.0.1:2378 --initial-cluster 'infra1=http://127.0.0.1:12380,infra2=http://127.0.0.1:22380,infra3=http://127.0.0.1:32380' --enable-pprof
proxy: bin/etcd --name infra-proxy1 --proxy=on --listen-client-urls http://127.0.0.1:2379 --initial-cluster 'infra1=http://127.0.0.1:12380,infra2=http://127.0.0.1:22380,infra3=http://127.0.0.1:32380' --enable-pprof

View File

@ -1,4 +1,4 @@
// Copyright 2016 CoreOS, Inc.
// Copyright 2016 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.

View File

@ -18,7 +18,7 @@ package authpb
import (
"fmt"
proto "github.com/gogo/protobuf/proto"
proto "github.com/golang/protobuf/proto"
math "math"
)
@ -32,7 +32,7 @@ var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
const _ = proto.GoGoProtoPackageIsVersion1
const _ = proto.ProtoPackageIsVersion1
type Permission_Type int32
@ -72,8 +72,9 @@ func (*User) Descriptor() ([]byte, []int) { return fileDescriptorAuth, []int{0}
// Permission is a single entity
type Permission struct {
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
PermType Permission_Type `protobuf:"varint,2,opt,name=permType,proto3,enum=authpb.Permission_Type" json:"permType,omitempty"`
PermType Permission_Type `protobuf:"varint,1,opt,name=permType,proto3,enum=authpb.Permission_Type" json:"permType,omitempty"`
Key []byte `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
RangeEnd []byte `protobuf:"bytes,3,opt,name=range_end,json=rangeEnd,proto3" json:"range_end,omitempty"`
}
func (m *Permission) Reset() { *m = Permission{} }
@ -158,16 +159,22 @@ func (m *Permission) MarshalTo(data []byte) (int, error) {
_ = i
var l int
_ = l
if m.PermType != 0 {
data[i] = 0x8
i++
i = encodeVarintAuth(data, i, uint64(m.PermType))
}
if len(m.Key) > 0 {
data[i] = 0xa
data[i] = 0x12
i++
i = encodeVarintAuth(data, i, uint64(len(m.Key)))
i += copy(data[i:], m.Key)
}
if m.PermType != 0 {
data[i] = 0x10
if len(m.RangeEnd) > 0 {
data[i] = 0x1a
i++
i = encodeVarintAuth(data, i, uint64(m.PermType))
i = encodeVarintAuth(data, i, uint64(len(m.RangeEnd)))
i += copy(data[i:], m.RangeEnd)
}
return i, nil
}
@ -258,12 +265,16 @@ func (m *User) Size() (n int) {
func (m *Permission) Size() (n int) {
var l int
_ = l
if m.PermType != 0 {
n += 1 + sovAuth(uint64(m.PermType))
}
l = len(m.Key)
if l > 0 {
n += 1 + l + sovAuth(uint64(l))
}
if m.PermType != 0 {
n += 1 + sovAuth(uint64(m.PermType))
l = len(m.RangeEnd)
if l > 0 {
n += 1 + l + sovAuth(uint64(l))
}
return n
}
@ -468,6 +479,25 @@ func (m *Permission) Unmarshal(data []byte) error {
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field PermType", wireType)
}
m.PermType = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowAuth
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
m.PermType |= (Permission_Type(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType)
}
@ -498,11 +528,11 @@ func (m *Permission) Unmarshal(data []byte) error {
m.Key = []byte{}
}
iNdEx = postIndex
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field PermType", wireType)
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field RangeEnd", wireType)
}
m.PermType = 0
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowAuth
@ -512,11 +542,23 @@ func (m *Permission) Unmarshal(data []byte) error {
}
b := data[iNdEx]
iNdEx++
m.PermType |= (Permission_Type(b) & 0x7F) << shift
byteLen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthAuth
}
postIndex := iNdEx + byteLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.RangeEnd = append(m.RangeEnd[:0], data[iNdEx:postIndex]...)
if m.RangeEnd == nil {
m.RangeEnd = []byte{}
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipAuth(data[iNdEx:])
@ -756,21 +798,23 @@ var (
)
var fileDescriptorAuth = []byte{
// 254 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0x4a, 0x2c, 0x2d, 0xc9,
0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x03, 0xb1, 0x0b, 0x92, 0xa4, 0x44, 0xd2, 0xf3,
0xd3, 0xf3, 0xc1, 0x42, 0xfa, 0x20, 0x16, 0x44, 0x56, 0xc9, 0x87, 0x8b, 0x25, 0xb4, 0x38, 0xb5,
0x48, 0x48, 0x88, 0x8b, 0x25, 0x2f, 0x31, 0x37, 0x55, 0x82, 0x51, 0x81, 0x51, 0x83, 0x27, 0x08,
0xcc, 0x16, 0x92, 0xe2, 0xe2, 0x28, 0x48, 0x2c, 0x2e, 0x2e, 0xcf, 0x2f, 0x4a, 0x91, 0x60, 0x02,
0x8b, 0xc3, 0xf9, 0x42, 0x22, 0x5c, 0xac, 0x45, 0xf9, 0x39, 0xa9, 0xc5, 0x12, 0xcc, 0x0a, 0xcc,
0x1a, 0x9c, 0x41, 0x10, 0x8e, 0x52, 0x3d, 0x17, 0x57, 0x40, 0x6a, 0x51, 0x6e, 0x66, 0x71, 0x71,
0x66, 0x7e, 0x9e, 0x90, 0x00, 0x17, 0x73, 0x76, 0x6a, 0x25, 0xd4, 0x48, 0x10, 0x53, 0xc8, 0x18,
0x68, 0x22, 0x50, 0x3e, 0xa4, 0xb2, 0x20, 0x15, 0x6c, 0x22, 0x9f, 0x91, 0xb8, 0x1e, 0xc4, 0x79,
0x7a, 0x08, 0x7d, 0x7a, 0x20, 0xe9, 0x20, 0xb8, 0x42, 0x25, 0x2d, 0x2e, 0x16, 0x10, 0x2d, 0xc4,
0xc1, 0xc5, 0x12, 0xe4, 0xea, 0xe8, 0x22, 0xc0, 0x20, 0xc4, 0xc9, 0xc5, 0x1a, 0x1e, 0xe4, 0x19,
0xe2, 0x2a, 0xc0, 0x28, 0xc4, 0xcb, 0xc5, 0x09, 0x12, 0x84, 0x70, 0x99, 0x94, 0x42, 0x80, 0x6a,
0x80, 0x2e, 0xc1, 0xea, 0x1d, 0x0b, 0x2e, 0x5e, 0xa0, 0x1b, 0x10, 0xf6, 0x00, 0x5d, 0xc0, 0xac,
0xc1, 0x6d, 0x24, 0x84, 0xe9, 0x82, 0x20, 0x54, 0x85, 0x4e, 0x22, 0x27, 0x1e, 0xca, 0x31, 0x5c,
0x00, 0xe2, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x00, 0xf1, 0x03, 0x20, 0x4e, 0x62, 0x03, 0x87, 0xa0,
0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x92, 0x06, 0xa1, 0xed, 0x6d, 0x01, 0x00, 0x00,
// 288 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 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,
0x64, 0x43, 0xdc, 0xed, 0xfb, 0xbe, 0xff, 0x97, 0xe4, 0x97, 0x3f, 0x40, 0xfe, 0xb6, 0x7e, 0x4d,
0x1a, 0x29, 0xd6, 0x02, 0x0f, 0x7b, 0xdd, 0xcc, 0x27, 0xe3, 0x52, 0x94, 0x42, 0x47, 0x57, 0xbd,
0x32, 0xd3, 0xe8, 0x01, 0xdc, 0x27, 0xc5, 0x25, 0xc6, 0xe0, 0xd6, 0x79, 0xc5, 0x09, 0x0a, 0x51,
0x7c, 0xca, 0xb4, 0xc6, 0x13, 0xf0, 0x9a, 0x5c, 0xa9, 0x77, 0x21, 0x0b, 0x62, 0xeb, 0x7c, 0xef,
0xf1, 0x18, 0x06, 0x52, 0xac, 0xb8, 0x22, 0x4e, 0xe8, 0xc4, 0x3e, 0x33, 0x26, 0xfa, 0x44, 0x00,
0x8f, 0x5c, 0x56, 0x0b, 0xa5, 0x16, 0xa2, 0xc6, 0x33, 0xf0, 0x1a, 0x2e, 0xab, 0xac, 0x6d, 0xcc,
0xc5, 0x67, 0xd3, 0xf3, 0xc4, 0xd0, 0x24, 0x87, 0x56, 0xd2, 0x8f, 0xd9, 0xbe, 0x88, 0x03, 0x70,
0x96, 0xbc, 0xfd, 0x7d, 0xb0, 0x97, 0xf8, 0x02, 0x7c, 0x99, 0xd7, 0x25, 0x7f, 0xe1, 0x75, 0x41,
0x1c, 0x03, 0xa2, 0x83, 0xb4, 0x2e, 0xa2, 0x4b, 0x70, 0xf5, 0x31, 0x0f, 0x5c, 0x96, 0xde, 0xdc,
0x05, 0x16, 0xf6, 0x61, 0xf0, 0xcc, 0xee, 0xb3, 0x34, 0x40, 0x78, 0x04, 0x7e, 0x1f, 0x1a, 0x6b,
0x47, 0x19, 0xb8, 0x4c, 0xac, 0xf8, 0xd1, 0xcf, 0x5e, 0xc3, 0x68, 0xc9, 0xdb, 0x03, 0x16, 0xb1,
0x43, 0x27, 0x3e, 0x99, 0xe2, 0xff, 0xc0, 0xec, 0x6f, 0xf1, 0x96, 0x6c, 0x76, 0xd4, 0xda, 0xee,
0xa8, 0xb5, 0xe9, 0x28, 0xda, 0x76, 0x14, 0x7d, 0x75, 0x14, 0x7d, 0x7c, 0x53, 0x6b, 0x3e, 0xd4,
0x3b, 0x9e, 0xfd, 0x04, 0x00, 0x00, 0xff, 0xff, 0xcc, 0x76, 0x8d, 0x4f, 0x8f, 0x01, 0x00, 0x00,
}

View File

@ -18,14 +18,15 @@ message User {
// Permission is a single entity
message Permission {
bytes key = 1;
enum Type {
READ = 0;
WRITE = 1;
READWRITE = 2;
}
Type permType = 2;
Type permType = 1;
bytes key = 2;
bytes range_end = 3;
}
// Role is a single entry in the bucket authRoles

16
auth/doc.go Normal file
View File

@ -0,0 +1,16 @@
// Copyright 2016 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 provides client role authentication for accessing keys in etcd.
package auth

219
auth/range_perm_cache.go Normal file
View File

@ -0,0 +1,219 @@
// Copyright 2016 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 (
"bytes"
"sort"
"github.com/coreos/etcd/auth/authpb"
"github.com/coreos/etcd/mvcc/backend"
)
// isSubset returns true if a is 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:
return 0 <= bytes.Compare(a.begin, b.begin) && bytes.Compare(a.begin, b.end) <= 0
default:
return 0 <= bytes.Compare(a.begin, b.begin) && 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.
func removeSubsetRangePerms(perms []*rangePerm) []*rangePerm {
// TODO(mitake): currently it is O(n^2), we need a better algorithm
newp := make([]*rangePerm, 0)
for i := range perms {
skip := false
for j := range perms {
if i == j {
continue
}
if isRangeEqual(perms[i], perms[j]) {
// if ranges are equal, we only keep the first range.
if i > j {
skip = true
break
}
} else if isSubset(perms[i], perms[j]) {
// if a range is a strict subset of the other one, we skip the subset.
skip = true
break
}
}
if skip {
continue
}
newp = append(newp, perms[i])
}
return newp
}
// mergeRangePerms merges adjacent rangePerms.
func mergeRangePerms(perms []*rangePerm) []*rangePerm {
merged := make([]*rangePerm, 0)
perms = removeSubsetRangePerms(perms)
sort.Sort(RangePermSliceByBegin(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) != -1 {
next++
}
merged = append(merged, &rangePerm{begin: perms[begin].begin, end: perms[next].end})
i = next + 1
}
return merged
}
func getMergedPerms(tx backend.BatchTx, userName string) *unifiedRangePermissions {
user := getUser(tx, userName)
if user == nil {
plog.Errorf("invalid user name %s", userName)
return nil
}
var readPerms, writePerms []*rangePerm
for _, roleName := range user.Roles {
role := getRole(tx, roleName)
if role == nil {
continue
}
for _, perm := range role.KeyPermission {
rp := &rangePerm{begin: perm.Key, end: perm.RangeEnd}
switch perm.PermType {
case authpb.READWRITE:
readPerms = append(readPerms, rp)
writePerms = append(writePerms, rp)
case authpb.READ:
readPerms = append(readPerms, rp)
case authpb.WRITE:
writePerms = append(writePerms, rp)
}
}
}
return &unifiedRangePermissions{
readPerms: mergeRangePerms(readPerms),
writePerms: mergeRangePerms(writePerms),
}
}
func checkKeyPerm(cachedPerms *unifiedRangePermissions, key, rangeEnd []byte, permtyp authpb.Permission_Type) bool {
var tocheck []*rangePerm
switch permtyp {
case authpb.READ:
tocheck = cachedPerms.readPerms
case authpb.WRITE:
tocheck = cachedPerms.writePerms
default:
plog.Panicf("unknown auth type: %v", permtyp)
}
requiredPerm := &rangePerm{begin: key, end: rangeEnd}
for _, perm := range tocheck {
if isSubset(requiredPerm, perm) {
return true
}
}
return false
}
func (as *authStore) isRangeOpPermitted(tx backend.BatchTx, userName string, key, rangeEnd []byte, permtyp authpb.Permission_Type) bool {
// assumption: tx is Lock()ed
_, ok := as.rangePermCache[userName]
if !ok {
perms := getMergedPerms(tx, userName)
if perms == nil {
plog.Errorf("failed to create a unified permission of user %s", userName)
return false
}
as.rangePermCache[userName] = perms
}
return checkKeyPerm(as.rangePermCache[userName], key, rangeEnd, permtyp)
}
func (as *authStore) clearCachedPerm() {
as.rangePermCache = make(map[string]*unifiedRangePermissions)
}
func (as *authStore) invalidateCachedPerm(userName string) {
delete(as.rangePermCache, userName)
}
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]
}

View File

@ -0,0 +1,129 @@
// Copyright 2016 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 (
"bytes"
"testing"
)
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) {
tests := []struct {
params []*rangePerm
want []*rangePerm
}{
{
[]*rangePerm{{[]byte("a"), []byte("b")}},
[]*rangePerm{{[]byte("a"), []byte("b")}},
},
{
[]*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("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("")}},
},
}
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)
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright 2016 Nippon Telegraph and Telephone Corporation.
// Copyright 2016 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.
@ -27,15 +27,7 @@ const (
defaultSimpleTokenLength = 16
)
var (
simpleTokens map[string]string // token -> user ID
)
func init() {
simpleTokens = make(map[string]string)
}
func genSimpleToken() (string, error) {
func (as *authStore) GenSimpleToken() (string, error) {
ret := make([]byte, defaultSimpleTokenLength)
for i := 0; i < defaultSimpleTokenLength; i++ {
@ -50,22 +42,14 @@ func genSimpleToken() (string, error) {
return string(ret), nil
}
func genSimpleTokenForUser(userID string) (string, error) {
var token string
var err error
func (as *authStore) assignSimpleTokenToUser(username, token string) {
as.simpleTokensMu.Lock()
for {
// generating random numbers in RSM would't a good idea
token, err = genSimpleToken()
if err != nil {
return "", err
}
if _, ok := simpleTokens[token]; !ok {
break
}
_, ok := as.simpleTokens[token]
if ok {
plog.Panicf("token %s is alredy used", token)
}
simpleTokens[token] = userID
return token, nil
as.simpleTokens[token] = username
as.simpleTokensMu.Unlock()
}

View File

@ -1,4 +1,4 @@
// Copyright 2016 Nippon Telegraph and Telephone Corporation.
// Copyright 2016 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.
@ -17,18 +17,23 @@ package auth
import (
"bytes"
"errors"
"fmt"
"sort"
"strings"
"sync"
"github.com/coreos/etcd/auth/authpb"
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
"github.com/coreos/etcd/mvcc/backend"
"github.com/coreos/pkg/capnslog"
"golang.org/x/crypto/bcrypt"
"golang.org/x/net/context"
)
var (
enableFlagKey = []byte("authEnabled")
authEnabled = []byte{1}
authDisabled = []byte{0}
authBucketName = []byte("auth")
authUsersBucketName = []byte("authUsers")
@ -36,22 +41,32 @@ var (
plog = capnslog.NewPackageLogger("github.com/coreos/etcd", "auth")
ErrUserAlreadyExist = errors.New("auth: user already exists")
ErrUserNotFound = errors.New("auth: user not found")
ErrRoleAlreadyExist = errors.New("auth: role already exists")
ErrRoleNotFound = errors.New("auth: role not found")
ErrAuthFailed = errors.New("auth: authentication failed, invalid user ID or password")
ErrRootUserNotExist = errors.New("auth: root user does not exist")
ErrRootRoleNotExist = errors.New("auth: root user does not have root role")
ErrUserAlreadyExist = errors.New("auth: user already exists")
ErrUserNotFound = errors.New("auth: user not found")
ErrRoleAlreadyExist = errors.New("auth: role already exists")
ErrRoleNotFound = errors.New("auth: role not found")
ErrAuthFailed = errors.New("auth: authentication failed, invalid user ID or password")
ErrPermissionDenied = errors.New("auth: permission denied")
ErrRoleNotGranted = errors.New("auth: role is not granted to the user")
ErrPermissionNotGranted = errors.New("auth: permission is not granted to the role")
)
const (
rootUser = "root"
rootRole = "root"
)
type AuthStore interface {
// AuthEnable turns on the authentication feature
AuthEnable()
AuthEnable() error
// Authenticate does authentication based on given user name and password,
// and returns a token for successful case.
// Note that the generated token is valid only for the member the client
// connected to within fixed time duration. Reauth is required after the duration.
Authenticate(name string, password string) (*pb.AuthenticateResponse, error)
// AuthDisable turns off the authentication feature
AuthDisable()
// Authenticate does authentication based on given user name and password
Authenticate(ctx context.Context, username, password string) (*pb.AuthenticateResponse, error)
// Recover recovers the state of auth store from the given backend
Recover(b backend.Backend)
@ -65,68 +80,154 @@ type AuthStore interface {
// UserChangePassword changes a password of a user
UserChangePassword(r *pb.AuthUserChangePasswordRequest) (*pb.AuthUserChangePasswordResponse, error)
// UserGrant grants a role to the user
UserGrant(r *pb.AuthUserGrantRequest) (*pb.AuthUserGrantResponse, error)
// UserGrantRole grants a role to the user
UserGrantRole(r *pb.AuthUserGrantRoleRequest) (*pb.AuthUserGrantRoleResponse, error)
// UserGet gets the detailed information of a users
UserGet(r *pb.AuthUserGetRequest) (*pb.AuthUserGetResponse, error)
// UserRevokeRole revokes a role of a user
UserRevokeRole(r *pb.AuthUserRevokeRoleRequest) (*pb.AuthUserRevokeRoleResponse, error)
// RoleAdd adds a new role
RoleAdd(r *pb.AuthRoleAddRequest) (*pb.AuthRoleAddResponse, error)
// RoleGrant grants a permission to a role
RoleGrant(r *pb.AuthRoleGrantRequest) (*pb.AuthRoleGrantResponse, error)
// RoleGrantPermission grants a permission to a role
RoleGrantPermission(r *pb.AuthRoleGrantPermissionRequest) (*pb.AuthRoleGrantPermissionResponse, error)
// RoleGet gets the detailed information of a role
RoleGet(r *pb.AuthRoleGetRequest) (*pb.AuthRoleGetResponse, error)
// RoleRevokePermission gets the detailed information of a role
RoleRevokePermission(r *pb.AuthRoleRevokePermissionRequest) (*pb.AuthRoleRevokePermissionResponse, error)
// RoleDelete gets the detailed information of a role
RoleDelete(r *pb.AuthRoleDeleteRequest) (*pb.AuthRoleDeleteResponse, error)
// UserList gets a list of all users
UserList(r *pb.AuthUserListRequest) (*pb.AuthUserListResponse, error)
// RoleList gets a list of all roles
RoleList(r *pb.AuthRoleListRequest) (*pb.AuthRoleListResponse, error)
// UsernameFromToken gets a username from the given Token
UsernameFromToken(token string) (string, bool)
// IsPutPermitted checks put permission of the user
IsPutPermitted(username string, key []byte) bool
// IsRangePermitted checks range permission of the user
IsRangePermitted(username string, key, rangeEnd []byte) bool
// IsDeleteRangePermitted checks delete-range permission of the user
IsDeleteRangePermitted(username string, key, rangeEnd []byte) bool
// IsAdminPermitted checks admin permission of the user
IsAdminPermitted(username string) bool
// GenSimpleToken produces a simple random string
GenSimpleToken() (string, error)
}
type authStore struct {
be backend.Backend
be backend.Backend
enabled bool
enabledMu sync.RWMutex
rangePermCache map[string]*unifiedRangePermissions // username -> unifiedRangePermissions
simpleTokensMu sync.RWMutex
simpleTokens map[string]string // token -> username
}
func (as *authStore) AuthEnable() {
value := []byte{1}
func (as *authStore) AuthEnable() error {
b := as.be
tx := b.BatchTx()
tx.Lock()
tx.UnsafePut(authBucketName, enableFlagKey, value)
defer func() {
tx.Unlock()
b.ForceCommit()
}()
u := getUser(tx, rootUser)
if u == nil {
return ErrRootUserNotExist
}
if !hasRootRole(u) {
return ErrRootRoleNotExist
}
tx.UnsafePut(authBucketName, enableFlagKey, authEnabled)
as.enabledMu.Lock()
as.enabled = true
as.enabledMu.Unlock()
as.rangePermCache = make(map[string]*unifiedRangePermissions)
plog.Noticef("Authentication enabled")
return nil
}
func (as *authStore) AuthDisable() {
b := as.be
tx := b.BatchTx()
tx.Lock()
tx.UnsafePut(authBucketName, enableFlagKey, authDisabled)
tx.Unlock()
b.ForceCommit()
plog.Noticef("Authentication enabled")
as.enabledMu.Lock()
as.enabled = false
as.enabledMu.Unlock()
plog.Noticef("Authentication disabled")
}
func (as *authStore) Authenticate(name string, password string) (*pb.AuthenticateResponse, error) {
func (as *authStore) Authenticate(ctx context.Context, username, password string) (*pb.AuthenticateResponse, error) {
// 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()
_, vs := tx.UnsafeRange(authUsersBucketName, []byte(name), nil, 0)
if len(vs) != 1 {
plog.Noticef("authentication failed, user %s doesn't exist", name)
return &pb.AuthenticateResponse{}, ErrAuthFailed
}
user := &authpb.User{}
err := user.Unmarshal(vs[0])
if err != nil {
return nil, err
user := getUser(tx, username)
if user == nil {
return nil, ErrAuthFailed
}
if bcrypt.CompareHashAndPassword(user.Password, []byte(password)) != nil {
plog.Noticef("authentication failed, invalid password for user %s", name)
plog.Noticef("authentication failed, invalid password for user %s", username)
return &pb.AuthenticateResponse{}, ErrAuthFailed
}
token, err := genSimpleTokenForUser(name)
if err != nil {
plog.Errorf("failed to generate simple token: %s", err)
return nil, err
}
token := fmt.Sprintf("%s.%d", simpleToken, index)
as.assignSimpleTokenToUser(username, token)
plog.Infof("authorized %s, token is %s", name, token)
plog.Infof("authorized %s, token is %s", username, token)
return &pb.AuthenticateResponse{Token: token}, nil
}
func (as *authStore) Recover(be backend.Backend) {
enabled := false
as.be = be
// TODO(mitake): recovery process
tx := be.BatchTx()
tx.Lock()
_, vs := tx.UnsafeRange(authBucketName, enableFlagKey, nil, 0)
if len(vs) == 1 {
if bytes.Equal(vs[0], authEnabled) {
enabled = true
}
}
tx.Unlock()
as.enabledMu.Lock()
as.enabled = enabled
as.enabledMu.Unlock()
}
func (as *authStore) UserAdd(r *pb.AuthUserAddRequest) (*pb.AuthUserAddResponse, error) {
@ -140,23 +241,17 @@ func (as *authStore) UserAdd(r *pb.AuthUserAddRequest) (*pb.AuthUserAddResponse,
tx.Lock()
defer tx.Unlock()
_, vs := tx.UnsafeRange(authUsersBucketName, []byte(r.Name), nil, 0)
if len(vs) != 0 {
return &pb.AuthUserAddResponse{}, ErrUserAlreadyExist
user := getUser(tx, r.Name)
if user != nil {
return nil, ErrUserAlreadyExist
}
newUser := authpb.User{
newUser := &authpb.User{
Name: []byte(r.Name),
Password: hashed,
}
marshaledUser, merr := newUser.Marshal()
if merr != nil {
plog.Errorf("failed to marshal a new user data: %s", merr)
return nil, merr
}
tx.UnsafePut(authUsersBucketName, []byte(r.Name), marshaledUser)
putUser(tx, newUser)
plog.Noticef("added a new user: %s", r.Name)
@ -168,12 +263,12 @@ func (as *authStore) UserDelete(r *pb.AuthUserDeleteRequest) (*pb.AuthUserDelete
tx.Lock()
defer tx.Unlock()
_, vs := tx.UnsafeRange(authUsersBucketName, []byte(r.Name), nil, 0)
if len(vs) != 1 {
return &pb.AuthUserDeleteResponse{}, ErrUserNotFound
user := getUser(tx, r.Name)
if user == nil {
return nil, ErrUserNotFound
}
tx.UnsafeDelete(authUsersBucketName, []byte(r.Name))
delUser(tx, r.Name)
plog.Noticef("deleted a user: %s", r.Name)
@ -193,68 +288,221 @@ func (as *authStore) UserChangePassword(r *pb.AuthUserChangePasswordRequest) (*p
tx.Lock()
defer tx.Unlock()
_, vs := tx.UnsafeRange(authUsersBucketName, []byte(r.Name), nil, 0)
if len(vs) != 1 {
return &pb.AuthUserChangePasswordResponse{}, ErrUserNotFound
user := getUser(tx, r.Name)
if user == nil {
return nil, ErrUserNotFound
}
updatedUser := authpb.User{
updatedUser := &authpb.User{
Name: []byte(r.Name),
Roles: user.Roles,
Password: hashed,
}
marshaledUser, merr := updatedUser.Marshal()
if merr != nil {
plog.Errorf("failed to marshal a new user data: %s", merr)
return nil, merr
}
tx.UnsafePut(authUsersBucketName, []byte(r.Name), marshaledUser)
putUser(tx, updatedUser)
plog.Noticef("changed a password of a user: %s", r.Name)
return &pb.AuthUserChangePasswordResponse{}, nil
}
func (as *authStore) UserGrant(r *pb.AuthUserGrantRequest) (*pb.AuthUserGrantResponse, error) {
func (as *authStore) UserGrantRole(r *pb.AuthUserGrantRoleRequest) (*pb.AuthUserGrantRoleResponse, error) {
tx := as.be.BatchTx()
tx.Lock()
defer tx.Unlock()
_, vs := tx.UnsafeRange(authUsersBucketName, []byte(r.User), nil, 0)
if len(vs) != 1 {
user := getUser(tx, r.User)
if user == nil {
return nil, ErrUserNotFound
}
user := &authpb.User{}
err := user.Unmarshal(vs[0])
if err != nil {
return nil, err
}
_, vs = tx.UnsafeRange(authRolesBucketName, []byte(r.Role), nil, 0)
if len(vs) != 1 {
return nil, ErrRoleNotFound
if r.Role != rootRole {
role := getRole(tx, r.Role)
if role == nil {
return nil, ErrRoleNotFound
}
}
idx := sort.SearchStrings(user.Roles, r.Role)
if idx < len(user.Roles) && strings.Compare(user.Roles[idx], r.Role) == 0 {
plog.Warningf("user %s is already granted role %s", r.User, r.Role)
return &pb.AuthUserGrantResponse{}, nil
return &pb.AuthUserGrantRoleResponse{}, nil
}
user.Roles = append(user.Roles, r.Role)
sort.Sort(sort.StringSlice(user.Roles))
marshaledUser, merr := user.Marshal()
if merr != nil {
return nil, merr
}
putUser(tx, user)
tx.UnsafePut(authUsersBucketName, user.Name, marshaledUser)
as.invalidateCachedPerm(r.User)
plog.Noticef("granted role %s to user %s", r.Role, r.User)
return &pb.AuthUserGrantResponse{}, nil
return &pb.AuthUserGrantRoleResponse{}, nil
}
func (as *authStore) UserGet(r *pb.AuthUserGetRequest) (*pb.AuthUserGetResponse, error) {
tx := as.be.BatchTx()
tx.Lock()
defer tx.Unlock()
var resp pb.AuthUserGetResponse
user := getUser(tx, r.Name)
if user == nil {
return nil, ErrUserNotFound
}
for _, role := range user.Roles {
resp.Roles = append(resp.Roles, role)
}
return &resp, nil
}
func (as *authStore) UserList(r *pb.AuthUserListRequest) (*pb.AuthUserListResponse, error) {
tx := as.be.BatchTx()
tx.Lock()
defer tx.Unlock()
var resp pb.AuthUserListResponse
users := getAllUsers(tx)
for _, u := range users {
resp.Users = append(resp.Users, string(u.Name))
}
return &resp, nil
}
func (as *authStore) UserRevokeRole(r *pb.AuthUserRevokeRoleRequest) (*pb.AuthUserRevokeRoleResponse, error) {
tx := as.be.BatchTx()
tx.Lock()
defer tx.Unlock()
user := getUser(tx, r.Name)
if user == nil {
return nil, ErrUserNotFound
}
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) {
return nil, ErrRoleNotGranted
}
putUser(tx, updatedUser)
as.invalidateCachedPerm(r.Name)
plog.Noticef("revoked role %s from user %s", r.Role, r.Name)
return &pb.AuthUserRevokeRoleResponse{}, nil
}
func (as *authStore) RoleGet(r *pb.AuthRoleGetRequest) (*pb.AuthRoleGetResponse, error) {
tx := as.be.BatchTx()
tx.Lock()
defer tx.Unlock()
var resp pb.AuthRoleGetResponse
role := getRole(tx, r.Role)
if role == nil {
return nil, ErrRoleNotFound
}
for _, perm := range role.KeyPermission {
resp.Perm = append(resp.Perm, perm)
}
return &resp, nil
}
func (as *authStore) RoleList(r *pb.AuthRoleListRequest) (*pb.AuthRoleListResponse, error) {
tx := as.be.BatchTx()
tx.Lock()
defer tx.Unlock()
var resp pb.AuthRoleListResponse
roles := getAllRoles(tx)
for _, r := range roles {
resp.Roles = append(resp.Roles, string(r.Name))
}
return &resp, nil
}
func (as *authStore) RoleRevokePermission(r *pb.AuthRoleRevokePermissionRequest) (*pb.AuthRoleRevokePermissionResponse, error) {
tx := as.be.BatchTx()
tx.Lock()
defer tx.Unlock()
role := getRole(tx, r.Role)
if role == nil {
return nil, ErrRoleNotFound
}
updatedRole := &authpb.Role{
Name: role.Name,
}
for _, perm := range role.KeyPermission {
if !bytes.Equal(perm.Key, []byte(r.Key)) || !bytes.Equal(perm.RangeEnd, []byte(r.RangeEnd)) {
updatedRole.KeyPermission = append(updatedRole.KeyPermission, perm)
}
}
if len(role.KeyPermission) == len(updatedRole.KeyPermission) {
return nil, ErrPermissionNotGranted
}
putRole(tx, updatedRole)
// TODO(mitake): currently single role update invalidates every cache
// It should be optimized.
as.clearCachedPerm()
plog.Noticef("revoked key %s from role %s", r.Key, r.Role)
return &pb.AuthRoleRevokePermissionResponse{}, nil
}
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.
tx := as.be.BatchTx()
tx.Lock()
defer tx.Unlock()
role := getRole(tx, r.Role)
if role == nil {
return nil, ErrRoleNotFound
}
delRole(tx, r.Role)
plog.Noticef("deleted role %s", r.Role)
return &pb.AuthRoleDeleteResponse{}, nil
}
func (as *authStore) RoleAdd(r *pb.AuthRoleAddRequest) (*pb.AuthRoleAddResponse, error) {
@ -262,8 +510,8 @@ func (as *authStore) RoleAdd(r *pb.AuthRoleAddRequest) (*pb.AuthRoleAddResponse,
tx.Lock()
defer tx.Unlock()
_, vs := tx.UnsafeRange(authRolesBucketName, []byte(r.Name), nil, 0)
if len(vs) != 0 {
role := getRole(tx, r.Name)
if role != nil {
return nil, ErrRoleAlreadyExist
}
@ -271,18 +519,20 @@ func (as *authStore) RoleAdd(r *pb.AuthRoleAddRequest) (*pb.AuthRoleAddResponse,
Name: []byte(r.Name),
}
marshaledRole, err := newRole.Marshal()
if err != nil {
return nil, err
}
tx.UnsafePut(authRolesBucketName, []byte(r.Name), marshaledRole)
putRole(tx, newRole)
plog.Noticef("Role %s is created", r.Name)
return &pb.AuthRoleAddResponse{}, nil
}
func (as *authStore) UsernameFromToken(token string) (string, bool) {
as.simpleTokensMu.RLock()
defer as.simpleTokensMu.RUnlock()
t, ok := as.simpleTokens[token]
return t, ok
}
type permSlice []*authpb.Permission
func (perms permSlice) Len() int {
@ -297,34 +547,28 @@ func (perms permSlice) Swap(i, j int) {
perms[i], perms[j] = perms[j], perms[i]
}
func (as *authStore) RoleGrant(r *pb.AuthRoleGrantRequest) (*pb.AuthRoleGrantResponse, error) {
func (as *authStore) RoleGrantPermission(r *pb.AuthRoleGrantPermissionRequest) (*pb.AuthRoleGrantPermissionResponse, error) {
tx := as.be.BatchTx()
tx.Lock()
defer tx.Unlock()
_, vs := tx.UnsafeRange(authRolesBucketName, []byte(r.Name), nil, 0)
if len(vs) != 1 {
role := getRole(tx, r.Name)
if role == nil {
return nil, ErrRoleNotFound
}
role := &authpb.Role{}
err := role.Unmarshal(vs[0])
if err != nil {
plog.Errorf("failed to unmarshal a role %s: %s", r.Name, err)
return nil, err
}
idx := sort.Search(len(role.KeyPermission), func(i int) bool {
return bytes.Compare(role.KeyPermission[i].Key, []byte(r.Perm.Key)) >= 0
})
if idx < len(role.KeyPermission) && bytes.Equal(role.KeyPermission[idx].Key, r.Perm.Key) {
if idx < len(role.KeyPermission) && bytes.Equal(role.KeyPermission[idx].Key, r.Perm.Key) && bytes.Equal(role.KeyPermission[idx].RangeEnd, r.Perm.RangeEnd) {
// update existing permission
role.KeyPermission[idx].PermType = r.Perm.PermType
} else {
// append new permission to the role
newPerm := &authpb.Permission{
Key: []byte(r.Perm.Key),
RangeEnd: []byte(r.Perm.RangeEnd),
PermType: r.Perm.PermType,
}
@ -332,17 +576,168 @@ func (as *authStore) RoleGrant(r *pb.AuthRoleGrantRequest) (*pb.AuthRoleGrantRes
sort.Sort(permSlice(role.KeyPermission))
}
marshaledRole, merr := role.Marshal()
if merr != nil {
plog.Errorf("failed to marshal updated role %s: %s", r.Name, merr)
return nil, merr
}
putRole(tx, role)
tx.UnsafePut(authRolesBucketName, []byte(r.Name), marshaledRole)
// TODO(mitake): currently single role update invalidates every cache
// It should be optimized.
as.clearCachedPerm()
plog.Noticef("role %s's permission of key %s is updated as %s", r.Name, r.Perm.Key, authpb.Permission_Type_name[int32(r.Perm.PermType)])
return &pb.AuthRoleGrantResponse{}, nil
return &pb.AuthRoleGrantPermissionResponse{}, nil
}
func (as *authStore) isOpPermitted(userName string, key, rangeEnd []byte, permTyp authpb.Permission_Type) bool {
// TODO(mitake): this function would be costly so we need a caching mechanism
if !as.isAuthEnabled() {
return true
}
tx := as.be.BatchTx()
tx.Lock()
defer tx.Unlock()
user := getUser(tx, userName)
if user == nil {
plog.Errorf("invalid user name %s for permission checking", userName)
return false
}
if as.isRangeOpPermitted(tx, userName, key, rangeEnd, permTyp) {
return true
}
return false
}
func (as *authStore) IsPutPermitted(username string, key []byte) bool {
return as.isOpPermitted(username, key, nil, authpb.WRITE)
}
func (as *authStore) IsRangePermitted(username string, key, rangeEnd []byte) bool {
return as.isOpPermitted(username, key, rangeEnd, authpb.READ)
}
func (as *authStore) IsDeleteRangePermitted(username string, key, rangeEnd []byte) bool {
return as.isOpPermitted(username, key, rangeEnd, authpb.WRITE)
}
func (as *authStore) IsAdminPermitted(username string) bool {
if !as.isAuthEnabled() {
return true
}
tx := as.be.BatchTx()
tx.Lock()
defer tx.Unlock()
u := getUser(tx, username)
if u == nil {
return false
}
return hasRootRole(u)
}
func getUser(tx backend.BatchTx, username string) *authpb.User {
_, vs := tx.UnsafeRange(authUsersBucketName, []byte(username), nil, 0)
if len(vs) == 0 {
return nil
}
user := &authpb.User{}
err := user.Unmarshal(vs[0])
if err != nil {
plog.Panicf("failed to unmarshal user struct (name: %s): %s", username, err)
}
return user
}
func getAllUsers(tx backend.BatchTx) []*authpb.User {
_, vs := tx.UnsafeRange(authUsersBucketName, []byte{0}, []byte{0xff}, -1)
if len(vs) == 0 {
return nil
}
var users []*authpb.User
for _, v := range vs {
user := &authpb.User{}
err := user.Unmarshal(v)
if err != nil {
plog.Panicf("failed to unmarshal user struct: %s", err)
}
users = append(users, user)
}
return users
}
func putUser(tx backend.BatchTx, user *authpb.User) {
b, err := user.Marshal()
if err != nil {
plog.Panicf("failed to marshal user struct (name: %s): %s", user.Name, err)
}
tx.UnsafePut(authUsersBucketName, user.Name, b)
}
func delUser(tx backend.BatchTx, username string) {
tx.UnsafeDelete(authUsersBucketName, []byte(username))
}
func getRole(tx backend.BatchTx, rolename string) *authpb.Role {
_, vs := tx.UnsafeRange(authRolesBucketName, []byte(rolename), nil, 0)
if len(vs) == 0 {
return nil
}
role := &authpb.Role{}
err := role.Unmarshal(vs[0])
if err != nil {
plog.Panicf("failed to unmarshal role struct (name: %s): %s", rolename, err)
}
return role
}
func getAllRoles(tx backend.BatchTx) []*authpb.Role {
_, vs := tx.UnsafeRange(authRolesBucketName, []byte{0}, []byte{0xff}, -1)
if len(vs) == 0 {
return nil
}
var roles []*authpb.Role
for _, v := range vs {
role := &authpb.Role{}
err := role.Unmarshal(v)
if err != nil {
plog.Panicf("failed to unmarshal role struct: %s", err)
}
roles = append(roles, role)
}
return roles
}
func putRole(tx backend.BatchTx, role *authpb.Role) {
b, err := role.Marshal()
if err != nil {
plog.Panicf("failed to marshal role struct (name: %s): %s", role.Name, err)
}
tx.UnsafePut(authRolesBucketName, []byte(role.Name), b)
}
func delRole(tx backend.BatchTx, rolename string) {
tx.UnsafeDelete(authRolesBucketName, []byte(rolename))
}
func (as *authStore) isAuthEnabled() bool {
as.enabledMu.RLock()
defer as.enabledMu.RUnlock()
return as.enabled
}
func NewAuthStore(be backend.Backend) *authStore {
@ -357,6 +752,16 @@ func NewAuthStore(be backend.Backend) *authStore {
be.ForceCommit()
return &authStore{
be: be,
be: be,
simpleTokens: make(map[string]string),
}
}
func hasRootRole(u *authpb.User) bool {
for _, r := range u.Roles {
if r == rootRole {
return true
}
}
return false
}

View File

@ -1,4 +1,4 @@
// Copyright 2016 CoreOS, Inc.
// Copyright 2016 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.
@ -20,6 +20,7 @@ import (
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
"github.com/coreos/etcd/mvcc/backend"
"golang.org/x/net/context"
)
func TestUserAdd(t *testing.T) {
@ -60,7 +61,8 @@ func TestAuthenticate(t *testing.T) {
}
// auth a non-existing user
_, err = as.Authenticate("foo-test", "bar")
ctx1 := context.WithValue(context.WithValue(context.TODO(), "index", uint64(1)), "simpleToken", "dummy")
_, err = as.Authenticate(ctx1, "foo-test", "bar")
if err == nil {
t.Fatalf("expected %v, got %v", ErrAuthFailed, err)
}
@ -69,13 +71,15 @@ func TestAuthenticate(t *testing.T) {
}
// auth an existing user with correct password
_, err = as.Authenticate("foo", "bar")
ctx2 := context.WithValue(context.WithValue(context.TODO(), "index", uint64(2)), "simpleToken", "dummy")
_, err = as.Authenticate(ctx2, "foo", "bar")
if err != nil {
t.Fatal(err)
}
// auth an existing user but with wrong password
_, err = as.Authenticate("foo", "")
ctx3 := context.WithValue(context.WithValue(context.TODO(), "index", uint64(3)), "simpleToken", "dummy")
_, err = as.Authenticate(ctx3, "foo", "")
if err == nil {
t.Fatalf("expected %v, got %v", ErrAuthFailed, err)
}
@ -129,7 +133,9 @@ func TestUserChangePassword(t *testing.T) {
if err != nil {
t.Fatal(err)
}
_, err = as.Authenticate("foo", "")
ctx1 := context.WithValue(context.WithValue(context.TODO(), "index", uint64(1)), "simpleToken", "dummy")
_, err = as.Authenticate(ctx1, "foo", "")
if err != nil {
t.Fatal(err)
}
@ -138,7 +144,9 @@ func TestUserChangePassword(t *testing.T) {
if err != nil {
t.Fatal(err)
}
_, err = as.Authenticate("foo", "bar")
ctx2 := context.WithValue(context.WithValue(context.TODO(), "index", uint64(2)), "simpleToken", "dummy")
_, err = as.Authenticate(ctx2, "foo", "bar")
if err != nil {
t.Fatal(err)
}
@ -190,13 +198,13 @@ func TestUserGrant(t *testing.T) {
}
// grants a role to the user
_, err = as.UserGrant(&pb.AuthUserGrantRequest{User: "foo", Role: "role-test"})
_, err = as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "foo", Role: "role-test"})
if err != nil {
t.Fatal(err)
}
// grants a role to a non-existing user
_, err = as.UserGrant(&pb.AuthUserGrantRequest{User: "foo-test", Role: "role-test"})
_, err = as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "foo-test", Role: "role-test"})
if err == nil {
t.Fatalf("expected %v, got %v", ErrUserNotFound, err)
}

48
build
View File

@ -1,22 +1,44 @@
#!/bin/sh -e
# 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"`
LINK_OPERATOR="="
if [ -z "${GOARCH}" ] || [ "${GOARCH}" = "$(go env GOHOSTARCH)" ]; then
out="bin"
else
out="bin/${GOARCH}"
if [ ! -z "$FAILPOINTS" ]; then
GIT_SHA="$GIT_SHA"-FAILPOINTS
fi
# Static compilation is useful when etcd is run in a container
CGO_ENABLED=0 go build $GO_BUILD_FLAGS -installsuffix cgo -ldflags "-s -X ${REPO_PATH}/cmd/vendor/${REPO_PATH}/version.GitSHA${LINK_OPERATOR}${GIT_SHA}" -o ${out}/etcd ${REPO_PATH}/cmd
CGO_ENABLED=0 go build $GO_BUILD_FLAGS -installsuffix cgo -ldflags "-s" -o ${out}/etcdctl ${REPO_PATH}/cmd/etcdctl
# enable/disable failpoints
toggle_failpoints() {
FAILPKGS="etcdserver/"
mode="disable"
if [ ! -z "$FAILPOINTS" ]; then mode="enable"; fi
if [ ! -z "$1" ]; then mode="$1"; fi
if which gofail >/dev/null 2>&1; then
gofail "$mode" $FAILPKGS
elif [ "$mode" != "disable" ]; then
echo "FAILPOINTS set but gofail not found"
exit 1
fi
}
etcd_build() {
if [ -z "${GOARCH}" ] || [ "${GOARCH}" = "$(go env GOHOSTARCH)" ]; then
out="bin"
else
out="bin/${GOARCH}"
fi
toggle_failpoints
# Static compilation is useful when etcd is run in a container
CGO_ENABLED=0 go build $GO_BUILD_FLAGS -installsuffix cgo -ldflags "-s -X ${REPO_PATH}/cmd/vendor/${REPO_PATH}/version.GitSHA=${GIT_SHA}" -o ${out}/etcd ${REPO_PATH}/cmd
CGO_ENABLED=0 go build $GO_BUILD_FLAGS -installsuffix cgo -ldflags "-s" -o ${out}/etcdctl ${REPO_PATH}/cmd/etcdctl
}
toggle_failpoints
# don't build when sourced
(echo "$0" | grep "/build$" > /dev/null) && etcd_build || true

View File

@ -1,4 +1,4 @@
// Copyright 2015 CoreOS, Inc.
// 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.

View File

@ -1,4 +1,4 @@
// Copyright 2015 CoreOS, Inc.
// 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.

View File

@ -1,4 +1,4 @@
// Copyright 2015 CoreOS, Inc.
// 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.
@ -37,6 +37,10 @@ var (
ErrClusterUnavailable = errors.New("client: etcd cluster is unavailable or misconfigured")
ErrNoLeaderEndpoint = errors.New("client: no leader endpoint available")
errTooManyRedirectChecks = errors.New("client: too many redirect checks")
// oneShotCtxValue is set on a context using WithValue(&oneShotValue) so
// that Do() will not retry a request
oneShotCtxValue interface{}
)
var DefaultRequestTimeout = 5 * time.Second
@ -335,6 +339,7 @@ func (c *httpClusterClient) Do(ctx context.Context, act httpAction) (*http.Respo
var body []byte
var err error
cerr := &ClusterError{}
isOneShot := ctx.Value(&oneShotCtxValue) != nil
for i := pinned; i < leps+pinned; i++ {
k := i % leps
@ -348,6 +353,9 @@ func (c *httpClusterClient) Do(ctx context.Context, act httpAction) (*http.Respo
if err == context.Canceled || err == context.DeadlineExceeded {
return nil, nil, err
}
if isOneShot {
return nil, nil, err
}
continue
}
if resp.StatusCode/100 == 5 {
@ -358,6 +366,9 @@ func (c *httpClusterClient) Do(ctx context.Context, act httpAction) (*http.Respo
default:
cerr.Errors = append(cerr.Errors, fmt.Errorf("client: etcd member %s returns server error [%s]", eps[k].String(), http.StatusText(resp.StatusCode)))
}
if isOneShot {
return nil, nil, cerr.Errors[0]
}
continue
}
if k != pinned {

View File

@ -1,4 +1,4 @@
// Copyright 2015 CoreOS, Inc.
// 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.

View File

@ -1,4 +1,4 @@
// Copyright 2015 CoreOS, Inc.
// 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.

View File

@ -1,4 +1,4 @@
// Copyright 2015 CoreOS, Inc.
// 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.

View File

@ -1,4 +1,4 @@
// Copyright 2015 CoreOS, Inc.
// 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.

View File

@ -1,4 +1,4 @@
// Copyright 2015 CoreOS, Inc.
// 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.

View File

@ -1,4 +1,4 @@
// Copyright 2015 CoreOS, Inc.
// 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.

View File

@ -0,0 +1,134 @@
// Copyright 2016 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 integration
import (
"fmt"
"net/http"
"net/http/httptest"
"os"
"strings"
"sync/atomic"
"testing"
"golang.org/x/net/context"
"github.com/coreos/etcd/client"
"github.com/coreos/etcd/integration"
"github.com/coreos/etcd/pkg/testutil"
)
// TestV2NoRetryEOF tests destructive api calls won't retry on a disconnection.
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()))
defer lEOF.Close()
tries := uint32(0)
go func() {
for {
conn, err := lEOF.Accept()
if err != nil {
return
}
atomic.AddUint32(&tries, 1)
conn.Close()
}
}()
eofURL := integration.UrlScheme + "://" + lEOF.Addr().String()
cli := integration.MustNewHTTPClient(t, []string{eofURL, eofURL}, nil)
kapi := client.NewKeysAPI(cli)
for i, f := range noRetryList(kapi) {
startTries := atomic.LoadUint32(&tries)
if err := f(); err == nil {
t.Errorf("#%d: expected EOF error, got nil", i)
}
endTries := atomic.LoadUint32(&tries)
if startTries+1 != endTries {
t.Errorf("#%d: expected 1 try, got %d", i, endTries-startTries)
}
}
}
// 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()))
eh := &errHandler{errCode: http.StatusServiceUnavailable}
srv := httptest.NewUnstartedServer(eh)
defer lHttp.Close()
defer srv.Close()
srv.Listener = lHttp
go srv.Start()
lHttpURL := integration.UrlScheme + "://" + lHttp.Addr().String()
cli := integration.MustNewHTTPClient(t, []string{lHttpURL, lHttpURL}, nil)
kapi := client.NewKeysAPI(cli)
// test error code
for i, f := range noRetryList(kapi) {
reqs := eh.reqs
if err := f(); err == nil || !strings.Contains(err.Error(), "no leader") {
t.Errorf("#%d: expected \"no leader\", got %v", i, err)
}
if eh.reqs != reqs+1 {
t.Errorf("#%d: expected 1 request, got %d", i, eh.reqs-reqs)
}
}
}
// TestV2RetryRefuse tests destructive api calls will retry if a connection is refused.
func TestV2RetryRefuse(t *testing.T) {
defer testutil.AfterTest(t)
cl := integration.NewCluster(t, 1)
cl.Launch(t)
defer cl.Terminate(t)
// test connection refused; expect no error failover
cli := integration.MustNewHTTPClient(t, []string{integration.UrlScheme + "://refuseconn:123", cl.URL(0)}, nil)
kapi := client.NewKeysAPI(cli)
if _, err := kapi.Set(context.Background(), "/delkey", "def", nil); err != nil {
t.Fatal(err)
}
for i, f := range noRetryList(kapi) {
if err := f(); err != nil {
t.Errorf("#%d: unexpected retry failure (%v)", i, err)
}
}
}
type errHandler struct {
errCode int
reqs int
}
func (eh *errHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
req.Body.Close()
eh.reqs++
w.WriteHeader(eh.errCode)
}
func noRetryList(kapi client.KeysAPI) []func() error {
return []func() error{
func() error {
opts := &client.SetOptions{PrevExist: client.PrevNoExist}
_, err := kapi.Set(context.Background(), "/setkey", "bar", opts)
return err
},
func() error {
_, err := kapi.Delete(context.Background(), "/delkey", nil)
return err
},
}
}

View File

@ -0,0 +1,20 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package integration
import (
"os"
"testing"
"github.com/coreos/etcd/pkg/testutil"
)
func TestMain(m *testing.M) {
v := m.Run()
if v == 0 && testutil.CheckLeakedGoroutine() {
os.Exit(1)
}
os.Exit(v)
}

View File

@ -1,4 +1,4 @@
// Copyright 2015 CoreOS, Inc.
// 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.
@ -337,7 +337,11 @@ func (k *httpKeysAPI) Set(ctx context.Context, key, val string, opts *SetOptions
act.Dir = opts.Dir
}
resp, body, err := k.client.Do(ctx, act)
doCtx := ctx
if act.PrevExist == PrevNoExist {
doCtx = context.WithValue(doCtx, &oneShotCtxValue, &oneShotCtxValue)
}
resp, body, err := k.client.Do(doCtx, act)
if err != nil {
return nil, err
}
@ -385,7 +389,8 @@ func (k *httpKeysAPI) Delete(ctx context.Context, key string, opts *DeleteOption
act.Recursive = opts.Recursive
}
resp, body, err := k.client.Do(ctx, act)
doCtx := context.WithValue(ctx, &oneShotCtxValue, &oneShotCtxValue)
resp, body, err := k.client.Do(doCtx, act)
if err != nil {
return nil, err
}

View File

@ -1,4 +1,4 @@
// Copyright 2015 CoreOS, Inc.
// 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.

View File

@ -1,4 +1,4 @@
// Copyright 2015 CoreOS, Inc.
// 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.
@ -645,15 +645,14 @@ func assertRequest(got http.Request, wantMethod string, wantURL *url.URL, wantHe
} else {
if wantBody == nil {
return fmt.Errorf("want.Body=%v got.Body=%s", wantBody, got.Body)
} else {
gotBytes, err := ioutil.ReadAll(got.Body)
if err != nil {
return err
}
}
gotBytes, err := ioutil.ReadAll(got.Body)
if err != nil {
return err
}
if !reflect.DeepEqual(wantBody, gotBytes) {
return fmt.Errorf("want.Body=%s got.Body=%s", wantBody, gotBytes)
}
if !reflect.DeepEqual(wantBody, gotBytes) {
return fmt.Errorf("want.Body=%s got.Body=%s", wantBody, gotBytes)
}
}

View File

@ -1,4 +1,4 @@
// Copyright 2015 CoreOS, Inc.
// 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.

View File

@ -1,4 +1,4 @@
// Copyright 2015 CoreOS, Inc.
// 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.

View File

@ -1,4 +1,4 @@
// Copyright 2015 CoreOS, Inc.
// 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.

View File

@ -1,4 +1,4 @@
// Copyright 2015 CoreOS, Inc.
// 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.

View File

@ -1,4 +1,4 @@
// Copyright 2016 CoreOS, Inc.
// Copyright 2016 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.

View File

@ -1,4 +1,4 @@
// Copyright 2016 Nippon Telegraph and Telephone Corporation.
// Copyright 2016 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.
@ -19,21 +19,28 @@ import (
"strings"
"github.com/coreos/etcd/auth/authpb"
"github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
"golang.org/x/net/context"
"google.golang.org/grpc"
)
type (
AuthEnableResponse pb.AuthEnableResponse
AuthenticateResponse pb.AuthenticateResponse
AuthUserAddResponse pb.AuthUserAddResponse
AuthUserDeleteResponse pb.AuthUserDeleteResponse
AuthUserChangePasswordResponse pb.AuthUserChangePasswordResponse
AuthUserGrantResponse pb.AuthUserGrantResponse
AuthRoleAddResponse pb.AuthRoleAddResponse
AuthRoleGrantResponse pb.AuthRoleGrantResponse
AuthEnableResponse pb.AuthEnableResponse
AuthDisableResponse pb.AuthDisableResponse
AuthenticateResponse pb.AuthenticateResponse
AuthUserAddResponse pb.AuthUserAddResponse
AuthUserDeleteResponse pb.AuthUserDeleteResponse
AuthUserChangePasswordResponse pb.AuthUserChangePasswordResponse
AuthUserGrantRoleResponse pb.AuthUserGrantRoleResponse
AuthUserGetResponse pb.AuthUserGetResponse
AuthUserRevokeRoleResponse pb.AuthUserRevokeRoleResponse
AuthRoleAddResponse pb.AuthRoleAddResponse
AuthRoleGrantPermissionResponse pb.AuthRoleGrantPermissionResponse
AuthRoleGetResponse pb.AuthRoleGetResponse
AuthRoleRevokePermissionResponse pb.AuthRoleRevokePermissionResponse
AuthRoleDeleteResponse pb.AuthRoleDeleteResponse
AuthUserListResponse pb.AuthUserListResponse
AuthRoleListResponse pb.AuthRoleListResponse
PermissionType authpb.Permission_Type
)
@ -48,8 +55,8 @@ type Auth interface {
// AuthEnable enables auth of an etcd cluster.
AuthEnable(ctx context.Context) (*AuthEnableResponse, error)
// Authenticate does authenticate with given user name and password.
Authenticate(ctx context.Context, name string, password string) (*AuthenticateResponse, error)
// AuthDisable disables auth of an etcd cluster.
AuthDisable(ctx context.Context) (*AuthDisableResponse, error)
// UserAdd adds a new user to an etcd cluster.
UserAdd(ctx context.Context, name string, password string) (*AuthUserAddResponse, error)
@ -60,14 +67,35 @@ type Auth interface {
// UserChangePassword changes a password of a user.
UserChangePassword(ctx context.Context, name string, password string) (*AuthUserChangePasswordResponse, error)
// UserGrant grants a role to a user.
UserGrant(ctx context.Context, user string, role string) (*AuthUserGrantResponse, error)
// UserGrantRole grants a role to a user.
UserGrantRole(ctx context.Context, user string, role string) (*AuthUserGrantRoleResponse, error)
// UserGet gets a detailed information of a user.
UserGet(ctx context.Context, name string) (*AuthUserGetResponse, error)
// UserList gets a list of all users.
UserList(ctx context.Context) (*AuthUserListResponse, error)
// UserRevokeRole revokes a role of a user.
UserRevokeRole(ctx context.Context, name string, role string) (*AuthUserRevokeRoleResponse, error)
// RoleAdd adds a new role to an etcd cluster.
RoleAdd(ctx context.Context, name string) (*AuthRoleAddResponse, error)
// RoleGrant grants a permission to a role.
RoleGrant(ctx context.Context, name string, key string, permType PermissionType) (*AuthRoleGrantResponse, error)
// RoleGrantPermission grants a permission to a role.
RoleGrantPermission(ctx context.Context, name string, key, rangeEnd string, permType PermissionType) (*AuthRoleGrantPermissionResponse, error)
// RoleGet gets a detailed information of a role.
RoleGet(ctx context.Context, role string) (*AuthRoleGetResponse, error)
// RoleList gets a list of all roles.
RoleList(ctx context.Context) (*AuthRoleListResponse, error)
// RoleRevokePermission revokes a permission from a role.
RoleRevokePermission(ctx context.Context, role string, key, rangeEnd string) (*AuthRoleRevokePermissionResponse, error)
// RoleDelete deletes a role.
RoleDelete(ctx context.Context, role string) (*AuthRoleDeleteResponse, error)
}
type auth struct {
@ -88,46 +116,82 @@ func NewAuth(c *Client) Auth {
func (auth *auth) AuthEnable(ctx context.Context) (*AuthEnableResponse, error) {
resp, err := auth.remote.AuthEnable(ctx, &pb.AuthEnableRequest{})
return (*AuthEnableResponse)(resp), rpctypes.Error(err)
return (*AuthEnableResponse)(resp), toErr(ctx, err)
}
func (auth *auth) Authenticate(ctx context.Context, name string, password string) (*AuthenticateResponse, error) {
resp, err := auth.remote.Authenticate(ctx, &pb.AuthenticateRequest{Name: name, Password: password})
return (*AuthenticateResponse)(resp), rpctypes.Error(err)
func (auth *auth) AuthDisable(ctx context.Context) (*AuthDisableResponse, error) {
resp, err := auth.remote.AuthDisable(ctx, &pb.AuthDisableRequest{})
return (*AuthDisableResponse)(resp), toErr(ctx, err)
}
func (auth *auth) UserAdd(ctx context.Context, name string, password string) (*AuthUserAddResponse, error) {
resp, err := auth.remote.UserAdd(ctx, &pb.AuthUserAddRequest{Name: name, Password: password})
return (*AuthUserAddResponse)(resp), rpctypes.Error(err)
return (*AuthUserAddResponse)(resp), toErr(ctx, err)
}
func (auth *auth) UserDelete(ctx context.Context, name string) (*AuthUserDeleteResponse, error) {
resp, err := auth.remote.UserDelete(ctx, &pb.AuthUserDeleteRequest{Name: name})
return (*AuthUserDeleteResponse)(resp), rpctypes.Error(err)
return (*AuthUserDeleteResponse)(resp), toErr(ctx, err)
}
func (auth *auth) UserChangePassword(ctx context.Context, name string, password string) (*AuthUserChangePasswordResponse, error) {
resp, err := auth.remote.UserChangePassword(ctx, &pb.AuthUserChangePasswordRequest{Name: name, Password: password})
return (*AuthUserChangePasswordResponse)(resp), rpctypes.Error(err)
return (*AuthUserChangePasswordResponse)(resp), toErr(ctx, err)
}
func (auth *auth) UserGrant(ctx context.Context, user string, role string) (*AuthUserGrantResponse, error) {
resp, err := auth.remote.UserGrant(ctx, &pb.AuthUserGrantRequest{User: user, Role: role})
return (*AuthUserGrantResponse)(resp), rpctypes.Error(err)
func (auth *auth) UserGrantRole(ctx context.Context, user string, role string) (*AuthUserGrantRoleResponse, error) {
resp, err := auth.remote.UserGrantRole(ctx, &pb.AuthUserGrantRoleRequest{User: user, Role: role})
return (*AuthUserGrantRoleResponse)(resp), toErr(ctx, err)
}
func (auth *auth) UserGet(ctx context.Context, name string) (*AuthUserGetResponse, error) {
resp, err := auth.remote.UserGet(ctx, &pb.AuthUserGetRequest{Name: name}, grpc.FailFast(false))
return (*AuthUserGetResponse)(resp), toErr(ctx, err)
}
func (auth *auth) UserList(ctx context.Context) (*AuthUserListResponse, error) {
resp, err := auth.remote.UserList(ctx, &pb.AuthUserListRequest{}, grpc.FailFast(false))
return (*AuthUserListResponse)(resp), toErr(ctx, err)
}
func (auth *auth) UserRevokeRole(ctx context.Context, name string, role string) (*AuthUserRevokeRoleResponse, error) {
resp, err := auth.remote.UserRevokeRole(ctx, &pb.AuthUserRevokeRoleRequest{Name: name, Role: role})
return (*AuthUserRevokeRoleResponse)(resp), toErr(ctx, err)
}
func (auth *auth) RoleAdd(ctx context.Context, name string) (*AuthRoleAddResponse, error) {
resp, err := auth.remote.RoleAdd(ctx, &pb.AuthRoleAddRequest{Name: name})
return (*AuthRoleAddResponse)(resp), rpctypes.Error(err)
return (*AuthRoleAddResponse)(resp), toErr(ctx, err)
}
func (auth *auth) RoleGrant(ctx context.Context, name string, key string, permType PermissionType) (*AuthRoleGrantResponse, error) {
func (auth *auth) RoleGrantPermission(ctx context.Context, name string, key, rangeEnd string, permType PermissionType) (*AuthRoleGrantPermissionResponse, error) {
perm := &authpb.Permission{
Key: []byte(key),
RangeEnd: []byte(rangeEnd),
PermType: authpb.Permission_Type(permType),
}
resp, err := auth.remote.RoleGrant(ctx, &pb.AuthRoleGrantRequest{Name: name, Perm: perm})
return (*AuthRoleGrantResponse)(resp), rpctypes.Error(err)
resp, err := auth.remote.RoleGrantPermission(ctx, &pb.AuthRoleGrantPermissionRequest{Name: name, Perm: perm})
return (*AuthRoleGrantPermissionResponse)(resp), toErr(ctx, err)
}
func (auth *auth) RoleGet(ctx context.Context, role string) (*AuthRoleGetResponse, error) {
resp, err := auth.remote.RoleGet(ctx, &pb.AuthRoleGetRequest{Role: role}, grpc.FailFast(false))
return (*AuthRoleGetResponse)(resp), toErr(ctx, err)
}
func (auth *auth) RoleList(ctx context.Context) (*AuthRoleListResponse, error) {
resp, err := auth.remote.RoleList(ctx, &pb.AuthRoleListRequest{}, grpc.FailFast(false))
return (*AuthRoleListResponse)(resp), toErr(ctx, err)
}
func (auth *auth) RoleRevokePermission(ctx context.Context, role string, key, rangeEnd string) (*AuthRoleRevokePermissionResponse, error) {
resp, err := auth.remote.RoleRevokePermission(ctx, &pb.AuthRoleRevokePermissionRequest{Role: role, Key: key, RangeEnd: rangeEnd})
return (*AuthRoleRevokePermissionResponse)(resp), toErr(ctx, err)
}
func (auth *auth) RoleDelete(ctx context.Context, role string) (*AuthRoleDeleteResponse, error) {
resp, err := auth.remote.RoleDelete(ctx, &pb.AuthRoleDeleteRequest{Role: role})
return (*AuthRoleDeleteResponse)(resp), toErr(ctx, err)
}
func StrToPermissionType(s string) (PermissionType, error) {
@ -137,3 +201,29 @@ func StrToPermissionType(s string) (PermissionType, error) {
}
return PermissionType(-1), fmt.Errorf("invalid permission type: %s", s)
}
type authenticator struct {
conn *grpc.ClientConn // conn in-use
remote pb.AuthClient
}
func (auth *authenticator) authenticate(ctx context.Context, name string, password string) (*AuthenticateResponse, error) {
resp, err := auth.remote.Authenticate(ctx, &pb.AuthenticateRequest{Name: name, Password: password}, grpc.FailFast(false))
return (*AuthenticateResponse)(resp), toErr(ctx, err)
}
func (auth *authenticator) close() {
auth.conn.Close()
}
func newAuthenticator(endpoint string, opts []grpc.DialOption) (*authenticator, error) {
conn, err := grpc.Dial(endpoint, opts...)
if err != nil {
return nil, err
}
return &authenticator{
conn: conn,
remote: pb.NewAuthClient(conn),
}, nil
}

147
clientv3/balancer.go Normal file
View File

@ -0,0 +1,147 @@
// Copyright 2016 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 clientv3
import (
"net/url"
"strings"
"sync"
"golang.org/x/net/context"
"google.golang.org/grpc"
)
// simpleBalancer does the bare minimum to expose multiple eps
// to the grpc reconnection code path
type simpleBalancer struct {
// addrs are the client's endpoints for grpc
addrs []grpc.Address
// notifyCh notifies grpc of the set of addresses for connecting
notifyCh chan []grpc.Address
// readyc closes once the first connection is up
readyc chan struct{}
readyOnce sync.Once
// 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{}
// pinAddr is the currently pinned address; set to the empty string on
// intialization and shutdown.
pinAddr string
}
func newSimpleBalancer(eps []string) *simpleBalancer {
notifyCh := make(chan []grpc.Address, 1)
addrs := make([]grpc.Address, len(eps))
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{}),
}
return sb
}
func (b *simpleBalancer) Start(target string) error { return nil }
func (b *simpleBalancer) ConnectNotify() <-chan struct{} {
b.mu.Lock()
defer b.mu.Unlock()
return b.upc
}
func (b *simpleBalancer) Up(addr grpc.Address) func(error) {
b.mu.Lock()
if len(b.upEps) == 0 {
// notify waiting Get()s and pin first connected address
close(b.upc)
b.pinAddr = addr.Addr
}
b.upEps[addr.Addr] = struct{}{}
b.mu.Unlock()
// 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.mu.Unlock()
}
}
func (b *simpleBalancer) Get(ctx context.Context, opts grpc.BalancerGetOptions) (grpc.Address, func(), error) {
var addr string
for {
b.mu.RLock()
ch := b.upc
b.mu.RUnlock()
select {
case <-ch:
case <-ctx.Done():
return grpc.Address{Addr: ""}, nil, ctx.Err()
}
b.mu.RLock()
addr = b.pinAddr
upEps := len(b.upEps)
b.mu.RUnlock()
if addr == "" {
return grpc.Address{Addr: ""}, nil, grpc.ErrClientConnClosing
}
if upEps > 0 {
break
}
}
return grpc.Address{Addr: addr}, func() {}, nil
}
func (b *simpleBalancer) Notify() <-chan []grpc.Address { return b.notifyCh }
func (b *simpleBalancer) Close() error {
b.mu.Lock()
close(b.notifyCh)
// terminate all waiting Get()s
b.pinAddr = ""
if len(b.upEps) == 0 {
close(b.upc)
}
b.mu.Unlock()
return nil
}
func getHost(ep string) string {
url, uerr := url.Parse(ep)
if uerr != nil || !strings.Contains(ep, "://") {
return ep
}
return url.Host
}

View File

@ -1,4 +1,4 @@
// Copyright 2016 CoreOS, Inc.
// Copyright 2016 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.
@ -15,18 +15,22 @@
package clientv3
import (
"crypto/tls"
"errors"
"fmt"
"io/ioutil"
"log"
"net"
"net/url"
"strings"
"sync"
"time"
"github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/metadata"
)
var (
@ -42,29 +46,23 @@ type Client struct {
Auth
Maintenance
conn *grpc.ClientConn
cfg Config
creds *credentials.TransportAuthenticator
mu sync.RWMutex // protects connection selection and error list
errors []error // errors passed to retryConnection
conn *grpc.ClientConn
cfg Config
creds *credentials.TransportCredentials
balancer *simpleBalancer
retryWrapper retryRpcFunc
ctx context.Context
cancel context.CancelFunc
// fields below are managed by connMonitor
// reconnc accepts writes which signal the client should reconnect
reconnc chan error
// newconnc is closed on successful connect and set to a fresh channel
newconnc chan struct{}
lastConnErr error
// Username is a username for authentication
Username string
// Password is a password for authentication
Password string
}
// New creates a new etcdv3 client from a given configuration.
func New(cfg Config) (*Client, error) {
if cfg.RetryDialer == nil {
cfg.RetryDialer = dialEndpointList
}
if len(cfg.Endpoints) == 0 {
return nil, ErrNoAvailableEndpoints
}
@ -88,20 +86,8 @@ func NewFromConfigFile(path string) (*Client, error) {
// Close shuts down the client's etcd connections.
func (c *Client) Close() error {
c.mu.Lock()
if c.cancel == nil {
c.mu.Unlock()
return nil
}
c.cancel()
c.cancel = nil
err := c.conn.Close()
connc := c.newconnc
c.mu.Unlock()
c.Watcher.Close()
c.Lease.Close()
<-connc
return err
return toErr(c.ctx, c.conn.Close())
}
// Ctx is a context for "out of band" messages (e.g., for sending
@ -112,76 +98,173 @@ func (c *Client) Ctx() context.Context { return c.ctx }
// Endpoints lists the registered endpoints for the client.
func (c *Client) Endpoints() []string { return c.cfg.Endpoints }
// Errors returns all errors that have been observed since called last.
func (c *Client) Errors() (errs []error) {
c.mu.Lock()
defer c.mu.Unlock()
errs = c.errors
c.errors = nil
return errs
type authTokenCredential struct {
token string
}
// Dial establishes a connection for a given endpoint using the client's config
func (c *Client) Dial(endpoint string) (*grpc.ClientConn, error) {
opts := []grpc.DialOption{
grpc.WithBlock(),
grpc.WithTimeout(c.cfg.DialTimeout),
func (cred authTokenCredential) RequireTransportSecurity() bool {
return false
}
func (cred authTokenCredential) GetRequestMetadata(ctx context.Context, s ...string) (map[string]string, error) {
return map[string]string{
"token": cred.token,
}, nil
}
func (c *Client) dialTarget(endpoint string) (proto string, host string, creds *credentials.TransportCredentials) {
proto = "tcp"
host = endpoint
creds = c.creds
url, uerr := url.Parse(endpoint)
if uerr != nil || !strings.Contains(endpoint, "://") {
return
}
if c.creds != nil {
opts = append(opts, grpc.WithTransportCredentials(*c.creds))
} else {
opts = append(opts, grpc.WithInsecure())
// strip scheme:// prefix since grpc dials by host
host = url.Host
switch url.Scheme {
case "unix":
proto = "unix"
case "http":
creds = nil
case "https":
if creds != nil {
break
}
tlsconfig := &tls.Config{}
emptyCreds := credentials.NewTLS(tlsconfig)
creds = &emptyCreds
default:
return "", "", nil
}
return
}
// dialSetupOpts gives the dial opts prior to any authentication
func (c *Client) dialSetupOpts(endpoint string, dopts ...grpc.DialOption) (opts []grpc.DialOption) {
if c.cfg.DialTimeout > 0 {
opts = []grpc.DialOption{grpc.WithTimeout(c.cfg.DialTimeout)}
}
opts = append(opts, dopts...)
// 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.
host2ep := make(map[string]string)
for i := range c.cfg.Endpoints {
_, host, _ := c.dialTarget(c.cfg.Endpoints[i])
host2ep[host] = c.cfg.Endpoints[i]
}
proto := "tcp"
if url, uerr := url.Parse(endpoint); uerr == nil && url.Scheme == "unix" {
proto = "unix"
// strip unix:// prefix so certs work
endpoint = url.Host
}
f := func(a string, t time.Duration) (net.Conn, error) {
f := func(host string, t time.Duration) (net.Conn, error) {
proto, host, _ := c.dialTarget(host2ep[host])
if proto == "" {
return nil, fmt.Errorf("unknown scheme for %q", host)
}
select {
case <-c.ctx.Done():
return nil, c.ctx.Err()
default:
}
return net.DialTimeout(proto, a, t)
return net.DialTimeout(proto, host, t)
}
opts = append(opts, grpc.WithDialer(f))
conn, err := grpc.Dial(endpoint, opts...)
_, _, creds := c.dialTarget(endpoint)
if creds != nil {
opts = append(opts, grpc.WithTransportCredentials(*creds))
} else {
opts = append(opts, grpc.WithInsecure())
}
return opts
}
// Dial connects to a single endpoint using the client's config.
func (c *Client) Dial(endpoint string) (*grpc.ClientConn, error) {
return c.dial(endpoint)
}
func (c *Client) dial(endpoint string, dopts ...grpc.DialOption) (*grpc.ClientConn, error) {
opts := c.dialSetupOpts(endpoint, dopts...)
host := getHost(endpoint)
if c.Username != "" && c.Password != "" {
// use dial options without dopts to avoid reusing the client balancer
auth, err := newAuthenticator(host, c.dialSetupOpts(endpoint))
if err != nil {
return nil, err
}
defer auth.close()
resp, err := auth.authenticate(c.ctx, c.Username, c.Password)
if err != nil {
return nil, err
}
opts = append(opts, grpc.WithPerRPCCredentials(authTokenCredential{token: resp.Token}))
}
conn, err := grpc.Dial(host, opts...)
if err != nil {
return nil, err
}
return conn, nil
}
// WithRequireLeader requires client requests to only succeed
// when the cluster has a leader.
func WithRequireLeader(ctx context.Context) context.Context {
md := metadata.Pairs(rpctypes.MetadataRequireLeaderKey, rpctypes.MetadataHasLeader)
return metadata.NewContext(ctx, md)
}
func newClient(cfg *Config) (*Client, error) {
if cfg == nil {
cfg = &Config{RetryDialer: dialEndpointList}
cfg = &Config{}
}
var creds *credentials.TransportAuthenticator
var creds *credentials.TransportCredentials
if cfg.TLS != nil {
c := credentials.NewTLS(cfg.TLS)
creds = &c
}
// use a temporary skeleton client to bootstrap first connection
ctx, cancel := context.WithCancel(context.TODO())
conn, err := cfg.RetryDialer(&Client{cfg: *cfg, creds: creds, ctx: ctx})
client := &Client{
conn: nil,
cfg: *cfg,
creds: creds,
ctx: ctx,
cancel: cancel,
}
if cfg.Username != "" && cfg.Password != "" {
client.Username = cfg.Username
client.Password = cfg.Password
}
client.balancer = newSimpleBalancer(cfg.Endpoints)
conn, err := client.dial(cfg.Endpoints[0], grpc.WithBalancer(client.balancer))
if err != nil {
return nil, err
}
client := &Client{
conn: conn,
cfg: *cfg,
creds: creds,
ctx: ctx,
cancel: cancel,
reconnc: make(chan error),
newconnc: make(chan struct{}),
}
client.conn = conn
client.retryWrapper = client.newRetryWrapper()
go client.connMonitor()
// wait for a connection
if cfg.DialTimeout > 0 {
hasConn := false
waitc := time.After(cfg.DialTimeout)
select {
case <-client.balancer.readyc:
hasConn = true
case <-ctx.Done():
case <-waitc:
}
if !hasConn {
client.cancel()
conn.Close()
return nil, grpc.ErrClientConnTimeout
}
}
client.Cluster = NewCluster(client)
client.KV = NewKV(client)
@ -200,102 +283,42 @@ func newClient(cfg *Config) (*Client, error) {
}
// ActiveConnection returns the current in-use connection
func (c *Client) ActiveConnection() *grpc.ClientConn {
c.mu.RLock()
defer c.mu.RUnlock()
return c.conn
}
// retryConnection establishes a new connection
func (c *Client) retryConnection(err error) (newConn *grpc.ClientConn, dialErr error) {
c.mu.Lock()
defer c.mu.Unlock()
if err != nil {
c.errors = append(c.errors, err)
}
if c.cancel == nil {
return nil, c.ctx.Err()
}
if c.conn != nil {
c.conn.Close()
if st, _ := c.conn.State(); st != grpc.Shutdown {
// wait so grpc doesn't leak sleeping goroutines
c.conn.WaitForStateChange(c.ctx, st)
}
}
c.conn, dialErr = c.cfg.RetryDialer(c)
if dialErr != nil {
c.errors = append(c.errors, dialErr)
}
return c.conn, dialErr
}
// connStartRetry schedules a reconnect if one is not already running
func (c *Client) connStartRetry(err error) {
select {
case c.reconnc <- err:
default:
}
}
// connWait waits for a reconnect to be processed
func (c *Client) connWait(ctx context.Context, err error) (*grpc.ClientConn, error) {
c.mu.Lock()
ch := c.newconnc
c.mu.Unlock()
c.connStartRetry(err)
select {
case <-ctx.Done():
return nil, ctx.Err()
case <-ch:
}
c.mu.Lock()
defer c.mu.Unlock()
return c.conn, c.lastConnErr
}
// connMonitor monitors the connection and handles retries
func (c *Client) connMonitor() {
var err error
for {
select {
case err = <-c.reconnc:
case <-c.ctx.Done():
c.mu.Lock()
c.lastConnErr = c.ctx.Err()
close(c.newconnc)
c.mu.Unlock()
return
}
conn, connErr := c.retryConnection(err)
c.mu.Lock()
c.lastConnErr = connErr
c.conn = conn
close(c.newconnc)
c.newconnc = make(chan struct{})
c.mu.Unlock()
}
}
// dialEndpointList attempts to connect to each endpoint in order until a
// connection is established.
func dialEndpointList(c *Client) (*grpc.ClientConn, error) {
var err error
for _, ep := range c.Endpoints() {
conn, curErr := c.Dial(ep)
if curErr != nil {
err = curErr
} else {
return conn, nil
}
}
return nil, err
}
func (c *Client) ActiveConnection() *grpc.ClientConn { return c.conn }
// isHaltErr returns true if the given error and context indicate no forward
// progress can be made, even after reconnecting.
func isHaltErr(ctx context.Context, err error) bool {
isRPCError := strings.HasPrefix(grpc.ErrorDesc(err), "etcdserver: ")
return isRPCError || ctx.Err() != nil
if ctx != nil && ctx.Err() != nil {
return true
}
if err == nil {
return false
}
eErr := rpctypes.Error(err)
if _, ok := eErr.(rpctypes.EtcdError); ok {
return eErr != rpctypes.ErrStopped && eErr != rpctypes.ErrNoLeader
}
// treat etcdserver errors not recognized by the client as halting
return isConnClosing(err) || strings.Contains(err.Error(), "etcdserver:")
}
// isConnClosing returns true if the error matches a grpc client closing error
func isConnClosing(err error) bool {
return strings.Contains(err.Error(), grpc.ErrClientConnClosing.Error())
}
func toErr(ctx context.Context, err error) error {
if err == nil {
return nil
}
err = rpctypes.Error(err)
switch {
case ctx.Err() != nil && strings.Contains(err.Error(), "context"):
err = ctx.Err()
case strings.Contains(err.Error(), ErrNoAvailableEndpoints.Error()):
err = ErrNoAvailableEndpoints
case strings.Contains(err.Error(), grpc.ErrClientConnClosing.Error()):
err = grpc.ErrClientConnClosing
}
return err
}

View File

@ -1,4 +1,4 @@
// Copyright 2016 CoreOS, Inc.
// Copyright 2016 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.
@ -19,11 +19,15 @@ import (
"testing"
"time"
"github.com/coreos/etcd/etcdserver"
"github.com/coreos/etcd/pkg/testutil"
"golang.org/x/net/context"
"google.golang.org/grpc"
)
func TestDialTimeout(t *testing.T) {
defer testutil.AfterTest(t)
donec := make(chan error)
go func() {
// without timeout, grpc keeps redialing if connection refused
@ -55,9 +59,24 @@ func TestDialTimeout(t *testing.T) {
}
}
func TestDialNoTimeout(t *testing.T) {
cfg := Config{Endpoints: []string{"127.0.0.1:12345"}}
c, err := New(cfg)
if c == nil || err != nil {
t.Fatalf("new client with DialNoWait should succeed, got %v", err)
}
c.Close()
}
func TestIsHaltErr(t *testing.T) {
if !isHaltErr(nil, fmt.Errorf("etcdserver: some etcdserver error")) {
t.Errorf(`error prefixed with "etcdserver: " should be Halted`)
t.Errorf(`error prefixed with "etcdserver: " should be Halted by default`)
}
if isHaltErr(nil, etcdserver.ErrStopped) {
t.Errorf("error %v should not halt", etcdserver.ErrStopped)
}
if isHaltErr(nil, etcdserver.ErrNoLeader) {
t.Errorf("error %v should not halt", etcdserver.ErrNoLeader)
}
ctx, cancel := context.WithCancel(context.TODO())
if isHaltErr(ctx, nil) {

View File

@ -1,4 +1,4 @@
// Copyright 2016 CoreOS, Inc.
// Copyright 2016 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.
@ -15,7 +15,6 @@
package clientv3
import (
"github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
"golang.org/x/net/context"
"google.golang.org/grpc"
@ -44,62 +43,47 @@ type Cluster interface {
}
type cluster struct {
rc *remoteClient
remote pb.ClusterClient
}
func NewCluster(c *Client) Cluster {
ret := &cluster{}
f := func(conn *grpc.ClientConn) { ret.remote = pb.NewClusterClient(conn) }
ret.rc = newRemoteClient(c, f)
return ret
return &cluster{remote: RetryClusterClient(c)}
}
func (c *cluster) MemberAdd(ctx context.Context, peerAddrs []string) (*MemberAddResponse, error) {
r := &pb.MemberAddRequest{PeerURLs: peerAddrs}
resp, err := c.getRemote().MemberAdd(ctx, r)
resp, err := c.remote.MemberAdd(ctx, r)
if err == nil {
return (*MemberAddResponse)(resp), nil
}
if isHaltErr(ctx, err) {
return nil, rpctypes.Error(err)
return nil, toErr(ctx, err)
}
c.rc.reconnect(err)
return nil, rpctypes.Error(err)
return nil, toErr(ctx, err)
}
func (c *cluster) MemberRemove(ctx context.Context, id uint64) (*MemberRemoveResponse, error) {
r := &pb.MemberRemoveRequest{ID: id}
resp, err := c.getRemote().MemberRemove(ctx, r)
resp, err := c.remote.MemberRemove(ctx, r)
if err == nil {
return (*MemberRemoveResponse)(resp), nil
}
if isHaltErr(ctx, err) {
return nil, rpctypes.Error(err)
return nil, toErr(ctx, err)
}
c.rc.reconnect(err)
return nil, rpctypes.Error(err)
return nil, toErr(ctx, err)
}
func (c *cluster) MemberUpdate(ctx context.Context, id uint64, peerAddrs []string) (*MemberUpdateResponse, error) {
// it is safe to retry on update.
for {
r := &pb.MemberUpdateRequest{ID: id, PeerURLs: peerAddrs}
resp, err := c.getRemote().MemberUpdate(ctx, r)
resp, err := c.remote.MemberUpdate(ctx, r)
if err == nil {
return (*MemberUpdateResponse)(resp), nil
}
if isHaltErr(ctx, err) {
return nil, rpctypes.Error(err)
}
if err = c.rc.reconnectWait(ctx, err); err != nil {
return nil, rpctypes.Error(err)
return nil, toErr(ctx, err)
}
}
}
@ -107,23 +91,12 @@ func (c *cluster) MemberUpdate(ctx context.Context, id uint64, peerAddrs []strin
func (c *cluster) MemberList(ctx context.Context) (*MemberListResponse, error) {
// it is safe to retry on list.
for {
resp, err := c.getRemote().MemberList(ctx, &pb.MemberListRequest{})
resp, err := c.remote.MemberList(ctx, &pb.MemberListRequest{}, grpc.FailFast(false))
if err == nil {
return (*MemberListResponse)(resp), nil
}
if isHaltErr(ctx, err) {
return nil, rpctypes.Error(err)
}
if err = c.rc.reconnectWait(ctx, err); err != nil {
return nil, rpctypes.Error(err)
return nil, toErr(ctx, err)
}
}
}
func (c *cluster) getRemote() pb.ClusterClient {
c.rc.mu.Lock()
defer c.rc.mu.Unlock()
return c.remote
}

53
clientv3/compact_op.go Normal file
View File

@ -0,0 +1,53 @@
// Copyright 2016 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 clientv3
import (
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
)
// CompactOp represents a compact operation.
type CompactOp struct {
revision int64
physical bool
}
// CompactOption configures compact operation.
type CompactOption func(*CompactOp)
func (op *CompactOp) applyCompactOpts(opts []CompactOption) {
for _, opt := range opts {
opt(op)
}
}
// OpCompact wraps slice CompactOption to create a CompactOp.
func OpCompact(rev int64, opts ...CompactOption) CompactOp {
ret := CompactOp{revision: rev}
ret.applyCompactOpts(opts)
return ret
}
func (op CompactOp) toRequest() *pb.CompactionRequest {
return &pb.CompactionRequest{Revision: op.revision, Physical: op.physical}
}
// WithCompactPhysical makes compact RPC call wait until
// the compaction is physically applied to the local database
// such that compacted entries are totally removed from the
// backend database.
func WithCompactPhysical() CompactOption {
return func(op *CompactOp) { op.physical = true }
}

View File

@ -0,0 +1,30 @@
// Copyright 2016 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 clientv3
import (
"reflect"
"testing"
"github.com/coreos/etcd/etcdserver/etcdserverpb"
)
func TestCompactOp(t *testing.T) {
req1 := OpCompact(100, WithCompactPhysical()).toRequest()
req2 := &etcdserverpb.CompactionRequest{Revision: 100, Physical: true}
if !reflect.DeepEqual(req1, req2) {
t.Fatalf("expected %+v, got %+v", req2, req1)
}
}

View File

@ -1,4 +1,4 @@
// Copyright 2016 CoreOS, Inc.
// Copyright 2016 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.

View File

@ -1,4 +1,4 @@
// Copyright 2016 CoreOS, Inc.
// Copyright 2016 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.

View File

@ -1,4 +1,4 @@
// Copyright 2016 CoreOS, Inc.
// Copyright 2016 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.
@ -16,6 +16,7 @@ package concurrency
import (
"errors"
"fmt"
v3 "github.com/coreos/etcd/clientv3"
"github.com/coreos/etcd/mvcc/mvccpb"
@ -39,7 +40,7 @@ type Election struct {
// NewElection returns a new election on a given key prefix.
func NewElection(client *v3.Client, pfx string) *Election {
return &Election{client: client, keyPrefix: pfx}
return &Election{client: client, keyPrefix: pfx + "/"}
}
// Campaign puts a value as eligible for the election. It blocks until
@ -50,22 +51,38 @@ func (e *Election) Campaign(ctx context.Context, val string) error {
return serr
}
k, rev, err := NewUniqueKV(ctx, e.client, e.keyPrefix, val, v3.WithLease(s.Lease()))
if err == nil {
err = waitDeletes(ctx, e.client, e.keyPrefix, v3.WithPrefix(), v3.WithRev(rev-1))
k := fmt.Sprintf("%s/%x", e.keyPrefix, s.Lease())
txn := e.client.Txn(ctx).If(v3.Compare(v3.CreateRevision(k), "=", 0))
txn = txn.Then(v3.OpPut(k, val, v3.WithLease(s.Lease())))
txn = txn.Else(v3.OpGet(k))
resp, err := txn.Commit()
if err != nil {
return err
}
e.leaderKey, e.leaderRev, e.leaderSession = k, resp.Header.Revision, s
if !resp.Succeeded {
kv := resp.Responses[0].GetResponseRange().Kvs[0]
e.leaderRev = kv.CreateRevision
if string(kv.Value) != val {
if err = e.Proclaim(ctx, val); err != nil {
e.Resign(ctx)
return err
}
}
}
err = waitDeletes(ctx, e.client, e.keyPrefix, v3.WithPrefix(), v3.WithRev(e.leaderRev-1))
if err != nil {
// clean up in case of context cancel
select {
case <-ctx.Done():
e.client.Delete(e.client.Ctx(), k)
e.Resign(e.client.Ctx())
default:
e.leaderSession = nil
}
return err
}
e.leaderKey, e.leaderRev, e.leaderSession = k, rev, s
return nil
}
@ -89,19 +106,19 @@ func (e *Election) Proclaim(ctx context.Context, val string) error {
}
// Resign lets a leader start a new election.
func (e *Election) Resign() (err error) {
func (e *Election) Resign(ctx context.Context) (err error) {
if e.leaderSession == nil {
return nil
}
_, err = e.client.Delete(e.client.Ctx(), e.leaderKey)
_, err = e.client.Delete(ctx, e.leaderKey)
e.leaderKey = ""
e.leaderSession = nil
return err
}
// Leader returns the leader value for the current election.
func (e *Election) Leader() (string, error) {
resp, err := e.client.Get(e.client.Ctx(), e.keyPrefix, v3.WithFirstCreate()...)
func (e *Election) Leader(ctx context.Context) (string, error) {
resp, err := e.client.Get(ctx, e.keyPrefix, v3.WithFirstCreate()...)
if err != nil {
return "", err
} else if len(resp.Kvs) == 0 {

View File

@ -1,4 +1,4 @@
// Copyright 2016 CoreOS, Inc.
// Copyright 2016 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.
@ -17,34 +17,12 @@ package concurrency
import (
"fmt"
"math"
"time"
v3 "github.com/coreos/etcd/clientv3"
"github.com/coreos/etcd/mvcc/mvccpb"
"golang.org/x/net/context"
)
// NewUniqueKey creates a new key from a given prefix.
func NewUniqueKey(ctx context.Context, kv v3.KV, pfx string, opts ...v3.OpOption) (string, int64, error) {
return NewUniqueKV(ctx, kv, pfx, "", opts...)
}
func NewUniqueKV(ctx context.Context, kv v3.KV, pfx, val string, opts ...v3.OpOption) (string, int64, error) {
for {
newKey := fmt.Sprintf("%s/%v", pfx, time.Now().UnixNano())
put := v3.OpPut(newKey, val, opts...)
cmp := v3.Compare(v3.ModRevision(newKey), "=", 0)
resp, err := kv.Txn(ctx).If(cmp).Then(put).Commit()
if err != nil {
return "", 0, err
}
if !resp.Succeeded {
continue
}
return newKey, resp.Header.Revision, nil
}
}
func waitDelete(ctx context.Context, client *v3.Client, key string, rev int64) error {
cctx, cancel := context.WithCancel(ctx)
defer cancel()

View File

@ -1,4 +1,4 @@
// Copyright 2016 CoreOS, Inc.
// Copyright 2016 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.
@ -32,7 +32,7 @@ type Mutex struct {
}
func NewMutex(client *v3.Client, pfx string) *Mutex {
return &Mutex{client, pfx, "", -1}
return &Mutex{client, pfx + "/", "", -1}
}
// Lock locks the mutex with a cancellable context. If the context is cancelled
@ -43,7 +43,7 @@ func (m *Mutex) Lock(ctx context.Context) error {
return serr
}
m.myKey = fmt.Sprintf("%s/%x", m.pfx, s.Lease())
m.myKey = fmt.Sprintf("%s%x", m.pfx, s.Lease())
cmp := v3.Compare(v3.CreateRevision(m.myKey), "=", 0)
// put self in lock waiters via myKey; oldest waiter holds lock
put := v3.OpPut(m.myKey, "", v3.WithLease(s.Lease()))
@ -63,14 +63,14 @@ func (m *Mutex) Lock(ctx context.Context) error {
// release lock key if cancelled
select {
case <-ctx.Done():
m.Unlock()
m.Unlock(m.client.Ctx())
default:
}
return err
}
func (m *Mutex) Unlock() error {
if _, err := m.client.Delete(m.client.Ctx(), m.myKey); err != nil {
func (m *Mutex) Unlock(ctx context.Context) error {
if _, err := m.client.Delete(ctx, m.myKey); err != nil {
return err
}
m.myKey = "\x00"
@ -92,7 +92,7 @@ func (lm *lockerMutex) Lock() {
}
}
func (lm *lockerMutex) Unlock() {
if err := lm.Mutex.Unlock(); err != nil {
if err := lm.Mutex.Unlock(lm.client.Ctx()); err != nil {
panic(err)
}
}

View File

@ -1,4 +1,4 @@
// Copyright 2016 CoreOS, Inc.
// Copyright 2016 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.

View File

@ -1,4 +1,4 @@
// Copyright 2016 CoreOS, Inc.
// Copyright 2016 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.
@ -56,6 +56,12 @@ func NewSTMSerializable(ctx context.Context, c *v3.Client, apply func(STM) error
return runSTM(s, apply)
}
// NewSTMReadCommitted initiates a new read committed transaction.
func NewSTMReadCommitted(ctx context.Context, c *v3.Client, apply func(STM) error) (*v3.TxnResponse, error) {
s := &stmReadCommitted{stm{client: c, ctx: ctx, getOpts: []v3.OpOption{v3.WithSerializable()}}}
return runSTM(s, apply)
}
type stmResponse struct {
resp *v3.TxnResponse
err error
@ -139,11 +145,12 @@ func (s *stm) commit() *v3.TxnResponse {
}
// cmps guards the txn from updates to read set
func (s *stm) cmps() (cmps []v3.Cmp) {
func (s *stm) cmps() []v3.Cmp {
cmps := make([]v3.Cmp, 0, len(s.rset))
for k, rk := range s.rset {
cmps = append(cmps, isKeyCurrent(k, rk))
}
return
return cmps
}
func (s *stm) fetch(key string) *v3.GetResponse {
@ -159,11 +166,12 @@ func (s *stm) fetch(key string) *v3.GetResponse {
}
// puts is the list of ops for all pending writes
func (s *stm) puts() (puts []v3.Op) {
func (s *stm) puts() []v3.Op {
puts := make([]v3.Op, 0, len(s.wset))
for _, v := range s.wset {
puts = append(puts, v.op)
}
return
return puts
}
func (s *stm) reset() {
@ -201,12 +209,14 @@ func (s *stmSerializable) Rev(key string) int64 {
return s.stm.Rev(key)
}
func (s *stmSerializable) gets() (keys []string, ops []v3.Op) {
func (s *stmSerializable) gets() ([]string, []v3.Op) {
keys := make([]string, 0, len(s.rset))
ops := make([]v3.Op, 0, len(s.rset))
for k := range s.rset {
keys = append(keys, k)
ops = append(ops, v3.OpGet(k))
}
return
return keys, ops
}
func (s *stmSerializable) commit() *v3.TxnResponse {
@ -230,6 +240,14 @@ func (s *stmSerializable) commit() *v3.TxnResponse {
return nil
}
type stmReadCommitted struct{ stm }
// commit always goes through when read committed
func (s *stmReadCommitted) commit() *v3.TxnResponse {
s.rset = nil
return s.stm.commit()
}
func isKeyCurrent(k string, r *v3.GetResponse) v3.Cmp {
rev := r.Header.Revision + 1
if len(r.Kvs) != 0 {

View File

@ -1,4 +1,4 @@
// Copyright 2016 CoreOS, Inc.
// Copyright 2016 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.
@ -22,19 +22,12 @@ import (
"github.com/coreos/etcd/pkg/tlsutil"
"github.com/ghodss/yaml"
"google.golang.org/grpc"
)
// EndpointDialer is a policy for choosing which endpoint to dial next
type EndpointDialer func(*Client) (*grpc.ClientConn, error)
type Config struct {
// Endpoints is a list of URLs
Endpoints []string
// RetryDialer chooses the next endpoint to use
RetryDialer EndpointDialer
// DialTimeout is the timeout for failing to establish a connection.
DialTimeout time.Duration
@ -43,6 +36,12 @@ type Config struct {
// Logger is the logger used by client library.
Logger Logger
// Username is a username for authentication
Username string
// Password is a password for authentication
Password string
}
type yamlConfig struct {

View File

@ -1,4 +1,4 @@
// Copyright 2016 CoreOS, Inc.
// Copyright 2016 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.

View File

@ -1,4 +1,4 @@
// Copyright 2016 CoreOS, Inc.
// Copyright 2016 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.

View File

@ -0,0 +1,99 @@
// Copyright 2016 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 clientv3_test
import (
"fmt"
"log"
"github.com/coreos/etcd/clientv3"
"golang.org/x/net/context"
)
func ExampleAuth() {
cli, err := clientv3.New(clientv3.Config{
Endpoints: endpoints,
DialTimeout: dialTimeout,
})
if err != nil {
log.Fatal(err)
}
defer cli.Close()
authapi := clientv3.NewAuth(cli)
if _, err = authapi.RoleAdd(context.TODO(), "root"); err != nil {
log.Fatal(err)
}
if _, err = authapi.RoleGrantPermission(
context.TODO(),
"root", // role name
"foo", // key
"zoo", // range end
clientv3.PermissionType(clientv3.PermReadWrite),
); err != nil {
log.Fatal(err)
}
if _, err = authapi.UserAdd(context.TODO(), "root", "123"); err != nil {
log.Fatal(err)
}
if _, err = authapi.UserGrantRole(context.TODO(), "root", "root"); err != nil {
log.Fatal(err)
}
if _, err = authapi.AuthEnable(context.TODO()); err != nil {
log.Fatal(err)
}
cliAuth, err := clientv3.New(clientv3.Config{
Endpoints: endpoints,
DialTimeout: dialTimeout,
Username: "root",
Password: "123",
})
if err != nil {
log.Fatal(err)
}
defer cliAuth.Close()
kv := clientv3.NewKV(cliAuth)
if _, err = kv.Put(context.TODO(), "foo1", "bar"); err != nil {
log.Fatal(err)
}
_, err = kv.Txn(context.TODO()).
If(clientv3.Compare(clientv3.Value("zoo1"), ">", "abc")).
Then(clientv3.OpPut("zoo1", "XYZ")).
Else(clientv3.OpPut("zoo1", "ABC")).
Commit()
fmt.Println(err)
// now check the permission
authapi2 := clientv3.NewAuth(cliAuth)
resp, err := authapi2.RoleGet(context.TODO(), "root")
if err != nil {
log.Fatal(err)
}
fmt.Printf("root user permission: key %q, range end %q\n", resp.Perm[0].Key, resp.Perm[0].RangeEnd)
if _, err = authapi2.AuthDisable(context.TODO()); err != nil {
log.Fatal(err)
}
// Output: etcdserver: permission denied
// root user permission: key "foo", range end "zoo"
}

View File

@ -1,4 +1,4 @@
// Copyright 2016 CoreOS, Inc.
// Copyright 2016 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.

View File

@ -1,4 +1,4 @@
// Copyright 2016 CoreOS, Inc.
// Copyright 2016 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.
@ -210,7 +210,7 @@ func ExampleKV_compact() {
compRev := resp.Header.Revision // specify compact revision of your choice
ctx, cancel = context.WithTimeout(context.Background(), requestTimeout)
err = cli.Compact(ctx, compRev)
_, err = cli.Compact(ctx, compRev)
cancel()
if err != nil {
log.Fatal(err)

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