Skip to content

CLOUDP-57839: Create db users, C/OM #54

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion internal/cli/atlas_dbusers_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func (opts *atlasDBUsersCreateOpts) Run() error {
func (opts *atlasDBUsersCreateOpts) newDatabaseUser() *atlas.DatabaseUser {
return &atlas.DatabaseUser{
DatabaseName: convert.AdminDB,
Roles: convert.BuildRoles(opts.roles),
Roles: convert.BuildAtlasRoles(opts.roles),
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed as now we have one for OM

GroupID: opts.ProjectID(),
Username: opts.username,
Password: opts.password,
Expand Down
2 changes: 1 addition & 1 deletion internal/cli/atlas_dbusers_update.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func (opts *atlasDBUsersUpdateOpts) update(out *atlas.DatabaseUser) {
out.Password = opts.password
}

out.Roles = convert.BuildRoles(opts.roles)
out.Roles = convert.BuildAtlasRoles(opts.roles)
}

// mongocli atlas dbuser(s) update username [--password password] [--role roleName@dbName] [--projectId projectId]
Expand Down
1 change: 1 addition & 0 deletions internal/cli/cloud_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ func CloudManagerBuilder() *cobra.Command {
cmd.AddCommand(AtlasBackupsBuilder())
cmd.AddCommand(OpsManagerServersBuilder())
cmd.AddCommand(OpsManagerAutomationBuilder())
cmd.AddCommand(OpsManagerDBUsersCreateBuilder())

return cmd
}
2 changes: 1 addition & 1 deletion internal/cli/cloud_manager_clusters_apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type cmClustersApplyOpts struct {
*globalOpts
filename string
fs afero.Fs
store store.AutomationStore
store store.AutomationPatcher
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Store now has also a list of cluster which we don't need so making this interface more flexible

}

func (opts *cmClustersApplyOpts) init() error {
Expand Down
2 changes: 1 addition & 1 deletion internal/cli/cloud_manager_clusters_apply_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import (

func TestCloudManagerClustersApply_Run(t *testing.T) {
ctrl := gomock.NewController(t)
mockStore := mocks.NewMockAutomationStore(ctrl)
mockStore := mocks.NewMockAutomationPatcher(ctrl)

defer ctrl.Finish()

Expand Down
2 changes: 1 addition & 1 deletion internal/cli/cloud_manager_clusters_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type cmClustersCreateOpts struct {
*globalOpts
filename string
fs afero.Fs
store store.AutomationStore
store store.AutomationPatcher
}

func (opts *cmClustersCreateOpts) init() error {
Expand Down
2 changes: 1 addition & 1 deletion internal/cli/cloud_manager_clusters_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func cloudManagerClustersListRun(opts *cloudManagerClustersListOpts) (interface{
var err error

if opts.projectID == "" && config.Service() == config.OpsManagerService {
result, err = opts.store.ListAllClustersProjects()
result, err = opts.store.ListAllProjectClusters()
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

small grammatical fix fix


} else {
var clusterConfigs *om.AutomationConfig
Expand Down
2 changes: 1 addition & 1 deletion internal/cli/cloud_manager_clusters_list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func TestCloudManagerClustersList_Run(t *testing.T) {
config.SetService(config.OpsManagerService)
mockStore.
EXPECT().
ListAllClustersProjects().
ListAllProjectClusters().
Return(expected, nil).
Times(1)

Expand Down
2 changes: 1 addition & 1 deletion internal/cli/cloud_manager_clusters_shutdown.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type cmClustersShutdownOpts struct {
*globalOpts
name string
confirm bool
store store.AutomationStore
store store.AutomationPatcher
}

func (opts *cmClustersShutdownOpts) init() error {
Expand Down
2 changes: 1 addition & 1 deletion internal/cli/cloud_manager_clusters_shutdown_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (

func TestCloudManagerClustersShutdown_Run(t *testing.T) {
ctrl := gomock.NewController(t)
mockStore := mocks.NewMockAutomationStore(ctrl)
mockStore := mocks.NewMockAutomationPatcher(ctrl)

defer ctrl.Finish()

Expand Down
2 changes: 1 addition & 1 deletion internal/cli/cloud_manager_clusters_startup.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type cmClustersStartupOpts struct {
*globalOpts
name string
confirm bool
store store.AutomationStore
store store.AutomationPatcher
}

func (opts *cmClustersStartupOpts) init() error {
Expand Down
2 changes: 1 addition & 1 deletion internal/cli/cloud_manager_clusters_startup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (

func TestCloudManagerClustersStartup_Run(t *testing.T) {
ctrl := gomock.NewController(t)
mockStore := mocks.NewMockAutomationStore(ctrl)
mockStore := mocks.NewMockAutomationPatcher(ctrl)

defer ctrl.Finish()

Expand Down
2 changes: 1 addition & 1 deletion internal/cli/cloud_manager_clusters_update.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type cmClustersUpdateOpts struct {
*globalOpts
filename string
fs afero.Fs
store store.AutomationStore
store store.AutomationPatcher
}

func (opts *cmClustersUpdateOpts) init() error {
Expand Down
2 changes: 1 addition & 1 deletion internal/cli/cloud_manager_clusters_update_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import (

func TestCloudManagerClustersUpdate_Run(t *testing.T) {
ctrl := gomock.NewController(t)
mockStore := mocks.NewMockAutomationStore(ctrl)
mockStore := mocks.NewMockAutomationPatcher(ctrl)

defer ctrl.Finish()

Expand Down
1 change: 1 addition & 0 deletions internal/cli/ops_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func OpsManagerBuilder() *cobra.Command {
cmd.AddCommand(AtlasBackupsBuilder())
cmd.AddCommand(OpsManagerServersBuilder())
cmd.AddCommand(OpsManagerAutomationBuilder())
cmd.AddCommand(OpsManagerDBUsersBuilder())

return cmd
}
35 changes: 35 additions & 0 deletions internal/cli/ops_manager_dbusers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2020 MongoDB 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.

package cli

import (
"github.com/spf13/cobra"
)

func OpsManagerDBUsersBuilder() *cobra.Command {
cmd := &cobra.Command{
Use: "dbusers",
Aliases: []string{"dbuser", "databaseUsers", "databaseUser"},
Short: "Manage database users for your project.",
Long: `
The dbusers command retrieves, creates and modifies the MongoDB database users in your cluster.
Each user has a set of roles that provide access to the project’s databases.
A user’s roles apply to all the clusters in the project.`,
}

cmd.AddCommand(OpsManagerDBUsersCreateBuilder())

return cmd
}
122 changes: 122 additions & 0 deletions internal/cli/ops_manager_dbusers_create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// Copyright 2020 MongoDB 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.

package cli

import (
"fmt"

"github.com/AlecAivazis/survey/v2"
om "github.com/mongodb/go-client-mongodb-ops-manager/opsmngr"
"github.com/mongodb/mongocli/internal/config"
"github.com/mongodb/mongocli/internal/convert"
"github.com/mongodb/mongocli/internal/flags"
"github.com/mongodb/mongocli/internal/messages"
"github.com/mongodb/mongocli/internal/store"
"github.com/mongodb/mongocli/internal/usage"
"github.com/spf13/cobra"
)

type opsManagerDBUsersCreateOpts struct {
*globalOpts
username string
password string
authDB string
roles []string
mechanisms []string
store store.AutomationPatcher
}

func (opts *opsManagerDBUsersCreateOpts) init() error {
if opts.ProjectID() == "" {
return errMissingProjectID
}

var err error
opts.store, err = store.New()
return err
}

func (opts *opsManagerDBUsersCreateOpts) Run() error {
current, err := opts.store.GetAutomationConfig(opts.ProjectID())

if err != nil {
return err
}

current.Auth.Users = append(current.Auth.Users, opts.newDBUser())

if err = opts.store.UpdateAutomationConfig(opts.ProjectID(), current); err != nil {
return err
}

fmt.Print(messages.DeploymentStatus(config.OpsManagerURL(), opts.ProjectID()))

return nil
}

func (opts *opsManagerDBUsersCreateOpts) newDBUser() *om.MongoDBUser {
return &om.MongoDBUser{
Database: opts.authDB,
Username: opts.username,
InitPassword: opts.password,
Roles: convert.BuildOMRoles(opts.roles),
AuthenticationRestrictions: []string{},
Mechanisms: opts.mechanisms,
}
}

func (opts *opsManagerDBUsersCreateOpts) Prompt() error {
if opts.password != "" {
return nil
}
prompt := &survey.Password{
Message: "Password:",
}
return survey.AskOne(prompt, &opts.password)
}

// mongocli atlas dbuser(s) create --username username --password password --role roleName@dbName [--projectId projectId]
func OpsManagerDBUsersCreateBuilder() *cobra.Command {
opts := &opsManagerDBUsersCreateOpts{
globalOpts: newGlobalOpts(),
}
cmd := &cobra.Command{
Use: "create",
Short: "Create a database user for a project.",
Example: ` mongocli om dbuser create --username User1 --password passW0rd --role readWriteAnyDatabase,clusterMonitor --mechanism SCRAM-SHA-256 --projectId <>`,
Args: cobra.NoArgs,
PreRunE: func(cmd *cobra.Command, args []string) error {
if err := opts.init(); err != nil {
return err
}
return opts.Prompt()
},
RunE: func(cmd *cobra.Command, args []string) error {
return opts.Run()
},
}

cmd.Flags().StringVar(&opts.username, flags.Username, "", usage.Username)
cmd.Flags().StringVar(&opts.password, flags.Password, "", usage.Password)
cmd.Flags().StringVar(&opts.authDB, flags.AuthDB, convert.AdminDB, usage.AuthDB)
cmd.Flags().StringSliceVar(&opts.roles, flags.Role, []string{}, usage.Roles)
cmd.Flags().StringSliceVar(&opts.mechanisms, flags.Mechanisms, []string{"SCRAM-SHA-1"}, usage.Mechanisms)

cmd.Flags().StringVar(&opts.projectID, flags.ProjectID, "", usage.ProjectID)

_ = cmd.MarkFlagRequired(flags.Username)

return cmd
}
57 changes: 57 additions & 0 deletions internal/cli/ops_manager_dbusers_create_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright 2020 MongoDB 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.

package cli

import (
"testing"

"github.com/golang/mock/gomock"
"github.com/mongodb/mongocli/internal/fixtures"
"github.com/mongodb/mongocli/internal/mocks"
)

func TestOpsManagerDBUserCreate_Run(t *testing.T) {
ctrl := gomock.NewController(t)
mockStore := mocks.NewMockAutomationPatcher(ctrl)

defer ctrl.Finish()

expected := fixtures.AutomationConfig()

createOpts := &opsManagerDBUsersCreateOpts{
globalOpts: newGlobalOpts(),
username: "ProjectBar",
password: "US",
roles: []string{"admin@admin"},
store: mockStore,
}

mockStore.
EXPECT().
GetAutomationConfig(createOpts.projectID).
Return(expected, nil).
Times(1)

mockStore.
EXPECT().
UpdateAutomationConfig(createOpts.projectID, expected).
Return(nil).
Times(1)

err := createOpts.Run()
if err != nil {
t.Fatalf("Run() unexpected error: %v", err)
}
}
25 changes: 23 additions & 2 deletions internal/convert/database_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"strings"

atlas "github.com/mongodb/go-client-mongodb-atlas/mongodbatlas"
om "github.com/mongodb/go-client-mongodb-ops-manager/opsmngr"
)

//Public constants
Expand All @@ -30,9 +31,9 @@ const (
roleSep = "@"
)

// BuildRoles converts the roles inside the array of string in an array of Atlas.Role Objects
// BuildAtlasRoles converts the roles inside the array of string in an array of mongodbatlas.Role structs
// r contains roles in the format roleName@dbName
func BuildRoles(r []string) []atlas.Role {
func BuildAtlasRoles(r []string) []atlas.Role {
roles := make([]atlas.Role, len(r))
for i, roleP := range r {
role := strings.Split(roleP, roleSep)
Expand All @@ -49,3 +50,23 @@ func BuildRoles(r []string) []atlas.Role {
}
return roles
}

// BuildOMRoles converts the roles inside the array of string in an array of opsmngr.Role structs
// r contains roles in the format roleName@dbName
func BuildOMRoles(r []string) []*om.Role {
roles := make([]*om.Role, len(r))
for i, roleP := range r {
role := strings.Split(roleP, roleSep)
roleName := role[0]
databaseName := AdminDB
if len(role) > 1 {
databaseName = role[1]
}

roles[i] = &om.Role{
Role: roleName,
Database: databaseName,
}
}
return roles
}
Loading