Skip to content
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
58 changes: 51 additions & 7 deletions internal/cli/atlas/quickstart/quick_start.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (

"github.com/AlecAivazis/survey/v2"
"github.com/mongodb/mongodb-atlas-cli/internal/cli"
"github.com/mongodb/mongodb-atlas-cli/internal/cli/auth"
"github.com/mongodb/mongodb-atlas-cli/internal/config"
"github.com/mongodb/mongodb-atlas-cli/internal/flag"
"github.com/mongodb/mongodb-atlas-cli/internal/mongosh"
Expand Down Expand Up @@ -85,6 +86,8 @@ const (
type Opts struct {
cli.GlobalOpts
cli.WatchOpts
login auth.LoginFlow
loginOpts *auth.LoginOpts
defaultName string
ClusterName string
Tier string
Expand All @@ -103,6 +106,7 @@ type Opts struct {
Confirm bool
CurrentIP bool
store store.AtlasClusterQuickStarter
shouldRunLogin bool
}

type quickstart struct {
Expand All @@ -122,6 +126,17 @@ type Flow interface {
Run() error
}

func NewQuickstartFlow(qsOpts *Opts) Flow {
return qsOpts
}

func NewQuickstartOpts(loginOpts *auth.LoginOpts) *Opts {
return &Opts{
loginOpts: loginOpts,
login: auth.NewLoginFlow(loginOpts),
}
}

func (opts *Opts) initStore(ctx context.Context) func() error {
return func() error {
var err error
Expand All @@ -130,13 +145,42 @@ func (opts *Opts) initStore(ctx context.Context) func() error {
}
}

func (opts *Opts) quickstartPreRun() error {
return opts.PreRunE(
opts.ValidateProjectID,
)
func (opts *Opts) quickstartPreRun(ctx context.Context, outWriter io.Writer) error {
opts.shouldRunLogin = false
opts.OutWriter = outWriter

// Get authentication status to define whether login should be run
status, _ := auth.GetStatus(ctx)
if status == auth.LoggedInWithValidToken || status == auth.LoggedInWithAPIKeys {
return opts.PreRunE(
opts.ValidateProjectID,
)
}

// If customer used --force and is not authenticated, check credentials and proceed. Likely to
// throw an error here.
if opts.Confirm {
if err := validate.Credentials(); err != nil {
return err
}
return opts.PreRunE(
opts.ValidateProjectID,
)
}

opts.loginOpts.OutWriter = opts.OutWriter
if err := opts.login.PreRun(); err != nil {
return err
}

opts.shouldRunLogin = true
_, _ = fmt.Fprintf(opts.OutWriter, `This action requires authentication.
`)
return opts.login.Run(ctx)
}

func (opts *Opts) PreRun(ctx context.Context, outWriter io.Writer) error {
opts.shouldRunLogin = false
opts.setTier()

if opts.CurrentIP && len(opts.IPAddresses) > 0 {
Expand Down Expand Up @@ -443,18 +487,18 @@ func (opts *Opts) interactiveSetup() error {
// [--skipMongosh skipMongosh]
// [--default]
func Builder() *cobra.Command {
opts := &Opts{}
opts := NewQuickstartOpts(auth.NewLoginOpts())
cmd := &cobra.Command{
Use: "quickstart",
Short: "Create and access an Atlas Cluster.",
Long: "This command creates a new cluster, adds your public IP to the atlas access list and creates a db user to access your new MongoDB instance.",
Example: fmt.Sprintf(` Skip setting cluster name, provider or database username by using the command options:
$ %s quickstart --clusterName Test --provider GCP --username dbuserTest`, cli.ExampleAtlasEntryPoint()),
PreRunE: func(cmd *cobra.Command, args []string) error {
if err := opts.quickstartPreRun(); err != nil {
if err := opts.PreRun(cmd.Context(), cmd.OutOrStdout()); err != nil {
return err
}
return opts.PreRun(cmd.Context(), cmd.OutOrStdout())
return opts.quickstartPreRun(cmd.Context(), cmd.OutOrStdout())
},
RunE: func(cmd *cobra.Command, args []string) error {
return opts.Run()
Expand Down
146 changes: 139 additions & 7 deletions internal/cli/atlas/quickstart/quick_start_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,34 @@
package quickstart

import (
"bytes"
"context"
"fmt"
"testing"

"github.com/golang/mock/gomock"
"github.com/mongodb/mongodb-atlas-cli/internal/cli/auth"
"github.com/mongodb/mongodb-atlas-cli/internal/config"
"github.com/mongodb/mongodb-atlas-cli/internal/flag"
"github.com/mongodb/mongodb-atlas-cli/internal/mocks"
"github.com/mongodb/mongodb-atlas-cli/internal/test"
"github.com/mongodb/mongodb-atlas-cli/internal/validate"
"github.com/stretchr/testify/require"
"go.mongodb.org/atlas/mongodbatlas"
)

func TestBuilder(t *testing.T) {
t.Cleanup(cleanUpConfig)
test.CmdValidator(
t,
Builder(),
0,
[]string{flag.ProjectID, flag.Region, flag.ClusterName, flag.Provider, flag.AccessListIP, flag.Username, flag.Password, flag.SkipMongosh, flag.SkipSampleData},
)
}

func TestQuickstartOpts_Run(t *testing.T) {
t.Cleanup(cleanUpConfig)
ctrl := gomock.NewController(t)
mockStore := mocks.NewMockAtlasClusterQuickStarter(ctrl)
defer ctrl.Finish()
Expand Down Expand Up @@ -85,11 +103,125 @@ func TestQuickstartOpts_Run(t *testing.T) {
}
}

func TestBuilder(t *testing.T) {
test.CmdValidator(
t,
Builder(),
0,
[]string{flag.ProjectID, flag.Region, flag.ClusterName, flag.Provider, flag.AccessListIP, flag.Username, flag.Password, flag.SkipMongosh, flag.SkipSampleData},
)
func TestQuickstartOpts_Run_NotLoggedIn(t *testing.T) {
t.Cleanup(cleanUpConfig)
ctrl := gomock.NewController(t)
mockStore := mocks.NewMockAtlasClusterQuickStarter(ctrl)
defer ctrl.Finish()
buf := new(bytes.Buffer)
ctx := context.TODO()
opts := &Opts{
ClusterName: "ProjectBar",
Region: "US",
store: mockStore,
IPAddresses: []string{"0.0.0.0"},
DBUsername: "user",
DBUserPassword: "test",
Provider: "AWS",
SkipMongosh: true,
SkipSampleData: true,
Confirm: true,
}

opts.runMongoShell = true
require.Error(t, validate.ErrMissingCredentials, opts.quickstartPreRun(ctx, buf))
}

func TestQuickstartOpts_Run_NeedLogin_ForceAfterLogin(t *testing.T) {
t.Cleanup(cleanUpConfig)
ctrl := gomock.NewController(t)
mockStore := mocks.NewMockAtlasClusterQuickStarter(ctrl)
mockLoginFlow := mocks.NewMockLoginFlow(ctrl)
defer ctrl.Finish()

ctx := context.TODO()
buf := new(bytes.Buffer)

expectedCluster := &mongodbatlas.AdvancedCluster{
StateName: "IDLE",
ConnectionStrings: &mongodbatlas.ConnectionStrings{
StandardSrv: "",
},
}

expectedDBUser := &mongodbatlas.DatabaseUser{}

var expectedProjectAccessLists *mongodbatlas.ProjectIPAccessLists

opts := &Opts{
ClusterName: "ProjectBar",
Region: "US",
store: mockStore,
IPAddresses: []string{"0.0.0.0"},
DBUsername: "user",
DBUserPassword: "test",
Provider: "AWS",
SkipMongosh: true,
SkipSampleData: true,
Confirm: false,
login: mockLoginFlow,
loginOpts: auth.NewLoginOpts(),
}

opts.runMongoShell = true
setConfig()
projectIPAccessList := opts.newProjectIPAccessList()

mockLoginFlow.
EXPECT().
PreRun().
Return(nil).
Times(1)

mockLoginFlow.
EXPECT().
Run(ctx).
Return(nil).
Times(1)

mockStore.
EXPECT().
CreateCluster(opts.newCluster()).Return(expectedCluster, nil).
Times(1)

mockStore.
EXPECT().
CreateProjectIPAccessList(projectIPAccessList).Return(expectedProjectAccessLists, nil).
Times(1)

mockStore.
EXPECT().
AtlasCluster(opts.ConfigProjectID(), opts.ClusterName).Return(expectedCluster, nil).
Times(2)

mockStore.
EXPECT().
CreateDatabaseUser(opts.newDatabaseUser()).Return(expectedDBUser, nil).
Times(1)

fmt.Println(config.Service())

if err := opts.quickstartPreRun(ctx, buf); err != nil {
t.Fatalf("Run() unexpected error: %v", err)
}
opts.Confirm = true

if err := opts.Run(); err != nil {
t.Fatalf("Run() unexpected error: %v", err)
}
}

func setConfig() func(ctx context.Context) error {
return func(ctx context.Context) error {
config.SetOrgID("a")
config.SetProjectID("b")
config.SetService("cloud")
return nil
}
}

func cleanUpConfig() {
config.SetAccessToken("")
config.SetPublicAPIKey("")
config.SetPrivateAPIKey("")
}
31 changes: 15 additions & 16 deletions internal/cli/atlas/setup/setup_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ import (
"github.com/mongodb/mongodb-atlas-cli/internal/cli"
"github.com/mongodb/mongodb-atlas-cli/internal/cli/atlas/quickstart"
"github.com/mongodb/mongodb-atlas-cli/internal/cli/auth"
"github.com/mongodb/mongodb-atlas-cli/internal/cli/require"
"github.com/mongodb/mongodb-atlas-cli/internal/config"
"github.com/mongodb/mongodb-atlas-cli/internal/flag"
"github.com/mongodb/mongodb-atlas-cli/internal/usage"
"github.com/mongodb/mongodb-atlas-cli/internal/validate"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -82,32 +82,30 @@ This command will help you
}

func (opts *Opts) PreRun(ctx context.Context) error {
opts.skipRegister = false
opts.skipRegister = true
opts.skipLogin = true

if config.PublicAPIKey() != "" && config.PrivateAPIKey() != "" {
opts.skipRegister = true
status, _ := auth.GetStatus(ctx)
switch status {
case auth.LoggedInWithAPIKeys:
msg := fmt.Sprintf(auth.AlreadyAuthenticatedMsg, config.PublicAPIKey())
_, _ = fmt.Fprintf(opts.OutWriter, `
%s

%s
`, msg, withProfileMsg)
}

if account, err := auth.AccountWithAccessToken(); err == nil {
opts.skipRegister = true
case auth.LoggedInWithValidToken:
account, _ := auth.AccountWithAccessToken()
msg := fmt.Sprintf(auth.AlreadyAuthenticatedEmailMsg, account)
// token exists but it is not refreshed
if err := cli.RefreshToken(ctx); err != nil || validate.Token() != nil {
opts.skipLogin = false
return nil
}

_, _ = fmt.Fprintf(opts.OutWriter, `%s

%s
`, msg, withProfileMsg)
case auth.LoggedInWithInvalidToken:
opts.skipLogin = false
case auth.NotLoggedIn:
opts.skipRegister = false
default:
}

return nil
Expand All @@ -123,11 +121,11 @@ func (opts *Opts) PreRun(ctx context.Context) error {
// [--skipMongosh skipMongosh]
func Builder() *cobra.Command {
loginOpts := auth.NewLoginOpts()
qsOpts := &quickstart.Opts{}
qsOpts := quickstart.NewQuickstartOpts(loginOpts)
opts := &Opts{
register: auth.NewRegisterFlow(loginOpts),
login: auth.NewLoginFlow(loginOpts),
quickstart: qsOpts,
quickstart: quickstart.NewQuickstartFlow(qsOpts),
}

cmd := &cobra.Command{
Expand All @@ -137,6 +135,7 @@ func Builder() *cobra.Command {
Example: ` Override default cluster settings like name, provider, or database username by using the command options
$ atlas setup --clusterName Test --provider GCP --username dbuserTest`,
Hidden: false,
Args: require.NoArgs,
PreRunE: func(cmd *cobra.Command, args []string) error {
opts.OutWriter = cmd.OutOrStdout()
// setup pre run
Expand Down
Loading