Skip to content

Commit 61eebff

Browse files
authored
Merge pull request #65 from arangodb/server-mode
Server mode (get/set)
2 parents 4867402 + 11f997e commit 61eebff

File tree

8 files changed

+403
-0
lines changed

8 files changed

+403
-0
lines changed

client.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ type Client interface {
5252

5353
// User functions
5454
ClientUsers
55+
56+
// Server/cluster administration functions
57+
ClientServerAdmin
5558
}
5659

5760
// ClientConfig contains all settings needed to create a client.

client_server_admin.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2017 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
// Author Ewout Prangsma
21+
//
22+
23+
package driver
24+
25+
import "context"
26+
27+
// ClientServerAdmin provides access to server administrations functions of an arangodb database server
28+
// or an entire cluster of arangodb servers.
29+
type ClientServerAdmin interface {
30+
// ServerMode returns the current mode in which the server/cluster is operating.
31+
// This call needs ArangoDB 3.3 and up.
32+
ServerMode(ctx context.Context) (ServerMode, error)
33+
// SetServerMode changes the current mode in which the server/cluster is operating.
34+
// This call needs a client that uses JWT authentication.
35+
// This call needs ArangoDB 3.3 and up.
36+
SetServerMode(ctx context.Context, mode ServerMode) error
37+
}
38+
39+
type ServerMode string
40+
41+
const (
42+
// ServerModeDefault is the normal mode of the database in which read and write requests
43+
// are allowed.
44+
ServerModeDefault ServerMode = "default"
45+
// ServerModeReadOnly is the mode in which all modifications to th database are blocked.
46+
// Behavior is the same as user that has read-only access to all databases & collections.
47+
ServerModeReadOnly ServerMode = "readonly"
48+
)

client_server_admin_impl.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2017 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
// Author Ewout Prangsma
21+
//
22+
23+
package driver
24+
25+
import (
26+
"context"
27+
)
28+
29+
type serverModeResponse struct {
30+
Mode ServerMode `json:"mode"`
31+
}
32+
33+
type serverModeRequest struct {
34+
Mode ServerMode `json:"mode"`
35+
}
36+
37+
// ServerMode returns the current mode in which the server/cluster is operating.
38+
// This call needs ArangoDB 3.3 and up.
39+
func (c *client) ServerMode(ctx context.Context) (ServerMode, error) {
40+
req, err := c.conn.NewRequest("GET", "_admin/server/mode")
41+
if err != nil {
42+
return "", WithStack(err)
43+
}
44+
resp, err := c.conn.Do(ctx, req)
45+
if err != nil {
46+
return "", WithStack(err)
47+
}
48+
if err := resp.CheckStatus(200); err != nil {
49+
return "", WithStack(err)
50+
}
51+
var result serverModeResponse
52+
if err := resp.ParseBody("", &result); err != nil {
53+
return "", WithStack(err)
54+
}
55+
return result.Mode, nil
56+
}
57+
58+
// SetServerMode changes the current mode in which the server/cluster is operating.
59+
// This call needs a client that uses JWT authentication.
60+
// This call needs ArangoDB 3.3 and up.
61+
func (c *client) SetServerMode(ctx context.Context, mode ServerMode) error {
62+
req, err := c.conn.NewRequest("PUT", "_admin/server/mode")
63+
if err != nil {
64+
return WithStack(err)
65+
}
66+
input := serverModeRequest{
67+
Mode: mode,
68+
}
69+
req, err = req.SetBody(input)
70+
if err != nil {
71+
return WithStack(err)
72+
}
73+
resp, err := c.conn.Do(ctx, req)
74+
if err != nil {
75+
return WithStack(err)
76+
}
77+
if err := resp.CheckStatus(200); err != nil {
78+
return WithStack(err)
79+
}
80+
return nil
81+
}

context.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ const (
5252
keyIsSystem ContextKey = "arangodb-isSystem"
5353
keyIgnoreRevs ContextKey = "arangodb-ignoreRevs"
5454
keyEnforceReplicationFactor ContextKey = "arangodb-enforceReplicationFactor"
55+
keyConfigured ContextKey = "arangodb-configured"
5556
)
5657

5758
// WithRevision is used to configure a context to make document
@@ -181,6 +182,16 @@ func WithEnforceReplicationFactor(parent context.Context, value bool) context.Co
181182
return context.WithValue(contextOrBackground(parent), keyEnforceReplicationFactor, value)
182183
}
183184

