Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
ce63f10738 | |||
31bd750141 | |||
37510d0306 | |||
d7da3787bc | |||
54d0f1d43b | |||
20db10f6f7 | |||
11c09373e1 | |||
96f412e4d7 | |||
2b67f5256a | |||
6aa8b631e6 | |||
72dea51e6a | |||
74fa0270a4 |
@ -137,12 +137,15 @@ curl -L http://127.0.0.1:2379/version
|
||||
|
||||
The `v2` API responses should not change after the 2.0.0 release but new features will be added over time.
|
||||
|
||||
#### 32-bit systems
|
||||
#### 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 producing an unstable etcd server, 32-bit builds emit an `etcd` that prints
|
||||
a warning message and immediately exits.
|
||||
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
|
||||
|
||||
|
@ -36,6 +36,12 @@ type User struct {
|
||||
Revoke []string `json:"revoke,omitempty"`
|
||||
}
|
||||
|
||||
// userListEntry is the user representation given by the server for ListUsers
|
||||
type userListEntry struct {
|
||||
User string `json:"user"`
|
||||
Roles []Role `json:"roles"`
|
||||
}
|
||||
|
||||
type UserRoles struct {
|
||||
User string `json:"user"`
|
||||
Roles []Role `json:"roles"`
|
||||
@ -198,7 +204,7 @@ func (u *httpAuthUserAPI) ListUsers(ctx context.Context) ([]string, error) {
|
||||
}
|
||||
|
||||
var userList struct {
|
||||
Users []User `json:"users"`
|
||||
Users []userListEntry `json:"users"`
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(body, &userList); err != nil {
|
||||
|
@ -342,7 +342,9 @@ func (c *httpClusterClient) Do(ctx context.Context, act httpAction) (*http.Respo
|
||||
resp, body, err = hc.Do(ctx, action)
|
||||
if err != nil {
|
||||
cerr.Errors = append(cerr.Errors, err)
|
||||
// mask previous errors with context error, which is controlled by user
|
||||
if err == ctx.Err() {
|
||||
return nil, nil, ctx.Err()
|
||||
}
|
||||
if err == context.Canceled || err == context.DeadlineExceeded {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@ -295,7 +295,7 @@ func TestSimpleHTTPClientDoHeaderTimeout(t *testing.T) {
|
||||
t.Fatalf("expected non-nil error, got nil")
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
t.Fatalf("unexpected timeout when waitting for the test to finish")
|
||||
t.Fatalf("unexpected timeout when waiting for the test to finish")
|
||||
}
|
||||
}
|
||||
|
||||
@ -444,7 +444,51 @@ func TestHTTPClusterClientDoDeadlineExceedContext(t *testing.T) {
|
||||
t.Errorf("err = %+v, want %+v", err, context.DeadlineExceeded)
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
t.Fatalf("unexpected timeout when waitting for request to deadline exceed")
|
||||
t.Fatalf("unexpected timeout when waiting for request to deadline exceed")
|
||||
}
|
||||
}
|
||||
|
||||
type fakeCancelContext struct{}
|
||||
|
||||
var fakeCancelContextError = errors.New("fake context canceled")
|
||||
|
||||
func (f fakeCancelContext) Deadline() (time.Time, bool) { return time.Time{}, false }
|
||||
func (f fakeCancelContext) Done() <-chan struct{} {
|
||||
d := make(chan struct{}, 1)
|
||||
d <- struct{}{}
|
||||
return d
|
||||
}
|
||||
func (f fakeCancelContext) Err() error { return fakeCancelContextError }
|
||||
func (f fakeCancelContext) Value(key interface{}) interface{} { return 1 }
|
||||
|
||||
func withTimeout(parent context.Context, timeout time.Duration) (context.Context, context.CancelFunc) {
|
||||
return parent, func() { parent = nil }
|
||||
}
|
||||
|
||||
func TestHTTPClusterClientDoCanceledContext(t *testing.T) {
|
||||
fakeURL := url.URL{}
|
||||
tr := newFakeTransport()
|
||||
tr.finishCancel <- struct{}{}
|
||||
c := &httpClusterClient{
|
||||
clientFactory: newHTTPClientFactory(tr, DefaultCheckRedirect, 0),
|
||||
endpoints: []url.URL{fakeURL},
|
||||
}
|
||||
|
||||
errc := make(chan error)
|
||||
go func() {
|
||||
ctx, cancel := withTimeout(fakeCancelContext{}, time.Millisecond)
|
||||
cancel()
|
||||
_, _, err := c.Do(ctx, &fakeAction{})
|
||||
errc <- err
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-errc:
|
||||
if err != fakeCancelContextError {
|
||||
t.Errorf("err = %+v, want %+v", err, fakeCancelContextError)
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
t.Fatalf("unexpected timeout when waiting for request to fake context canceled")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -185,9 +185,18 @@ func testCtlV2GetRoleUser(t *testing.T, cfg *etcdProcessClusterConfig) {
|
||||
if err := etcdctlUserGet(epc, "username"); err != nil {
|
||||
t.Fatalf("failed to get user (%v)", err)
|
||||
}
|
||||
// ensure double grant gives an error; was crashing in 2.3.1
|
||||
regrantArgs := etcdctlPrefixArgs(epc)
|
||||
regrantArgs = append(regrantArgs, "user", "grant", "--roles", "foo", "username")
|
||||
if err := spawnWithExpect(regrantArgs, "duplicate"); err != nil {
|
||||
t.Fatalf("missing duplicate error on double grant role (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCtlV2UserList(t *testing.T) {
|
||||
func TestCtlV2UserListUsername(t *testing.T) { testCtlV2UserList(t, "username") }
|
||||
func TestCtlV2UserListRoot(t *testing.T) { testCtlV2UserList(t, "root") }
|
||||
|
||||
func testCtlV2UserList(t *testing.T, username string) {
|
||||
defer testutil.AfterTest(t)
|
||||
|
||||
epc := setupEtcdctlTest(t, &configWithProxy, false)
|
||||
@ -197,10 +206,10 @@ func TestCtlV2UserList(t *testing.T) {
|
||||
}
|
||||
}()
|
||||
|
||||
if err := etcdctlUserAdd(epc, "username", "password"); err != nil {
|
||||
if err := etcdctlUserAdd(epc, username, "password"); err != nil {
|
||||
t.Fatalf("failed to add user (%v)", err)
|
||||
}
|
||||
if err := etcdctlUserList(epc, "username"); err != nil {
|
||||
if err := etcdctlUserList(epc, username); err != nil {
|
||||
t.Fatalf("failed to list users (%v)", err)
|
||||
}
|
||||
}
|
||||
|
@ -17,8 +17,6 @@ package command
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/coreos/etcd/Godeps/_workspace/src/github.com/bgentry/speakeasy"
|
||||
@ -195,21 +193,12 @@ func userGrantRevoke(c *cli.Context, grant bool) {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var newUser *client.User
|
||||
if grant {
|
||||
newUser, err = api.GrantUser(ctx, user, roles)
|
||||
_, err = api.GrantUser(ctx, user, roles)
|
||||
} else {
|
||||
newUser, err = api.RevokeUser(ctx, user, roles)
|
||||
}
|
||||
sort.Strings(newUser.Roles)
|
||||
sort.Strings(currentUser.Roles)
|
||||
if reflect.DeepEqual(newUser.Roles, currentUser.Roles) {
|
||||
if grant {
|
||||
fmt.Printf("User unchanged; roles already granted")
|
||||
} else {
|
||||
fmt.Printf("User unchanged; roles already revoked")
|
||||
}
|
||||
_, err = api.RevokeUser(ctx, user, roles)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
|
@ -12,9 +12,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// TODO: support arm64
|
||||
// +build amd64
|
||||
|
||||
package etcdmain
|
||||
|
||||
import (
|
||||
@ -79,6 +76,8 @@ var (
|
||||
)
|
||||
|
||||
func Main() {
|
||||
checkSupportArch()
|
||||
|
||||
cfg := NewConfig()
|
||||
err := cfg.Parse(os.Args[1:])
|
||||
if err != nil {
|
||||
@ -554,3 +553,16 @@ func setupLogging(cfg *config) {
|
||||
repoLog.SetLogLevel(settings)
|
||||
}
|
||||
}
|
||||
|
||||
func checkSupportArch() {
|
||||
// TODO qualify arm64
|
||||
if runtime.GOARCH == "amd64" {
|
||||
return
|
||||
}
|
||||
if env, ok := os.LookupEnv("ETCD_UNSUPPORTED_ARCH"); ok && env == runtime.GOARCH {
|
||||
plog.Warningf("running etcd on unsupported architecture %q since ETCD_UNSUPPORTED_ARCH is set", env)
|
||||
return
|
||||
}
|
||||
plog.Errorf("etcd on unsupported platform without ETCD_UNSUPPORTED_ARCH=%s set.", runtime.GOARCH)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
@ -1,31 +0,0 @@
|
||||
// Copyright 2016 CoreOS, Inc.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// +build !amd64
|
||||
|
||||
package etcdmain
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/coreos/etcd/Godeps/_workspace/src/github.com/coreos/pkg/capnslog"
|
||||
)
|
||||
|
||||
var plog = capnslog.NewPackageLogger("github.com/coreos/etcd", "etcdmain")
|
||||
|
||||
func Main() {
|
||||
fmt.Println("unsupported architecture; unreliable, unstable")
|
||||
os.Exit(-1)
|
||||
}
|
@ -71,6 +71,7 @@ func getClusterFromRemotePeers(urls []string, timeout time.Duration, logerr bool
|
||||
continue
|
||||
}
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
if logerr {
|
||||
plog.Warningf("could not read the body of cluster response: %v", err)
|
||||
|
@ -142,11 +142,23 @@ func startPeer(transport *Transport, urls types.URLs, local, to, cid types.ID, r
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case mm := <-p.propc:
|
||||
case mm := <-p.recvc:
|
||||
if err := r.Process(ctx, mm); err != nil {
|
||||
plog.Warningf("failed to process raft message (%v)", err)
|
||||
}
|
||||
case mm := <-p.recvc:
|
||||
case <-p.stopc:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// r.Process might block for processing proposal when there is no leader.
|
||||
// Thus propc must be put into a separate routine with recvc to avoid blocking
|
||||
// processing other raft messages.
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case mm := <-p.propc:
|
||||
if err := r.Process(ctx, mm); err != nil {
|
||||
plog.Warningf("failed to process raft message (%v)", err)
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ import (
|
||||
var (
|
||||
// MinClusterVersion is the min cluster version this etcd binary is compatible with.
|
||||
MinClusterVersion = "2.2.0"
|
||||
Version = "2.3.0"
|
||||
Version = "2.3.2"
|
||||
|
||||
// Git SHA Value will be set during build
|
||||
GitSHA = "Not provided (use ./build instead of go build)"
|
||||
|
Reference in New Issue
Block a user