Skip to content

Commit 9df5aa7

Browse files
authored
CLOUDP-57839: Create db users, C/OM (#54)
1 parent bc55ca2 commit 9df5aa7

24 files changed

+329
-79
lines changed

internal/cli/atlas_dbusers_create.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ func (opts *atlasDBUsersCreateOpts) Run() error {
5959
func (opts *atlasDBUsersCreateOpts) newDatabaseUser() *atlas.DatabaseUser {
6060
return &atlas.DatabaseUser{
6161
DatabaseName: convert.AdminDB,
62-
Roles: convert.BuildRoles(opts.roles),
62+
Roles: convert.BuildAtlasRoles(opts.roles),
6363
GroupID: opts.ProjectID(),
6464
Username: opts.username,
6565
Password: opts.password,

internal/cli/atlas_dbusers_update.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func (opts *atlasDBUsersUpdateOpts) update(out *atlas.DatabaseUser) {
6363
out.Password = opts.password
6464
}
6565

66-
out.Roles = convert.BuildRoles(opts.roles)
66+
out.Roles = convert.BuildAtlasRoles(opts.roles)
6767
}
6868

6969
// mongocli atlas dbuser(s) update username [--password password] [--role roleName@dbName] [--projectId projectId]

internal/cli/cloud_manager.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ func CloudManagerBuilder() *cobra.Command {
3030
cmd.AddCommand(AtlasBackupsBuilder())
3131
cmd.AddCommand(OpsManagerServersBuilder())
3232
cmd.AddCommand(OpsManagerAutomationBuilder())
33+
cmd.AddCommand(OpsManagerDBUsersCreateBuilder())
3334

3435
return cmd
3536
}

internal/cli/cloud_manager_clusters_apply.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ type cmClustersApplyOpts struct {
3232
*globalOpts
3333
filename string
3434
fs afero.Fs
35-
store store.AutomationStore
35+
store store.AutomationPatcher
3636
}
3737

3838
func (opts *cmClustersApplyOpts) init() error {

internal/cli/cloud_manager_clusters_apply_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import (
2525

2626
func TestCloudManagerClustersApply_Run(t *testing.T) {
2727
ctrl := gomock.NewController(t)
28-
mockStore := mocks.NewMockAutomationStore(ctrl)
28+
mockStore := mocks.NewMockAutomationPatcher(ctrl)
2929

3030
defer ctrl.Finish()
3131

internal/cli/cloud_manager_clusters_create.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ type cmClustersCreateOpts struct {
3333
*globalOpts
3434
filename string
3535
fs afero.Fs
36-
store store.AutomationStore
36+
store store.AutomationPatcher
3737
}
3838

3939
func (opts *cmClustersCreateOpts) init() error {

internal/cli/cloud_manager_clusters_list.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func cloudManagerClustersListRun(opts *cloudManagerClustersListOpts) (interface{
5151
var err error
5252

5353
if opts.projectID == "" && config.Service() == config.OpsManagerService {
54-
result, err = opts.store.ListAllClustersProjects()
54+
result, err = opts.store.ListAllProjectClusters()
5555

5656
} else {
5757
var clusterConfigs *om.AutomationConfig

internal/cli/cloud_manager_clusters_list_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func TestCloudManagerClustersList_Run(t *testing.T) {
5656
config.SetService(config.OpsManagerService)
5757
mockStore.
5858
EXPECT().
59-
ListAllClustersProjects().
59+
ListAllProjectClusters().
6060
Return(expected, nil).
6161
Times(1)
6262

internal/cli/cloud_manager_clusters_shutdown.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ type cmClustersShutdownOpts struct {
3232
*globalOpts
3333
name string
3434
confirm bool
35-
store store.AutomationStore
35+
store store.AutomationPatcher
3636
}
3737

3838
func (opts *cmClustersShutdownOpts) init() error {

internal/cli/cloud_manager_clusters_shutdown_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import (
2424

2525
func TestCloudManagerClustersShutdown_Run(t *testing.T) {
2626
ctrl := gomock.NewController(t)
27-
mockStore := mocks.NewMockAutomationStore(ctrl)
27+
mockStore := mocks.NewMockAutomationPatcher(ctrl)
2828

2929
defer ctrl.Finish()
3030

internal/cli/cloud_manager_clusters_startup.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ type cmClustersStartupOpts struct {
3232
*globalOpts
3333
name string
3434
confirm bool
35-
store store.AutomationStore
35+
store store.AutomationPatcher
3636
}
3737

3838
func (opts *cmClustersStartupOpts) init() error {

internal/cli/cloud_manager_clusters_startup_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import (
2424

2525
func TestCloudManagerClustersStartup_Run(t *testing.T) {
2626
ctrl := gomock.NewController(t)
27-
mockStore := mocks.NewMockAutomationStore(ctrl)
27+
mockStore := mocks.NewMockAutomationPatcher(ctrl)
2828

2929
defer ctrl.Finish()
3030

internal/cli/cloud_manager_clusters_update.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ type cmClustersUpdateOpts struct {
3333
*globalOpts
3434
filename string
3535
fs afero.Fs
36-
store store.AutomationStore
36+
store store.AutomationPatcher
3737
}
3838

3939
func (opts *cmClustersUpdateOpts) init() error {

internal/cli/cloud_manager_clusters_update_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import (
2525

2626
func TestCloudManagerClustersUpdate_Run(t *testing.T) {
2727
ctrl := gomock.NewController(t)
28-
mockStore := mocks.NewMockAutomationStore(ctrl)
28+
mockStore := mocks.NewMockAutomationPatcher(ctrl)
2929

3030
defer ctrl.Finish()
3131

internal/cli/ops_manager.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ func OpsManagerBuilder() *cobra.Command {
3131
cmd.AddCommand(AtlasBackupsBuilder())
3232
cmd.AddCommand(OpsManagerServersBuilder())
3333
cmd.AddCommand(OpsManagerAutomationBuilder())
34+
cmd.AddCommand(OpsManagerDBUsersBuilder())
3435

3536
return cmd
3637
}

internal/cli/ops_manager_dbusers.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2020 MongoDB Inc
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package cli
16+
17+
import (
18+
"github.com/spf13/cobra"
19+
)
20+
21+
func OpsManagerDBUsersBuilder() *cobra.Command {
22+
cmd := &cobra.Command{
23+
Use: "dbusers",
24+
Aliases: []string{"dbuser", "databaseUsers", "databaseUser"},
25+
Short: "Manage database users for your project.",
26+
Long: `
27+
The dbusers command retrieves, creates and modifies the MongoDB database users in your cluster.
28+
Each user has a set of roles that provide access to the project’s databases.
29+
A user’s roles apply to all the clusters in the project.`,
30+
}
31+
32+
cmd.AddCommand(OpsManagerDBUsersCreateBuilder())
33+
34+
return cmd
35+
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// Copyright 2020 MongoDB Inc
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package cli
16+
17+
import (
18+
"fmt"
19+
20+
"github.com/AlecAivazis/survey/v2"
21+
om "github.com/mongodb/go-client-mongodb-ops-manager/opsmngr"
22+
"github.com/mongodb/mongocli/internal/config"
23+
"github.com/mongodb/mongocli/internal/convert"
24+
"github.com/mongodb/mongocli/internal/flags"
25+
"github.com/mongodb/mongocli/internal/messages"
26+
"github.com/mongodb/mongocli/internal/store"
27+
"github.com/mongodb/mongocli/internal/usage"
28+
"github.com/spf13/cobra"
29+
)
30+
31+
type opsManagerDBUsersCreateOpts struct {
32+
*globalOpts
33+
username string
34+
password string
35+
authDB string
36+
roles []string
37+
mechanisms []string
38+
store store.AutomationPatcher
39+
}
40+
41+
func (opts *opsManagerDBUsersCreateOpts) init() error {
42+
if opts.ProjectID() == "" {
43+
return errMissingProjectID
44+
}
45+
46+
var err error
47+
opts.store, err = store.New()
48+
return err
49+
}
50+
51+
func (opts *opsManagerDBUsersCreateOpts) Run() error {
52+
current, err := opts.store.GetAutomationConfig(opts.ProjectID())
53+
54+
if err != nil {
55+
return err
56+
}
57+
58+
current.Auth.Users = append(current.Auth.Users, opts.newDBUser())
59+
60+
if err = opts.store.UpdateAutomationConfig(opts.ProjectID(), current); err != nil {
61+
return err
62+
}
63+
64+
fmt.Print(messages.DeploymentStatus(config.OpsManagerURL(), opts.ProjectID()))
65+
66+
return nil
67+
}
68+
69+
func (opts *opsManagerDBUsersCreateOpts) newDBUser() *om.MongoDBUser {
70+
return &om.MongoDBUser{
71+
Database: opts.authDB,
72+
Username: opts.username,
73+
InitPassword: opts.password,
74+
Roles: convert.BuildOMRoles(opts.roles),
75+
AuthenticationRestrictions: []string{},
76+
Mechanisms: opts.mechanisms,
77+
}
78+
}
79+
80+
func (opts *opsManagerDBUsersCreateOpts) Prompt() error {
81+
if opts.password != "" {
82+
return nil
83+
}
84+
prompt := &survey.Password{
85+
Message: "Password:",
86+
}
87+
return survey.AskOne(prompt, &opts.password)
88+
}
89+
90+
// mongocli atlas dbuser(s) create --username username --password password --role roleName@dbName [--projectId projectId]
91+
func OpsManagerDBUsersCreateBuilder() *cobra.Command {
92+
opts := &opsManagerDBUsersCreateOpts{
93+
globalOpts: newGlobalOpts(),
94+
}
95+
cmd := &cobra.Command{
96+
Use: "create",
97+
Short: "Create a database user for a project.",
98+
Example: ` mongocli om dbuser create --username User1 --password passW0rd --role readWriteAnyDatabase,clusterMonitor --mechanism SCRAM-SHA-256 --projectId <>`,
99+
Args: cobra.NoArgs,
100+
PreRunE: func(cmd *cobra.Command, args []string) error {
101+
if err := opts.init(); err != nil {
102+
return err
103+
}
104+
return opts.Prompt()
105+
},
106+
RunE: func(cmd *cobra.Command, args []string) error {
107+
return opts.Run()
108+
},
109+
}
110+
111+
cmd.Flags().StringVar(&opts.username, flags.Username, "", usage.Username)
112+
cmd.Flags().StringVar(&opts.password, flags.Password, "", usage.Password)
113+
cmd.Flags().StringVar(&opts.authDB, flags.AuthDB, convert.AdminDB, usage.AuthDB)
114+
cmd.Flags().StringSliceVar(&opts.roles, flags.Role, []string{}, usage.Roles)
115+
cmd.Flags().StringSliceVar(&opts.mechanisms, flags.Mechanisms, []string{"SCRAM-SHA-1"}, usage.Mechanisms)
116+
117+
cmd.Flags().StringVar(&opts.projectID, flags.ProjectID, "", usage.ProjectID)
118+
119+
_ = cmd.MarkFlagRequired(flags.Username)
120+
121+
return cmd
122+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright 2020 MongoDB Inc
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package cli
16+
17+
import (
18+
"testing"
19+
20+
"github.com/golang/mock/gomock"
21+
"github.com/mongodb/mongocli/internal/fixtures"
22+
"github.com/mongodb/mongocli/internal/mocks"
23+
)
24+
25+
func TestOpsManagerDBUserCreate_Run(t *testing.T) {
26+
ctrl := gomock.NewController(t)
27+
mockStore := mocks.NewMockAutomationPatcher(ctrl)
28+
29+
defer ctrl.Finish()
30+
31+
expected := fixtures.AutomationConfig()
32+
33+
createOpts := &opsManagerDBUsersCreateOpts{
34+
globalOpts: newGlobalOpts(),
35+
username: "ProjectBar",
36+
password: "US",
37+
roles: []string{"admin@admin"},
38+
store: mockStore,
39+
}
40+
41+
mockStore.
42+
EXPECT().
43+
GetAutomationConfig(createOpts.projectID).
44+
Return(expected, nil).
45+
Times(1)
46+
47+
mockStore.
48+
EXPECT().
49+
UpdateAutomationConfig(createOpts.projectID, expected).
50+
Return(nil).
51+
Times(1)
52+
53+
err := createOpts.Run()
54+
if err != nil {
55+
t.Fatalf("Run() unexpected error: %v", err)
56+
}
57+
}

internal/convert/database_user.go

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"strings"
1919

2020
atlas "github.com/mongodb/go-client-mongodb-atlas/mongodbatlas"
21+
om "github.com/mongodb/go-client-mongodb-ops-manager/opsmngr"
2122
)
2223

2324
//Public constants
@@ -30,9 +31,9 @@ const (
3031
roleSep = "@"
3132
)
3233

33-
// BuildRoles converts the roles inside the array of string in an array of Atlas.Role Objects
34+
// BuildAtlasRoles converts the roles inside the array of string in an array of mongodbatlas.Role structs
3435
// r contains roles in the format roleName@dbName
35-
func BuildRoles(r []string) []atlas.Role {
36+
func BuildAtlasRoles(r []string) []atlas.Role {
3637
roles := make([]atlas.Role, len(r))
3738
for i, roleP := range r {
3839
role := strings.Split(roleP, roleSep)
@@ -49,3 +50,23 @@ func BuildRoles(r []string) []atlas.Role {
4950
}
5051
return roles
5152
}
53+
54+
// BuildOMRoles converts the roles inside the array of string in an array of opsmngr.Role structs
55+
// r contains roles in the format roleName@dbName
56+
func BuildOMRoles(r []string) []*om.Role {
57+
roles := make([]*om.Role, len(r))
58+
for i, roleP := range r {
59+
role := strings.Split(roleP, roleSep)
60+
roleName := role[0]
61+
databaseName := AdminDB
62+
if len(role) > 1 {
63+
databaseName = role[1]
64+
}
65+
66+
roles[i] = &om.Role{
67+
Role: roleName,
68+
Database: databaseName,
69+
}
70+
}
71+
return roles
72+
}

0 commit comments

Comments
 (0)