185+
// WithConfigured is used to configure a context to return the configured value of
186+
// a user grant instead of the effective grant.
187+
func WithConfigured(parent context.Context, value ...bool) context.Context {
188+
v := true
189+
if len(value) == 1 {
190+
v = value[0]
191+
}
192+
return context.WithValue(contextOrBackground(parent), keyConfigured, v)
193+
}
194+
184195
type contextSettings struct {
185196
Silent bool
186197
WaitForSync bool
@@ -193,6 +204,7 @@ type contextSettings struct {
193204
IsSystem bool
194205
IgnoreRevs *bool
195206
EnforceReplicationFactor *bool
207+
Configured *bool
196208
}
197209

198210
// applyContextSettings returns the settings configured in the context in the given request.
@@ -293,6 +305,13 @@ func applyContextSettings(ctx context.Context, req Request) contextSettings {
293305
result.EnforceReplicationFactor = &enforceReplicationFactor
294306
}
295307
}
308+
// Configured
309+
if v := ctx.Value(keyConfigured); v != nil {
310+
if configured, ok := v.(bool); ok {
311+
req.SetQuery("configured", strconv.FormatBool(configured))
312+
result.Configured = &configured
313+
}
314+
}
296315
return result
297316
}
298317

test/server_mode_auth_test.go

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2017 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
// Author Ewout Prangsma
21+
//
22+
23+
// +build auth
24+
25+
package test
26+
27+
import (
28+
"context"
29+
"testing"
30+
31+
driver "github.com/arangodb/go-driver"
32+
)
33+
34+
// TestServerModeAndGrants checks user access grants in combination with
35+
// server mode and WithConfigured.
36+
func TestServerModeAndGrants(t *testing.T) {
37+
c := createClientFromEnv(t, true)
38+
ctx := context.Background()
39+
40+
version, err := c.Version(nil)
41+
if err != nil {
42+
t.Fatalf("Version failed: %s", describe(err))
43+
}
44+
isv33p := version.Version.CompareTo("3.3") >= 0
45+
if !isv33p {
46+
t.Skip("This test requires version 3.3")
47+
} else {
48+
// Get root user
49+
u, err := c.User(ctx, "root")
50+
if err != nil {
51+
t.Fatalf("User('root') failed: %s", describe(err))
52+
}
53+
54+
// Initial server mode must be default
55+
if mode, err := c.ServerMode(ctx); err != nil {
56+
t.Fatalf("ServerMode failed: %s", describe(err))
57+
} else if mode != driver.ServerModeDefault {
58+
t.Errorf("ServerMode returned '%s', but expected '%s'", mode, driver.ServerModeDefault)
59+
}
60+
61+
// Create simple collection
62+
db := ensureDatabase(ctx, c, "_system", nil, t)
63+
colName := "server_mode_and_grants_test1"
64+
col := ensureCollection(ctx, db, colName, nil, t)
65+
66+
// Get database & collection access
67+
defaultDBAccess, err := u.GetDatabaseAccess(ctx, db)
68+
if err != nil {
69+
t.Fatalf("GetDatabaseAccess failed: %s", describe(err))
70+
}
71+
defaultColAccess, err := u.GetCollectionAccess(ctx, col)
72+
if err != nil {
73+
t.Fatalf("GetCollectionAccess failed: %s", describe(err))
74+
}
75+
76+
// Get database & collection access using WithConfigured
77+
if grant, err := u.GetDatabaseAccess(driver.WithConfigured(ctx), db); err != nil {
78+
t.Fatalf("GetDatabaseAccess(WithConfigured) failed: %s", describe(err))
79+
} else if grant != defaultDBAccess {
80+
t.Errorf("Database access using WithConfigured differs, got '%s', expected '%s'", grant, defaultDBAccess)
81+
}
82+
if grant, err := u.GetCollectionAccess(driver.WithConfigured(ctx), col); err != nil {
83+
t.Fatalf("GetCollectionAccess(WithConfigured) failed: %s", describe(err))
84+
} else if grant != defaultDBAccess {
85+
t.Errorf("Collection access using WithConfigured differs, got '%s', expected '%s'", grant, defaultColAccess)
86+
}
87+
88+
// Change server mode to readonly.
89+
if err := c.SetServerMode(ctx, driver.ServerModeReadOnly); err != nil {
90+
t.Fatalf("SetServerMode failed: %s", describe(err))
91+
}
92+
93+
// Check server mode, must be readonly
94+
if mode, err := c.ServerMode(ctx); err != nil {
95+
t.Fatalf("ServerMode failed: %s", describe(err))
96+
} else if mode != driver.ServerModeReadOnly {
97+
t.Errorf("ServerMode returned '%s', but expected '%s'", mode, driver.ServerModeReadOnly)
98+
}
99+
100+
// Get database & collection access now (must be readonly)
101+
if grant, err := u.GetDatabaseAccess(ctx, db); err != nil {
102+
t.Fatalf("GetDatabaseAccess failed: %s", describe(err))
103+
} else if grant != driver.GrantReadOnly {
104+
t.Errorf("Database access must be readonly, got '%s'", grant)
105+
}
106+
if grant, err := u.GetCollectionAccess(ctx, col); err != nil {
107+
t.Fatalf("GetCollectionAccess failed: %s", describe(err))
108+
} else if grant != driver.GrantReadOnly {
109+
t.Errorf("Collection access must be readonly, got '%s'", grant)
110+
}
111+
112+
// Get database & collection access using WithConfigured (must be same as before)
113+
if grant, err := u.GetDatabaseAccess(driver.WithConfigured(ctx), db); err != nil {
114+
t.Fatalf("GetDatabaseAccess(WithConfigured) failed: %s", describe(err))
115+
} else if grant != defaultDBAccess {
116+
t.Errorf("Database access using WithConfigured differs, got '%s', expected '%s'", grant, defaultDBAccess)
117+
}
118+
if grant, err := u.GetCollectionAccess(driver.WithConfigured(ctx), col); err != nil {
119+
t.Fatalf("GetCollectionAccess(WithConfigured) failed: %s", describe(err))
120+
} else if grant != defaultDBAccess {
121+
t.Errorf("Collection access using WithConfigured differs, got '%s', expected '%s'", grant, defaultColAccess)
122+
}
123+
124+
// Change server mode back to default.
125+
if err := c.SetServerMode(ctx, driver.ServerModeDefault); err != nil {
126+
t.Fatalf("SetServerMode failed: %s", describe(err))
127+
}
128+
129+
// Initial server mode must be default
130+
if mode, err := c.ServerMode(ctx); err != nil {
131+
t.Fatalf("ServerMode failed: %s", describe(err))
132+
} else if mode != driver.ServerModeDefault {
133+
t.Errorf("ServerMode returned '%s', but expected '%s'", mode, driver.ServerModeDefault)
134+
}
135+
136+
// Get database & collection access (must now be same as before)
137+
if grant, err := u.GetDatabaseAccess(ctx, db); err != nil {
138+
t.Fatalf("GetDatabaseAccess failed: %s", describe(err))
139+
} else if grant != defaultDBAccess {
140+
t.Errorf("Database access differs, got '%s', expected '%s'", grant, defaultDBAccess)
141+
}
142+
if grant, err := u.GetCollectionAccess(ctx, col); err != nil {
143+
t.Fatalf("GetCollectionAccess failed: %s", describe(err))
144+
} else if grant != defaultDBAccess {
145+
t.Errorf("Collection access differs, got '%s', expected '%s'", grant, defaultColAccess)
146+
}
147+
148+
// Get database & collection access with WithConfigured (must now be same as before)
149+
if grant, err := u.GetDatabaseAccess(driver.WithConfigured(ctx), db); err != nil {
150+
t.Fatalf("GetDatabaseAccess(WithConfigured) failed: %s", describe(err))
151+
} else if grant != defaultDBAccess {
152+
t.Errorf("Database access using WithConfigured differs, got '%s', expected '%s'", grant, defaultDBAccess)
153+
}
154+
if grant, err := u.GetCollectionAccess(driver.WithConfigured(ctx), col); err != nil {
155+
t.Fatalf("GetCollectionAccess(WithConfigured) failed: %s", describe(err))
156+
} else if grant != defaultDBAccess {
157+
t.Errorf("Collection access using WithConfigured differs, got '%s', expected '%s'", grant, defaultColAccess)
158+
}
159+
}
160+
}

0 commit comments

Comments
 (0)