• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mongodb / mongodb-atlas-cli / 16671521771

01 Aug 2025 09:28AM UTC coverage: 57.953% (-7.1%) from 65.017%
16671521771

push

github

web-flow
chore: remove unit tag from tests (#4071)

23613 of 40745 relevant lines covered (57.95%)

2.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

56.78
/internal/cli/setup/setup_cmd.go
1
// Copyright 2022 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 setup
16

17
import (
18
        "context"
19
        "errors"
20
        "fmt"
21
        "io"
22
        "os"
23
        "strconv"
24
        "strings"
25
        "syscall"
26
        "time"
27

28
        "github.com/AlecAivazis/survey/v2"
29
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli"
30
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/auth"
31
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/require"
32
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/compass"
33
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/config"
34
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/flag"
35
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/log"
36
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/mongosh"
37
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/prerun"
38
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/sighandle"
39
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/store"
40
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/telemetry"
41
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/usage"
42
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/validate"
43
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/vscode"
44
        "github.com/spf13/cobra"
45
        "github.com/spf13/pflag"
46
        atlasClustersPinned "go.mongodb.org/atlas-sdk/v20240530005/admin"
47
        atlasv2 "go.mongodb.org/atlas-sdk/v20250312005/admin"
48
)
49

50
const (
51
        DefaultAtlasTier           = "M0"
52
        defaultAtlasGovTier        = "M30"
53
        atlasAdmin                 = "atlasAdmin"
54
        replicaSet                 = "REPLICASET"
55
        defaultProvider            = "AWS"
56
        defaultRegion              = "US_EAST_1"
57
        defaultRegionGCP           = "US_EAST_4"
58
        defaultRegionAzure         = "US_EAST_2"
59
        defaultRegionGov           = "US_GOV_EAST_1"
60
        defaultSettings            = "default"
61
        customSettings             = "custom"
62
        cancelSettings             = "cancel"
63
        skipConnect                = "skip"
64
        compassConnect             = "compass"
65
        mongoshConnect             = "mongosh"
66
        vsCodeConnect              = "vscode"
67
        clusterWideScaling         = "clusterWideScaling"
68
        independentShardScaling    = "independentShardScaling"
69
        deprecateMessageSharedTier = "The '%s' tier is deprecated. For the migration guide and timeline, visit: https://dochub.mongodb.org/core/flex-migration.\n"
70
)
71

72
var (
73
        settingOptions      = []string{defaultSettings, customSettings, cancelSettings}
74
        settingsDescription = map[string]string{
75
                defaultSettings: "With default settings",
76
                customSettings:  "With custom settings",
77
                cancelSettings:  "Cancel setup",
78
        }
79
        connectWithOptions     = []string{mongoshConnect, compassConnect, vsCodeConnect, skipConnect}
80
        connectWithDescription = map[string]string{
81
                mongoshConnect: "MongoDB Shell",
82
                compassConnect: "MongoDB Compass",
83
                vsCodeConnect:  "MongoDB for VsCode",
84
                skipConnect:    "Skip Connection",
85
        }
86
)
87

88
var errNeedsProject = errors.New("ensure you select or add a project to the profile")
89

90
const setupTemplateCloseHandler = `
91
Enter 'atlas cluster watch %s' to learn when your cluster is available.
92
`
93

94
const setupTemplateStoreWarning = `
95
Store your database authentication access details in a secure location:
96
Database User Username: %s
97
Database User Password: %s
98
`
99

100
const setupTemplateIntro = `Press [Enter] to use the default values.
101

102
Enter [?] on any option to get help.
103
`
104

105
const setupTemplateCluster = `
106
Creating your cluster... [It's safe to 'Ctrl + C']
107
`
108
const setupTemplateIPNotFound = `
109
We could not find your public IP address. To add your IP address run:
110
  atlas accesslist create
111

112
`
113

114
//go:generate go tool go.uber.org/mock/mockgen -typed -destination=setup_mock_test.go -package=setup . AtlasClusterQuickStarter
115

116
type profileReader interface {
117
        ProjectID() string
118
        OrgID() string
119
}
120

121
type AtlasClusterQuickStarter interface {
122
        AddSampleData(string, string) (*atlasv2.SampleDatasetStatus, error)
123
        SampleDataStatus(string, string) (*atlasv2.SampleDatasetStatus, error)
124
        CloudProviderRegions(string, string, []string) (*atlasv2.PaginatedApiAtlasProviderRegions, error)
125
        CreateCluster(v15 *atlasClustersPinned.AdvancedClusterDescription) (*atlasClustersPinned.AdvancedClusterDescription, error)
126
        LatestAtlasCluster(string, string) (*atlasv2.ClusterDescription20240805, error)
127
        CreateClusterLatest(v15 *atlasv2.ClusterDescription20240805) (*atlasv2.ClusterDescription20240805, error)
128
        MDBVersions(projectID string, opt *store.MDBVersionListOptions) (*atlasv2.PaginatedAvailableVersion, error)
129
        CreateDatabaseUser(*atlasv2.CloudDatabaseUser) (*atlasv2.CloudDatabaseUser, error)
130
        DatabaseUser(string, string, string) (*atlasv2.CloudDatabaseUser, error)
131
        CreateProjectIPAccessList([]*atlasv2.NetworkPermissionEntry) (*atlasv2.PaginatedNetworkAccess, error)
132
}
133

134
type Opts struct {
135
        cli.ProjectOpts
136
        cli.WatchOpts
137
        register                    auth.RegisterOpts
138
        config                      profileReader
139
        store                       AtlasClusterQuickStarter
140
        defaultName                 string
141
        ClusterName                 string
142
        Provider                    string
143
        Region                      string
144
        IPAddresses                 []string
145
        IPAddressesResponse         string
146
        DBUsername                  string
147
        DBUserPassword              string
148
        SampleDataJobID             string
149
        MDBVersion                  string
150
        Tier                        string
151
        Tag                         map[string]string
152
        SkipSampleData              bool
153
        SkipMongosh                 bool
154
        connectWith                 string
155
        DefaultValue                bool
156
        Confirm                     bool
157
        CurrentIP                   bool
158
        EnableTerminationProtection bool
159
        AutoScalingMode             string
160
        flags                       *pflag.FlagSet
161
        flagSet                     map[string]struct{}
162
        settings                    string
163
        connectionString            string
164

165
        // control
166
        skipRegister bool
167
        skipLogin    bool
168
}
169

170
type clusterSettings struct {
171
        ClusterName                 string
172
        Provider                    string
173
        Region                      string
174
        Tier                        string
175
        DBUsername                  string
176
        DBUserPassword              string
177
        IPAddresses                 []string
178
        EnableTerminationProtection bool
179
        SkipSampleData              bool
180
        Tag                         map[string]string
181
        MdbVersion                  string
182
}
183

184
func (opts *Opts) providerAndRegionToConstant() {
1✔
185
        opts.Provider = strings.ToUpper(opts.Provider)
1✔
186
        opts.Region = strings.ReplaceAll(strings.ToUpper(opts.Region), "-", "_")
1✔
187
}
1✔
188

189
func (opts *Opts) trackFlags() {
1✔
190
        if opts.flags == nil {
1✔
191
                opts.flagSet = make(map[string]struct{})
×
192
                return
×
193
        }
×
194

195
        opts.flagSet = make(map[string]struct{}, opts.flags.NFlag())
1✔
196
        opts.flags.Visit(func(f *pflag.Flag) {
2✔
197
                opts.flagSet[f.Name] = struct{}{}
1✔
198
        })
1✔
199
}
200

201
func (opts *Opts) newDefaultValues() (*clusterSettings, error) {
1✔
202
        values := &clusterSettings{}
1✔
203
        values.SkipSampleData = opts.SkipSampleData
1✔
204

1✔
205
        values.ClusterName = opts.ClusterName
1✔
206
        if opts.ClusterName == "" {
2✔
207
                values.ClusterName = opts.defaultName
1✔
208
        }
1✔
209

210
        values.Provider = opts.Provider
1✔
211
        if opts.Provider == "" {
2✔
212
                values.Provider = defaultProvider
1✔
213
        }
1✔
214

215
        values.Region = opts.Region
1✔
216
        if opts.Region == "" {
2✔
217
                if config.CloudGovService == config.Service() {
1✔
218
                        values.Region = defaultRegionGov
×
219
                } else {
1✔
220
                        switch strings.ToUpper(opts.Provider) {
1✔
221
                        case "AZURE":
×
222
                                values.Region = defaultRegionAzure
×
223
                        case "GCP":
×
224
                                values.Region = defaultRegionGCP
×
225
                        default:
1✔
226
                                values.Region = defaultRegion
1✔
227
                        }
228
                }
229
        }
230

231
        values.MdbVersion = opts.MDBVersion
1✔
232
        if opts.MDBVersion == "" {
2✔
233
                opts.MDBVersion, _ = cli.DefaultMongoDBMajorVersion()
1✔
234
        }
1✔
235

236
        values.DBUsername = opts.DBUsername
1✔
237
        if opts.DBUsername == "" {
2✔
238
                values.DBUsername = opts.defaultName
1✔
239
        }
1✔
240

241
        values.DBUserPassword = opts.DBUserPassword
1✔
242
        if opts.DBUserPassword == "" {
2✔
243
                pwd, err := generatePassword()
1✔
244
                if err != nil {
1✔
245
                        return nil, err
×
246
                }
×
247
                values.DBUserPassword = pwd
1✔
248
        }
249

250
        values.IPAddresses = opts.IPAddresses
1✔
251
        if len(opts.IPAddresses) == 0 {
2✔
252
                if publicIP := store.IPAddress(); publicIP != "" {
2✔
253
                        values.IPAddresses = []string{publicIP}
1✔
254
                } else {
2✔
255
                        _, _ = log.Warning(setupTemplateIPNotFound)
1✔
256
                }
1✔
257
        }
258

259
        values.Tier = opts.Tier
1✔
260
        values.EnableTerminationProtection = opts.EnableTerminationProtection
1✔
261
        values.Tag = opts.Tag
1✔
262

1✔
263
        return values, nil
1✔
264
}
265

266
func (opts *Opts) clusterCreationWatcher() (any, bool, error) {
1✔
267
        result, err := opts.store.LatestAtlasCluster(opts.ConfigProjectID(), opts.ClusterName)
1✔
268
        if err != nil {
1✔
269
                return nil, false, err
×
270
        }
×
271
        return nil, result.GetStateName() == "IDLE", nil
1✔
272
}
273

274
func (opts *Opts) sampleDataWatcher() (any, bool, error) {
×
275
        result, err := opts.store.SampleDataStatus(opts.ConfigProjectID(), opts.SampleDataJobID)
×
276
        if err != nil {
×
277
                return nil, false, err
×
278
        }
×
279
        if result.GetState() == "FAILED" {
×
280
                return nil, false, fmt.Errorf("failed to load data: %s", result.GetErrorMessage())
×
281
        }
×
282
        return nil, result.GetState() == "COMPLETED", nil
×
283
}
284

285
func (opts *Opts) loadSampleData() error {
1✔
286
        if opts.SkipSampleData {
2✔
287
                return nil
1✔
288
        }
1✔
289

290
        fmt.Print(`
×
291
Loading sample data into your cluster... [It's safe to 'Ctrl + C']
×
292
`)
×
293
        sampleDataJob, err := opts.store.AddSampleData(opts.ConfigProjectID(), opts.ClusterName)
×
294

×
295
        if err != nil {
×
296
                return nil
×
297
        }
×
298

299
        opts.SampleDataJobID = sampleDataJob.GetId()
×
300

×
301
        _, err = opts.Watch(opts.sampleDataWatcher)
×
302
        return err
×
303
}
304

305
func (opts *Opts) createResources() error {
1✔
306
        if err := opts.createDatabaseUser(); err != nil {
2✔
307
                return err
1✔
308
        }
1✔
309

310
        if err := opts.createAccessList(); err != nil {
1✔
311
                return err
×
312
        }
×
313

314
        if err := opts.createCluster(); err != nil {
1✔
315
                target, _ := atlasClustersPinned.AsError(err)
×
316
                if target.GetErrorCode() == "CANNOT_CREATE_FREE_CLUSTER_VIA_PUBLIC_API" && strings.Contains(strings.ToLower(target.GetDetail()), cli.ErrFreeClusterAlreadyExists.Error()) {
×
317
                        return cli.ErrFreeClusterAlreadyExists
×
318
                } else if target.GetErrorCode() == "INVALID_ATTRIBUTE" && strings.Contains(target.GetDetail(), "regionName") {
×
319
                        return cli.ErrNoRegionExistsTryCommand
×
320
                }
×
321
                return err
×
322
        }
323
        return nil
1✔
324
}
325

326
func (opts *Opts) askSampleDataQuestion() error {
×
327
        if opts.SkipSampleData {
×
328
                return nil
×
329
        }
×
330

331
        q := newSampleDataQuestion()
×
332
        var addSampleData bool
×
333
        if err := telemetry.TrackAskOne(q, &addSampleData); err != nil {
×
334
                return err
×
335
        }
×
336
        opts.SkipSampleData = !addSampleData
×
337

×
338
        return nil
×
339
}
340

341
func (opts *Opts) interactiveSetup() error {
×
342
        if err := opts.askClusterOptions(); err != nil {
×
343
                return err
×
344
        }
×
345

346
        if err := opts.askSampleDataQuestion(); err != nil {
×
347
                return err
×
348
        }
×
349

350
        if err := opts.askDBUserOptions(); err != nil {
×
351
                return err
×
352
        }
×
353

354
        return opts.askAccessListOptions()
×
355
}
356

357
func (opts *Opts) shouldAskForValue(f string) bool {
×
358
        _, isFlagSet := opts.flagSet[f]
×
359
        return !isFlagSet
×
360
}
×
361

362
func (opts *Opts) replaceWithDefaultSettings(values *clusterSettings) {
1✔
363
        if values.ClusterName != "" {
2✔
364
                opts.ClusterName = values.ClusterName
1✔
365
        }
1✔
366

367
        if values.Provider != "" {
2✔
368
                opts.Provider = values.Provider
1✔
369
        }
1✔
370

371
        if values.Region != "" {
2✔
372
                opts.Region = values.Region
1✔
373
        }
1✔
374

375
        if values.MdbVersion != "" {
1✔
376
                opts.MDBVersion = values.MdbVersion
×
377
        }
×
378

379
        if values.DBUsername != "" {
2✔
380
                opts.DBUsername = values.DBUsername
1✔
381
        }
1✔
382

383
        if values.DBUserPassword != "" {
2✔
384
                opts.DBUserPassword = values.DBUserPassword
1✔
385
        }
1✔
386

387
        if values.IPAddresses != nil {
2✔
388
                opts.IPAddresses = values.IPAddresses
1✔
389
        }
1✔
390

391
        opts.EnableTerminationProtection = values.EnableTerminationProtection
1✔
392
        opts.SkipSampleData = values.SkipSampleData
1✔
393
        opts.Tag = values.Tag
1✔
394
}
395

396
// setupCloseHandler creates a 'listener' on a new goroutine which will notify the
397
// program if it receives an interrupt from the OS. We then handle this by printing
398
// the dbUsername and dbPassword.
399
func (opts *Opts) setupCloseHandler() {
1✔
400
        sighandle.Notify(func(sig os.Signal) {
1✔
401
                fmt.Printf(setupTemplateCloseHandler, opts.ClusterName)
×
402
                telemetry.FinishTrackingCommand(telemetry.TrackOptions{
×
403
                        Signal: sig.String(),
×
404
                })
×
405
                os.Exit(0)
×
406
        }, os.Interrupt, syscall.SIGTERM)
×
407
}
408

409
func (opts *Opts) Run(ctx context.Context) error {
1✔
410
        if !opts.skipRegister {
1✔
411
                _, _ = fmt.Fprintf(opts.OutWriter, `
×
412
This command will help you:
×
413
1. Create and verify your MongoDB Atlas account in your browser.
×
414
2. Return to the terminal to create your first free MongoDB database in Atlas.
×
415
`)
×
416
                if err := opts.register.RegisterRun(ctx); err != nil {
×
417
                        return err
×
418
                }
×
419
        } else if !opts.skipLogin {
1✔
420
                _, _ = fmt.Fprintf(opts.OutWriter, `Next steps:
×
421
1. Log in and verify your MongoDB Atlas account in your browser.
×
422
2. Return to the terminal to create your first free MongoDB database in Atlas.
×
423
`)
×
424

×
425
                if err := opts.register.LoginRun(ctx); err != nil {
×
426
                        return err
×
427
                }
×
428
        }
429

430
        if err := opts.clusterPreRun(ctx, opts.OutWriter); err != nil {
1✔
431
                return err
×
432
        }
×
433

434
        if opts.config.ProjectID() == "" {
1✔
435
                return fmt.Errorf("%w: %s", errNeedsProject, config.Default().Name())
×
436
        }
×
437

438
        return opts.setupCluster()
1✔
439
}
440

441
func (opts *Opts) clusterPreRun(ctx context.Context, outWriter io.Writer) error {
1✔
442
        opts.setTier()
1✔
443
        defaultProfile := config.Default()
1✔
444

1✔
445
        return opts.PreRunE(
1✔
446
                opts.initStore(ctx),
1✔
447
                opts.register.SyncWithOAuthAccessProfile(defaultProfile),
1✔
448
                opts.register.InitFlow(defaultProfile),
1✔
449
                opts.InitOutput(outWriter, ""),
1✔
450
        )
1✔
451
}
1✔
452

453
func (opts *Opts) setupCluster() error {
1✔
454
        const base10 = 10
1✔
455
        opts.defaultName = "Cluster" + strconv.FormatInt(time.Now().Unix(), base10)[5:]
1✔
456
        opts.providerAndRegionToConstant()
1✔
457
        opts.trackFlags()
1✔
458

1✔
459
        if opts.CurrentIP {
1✔
460
                if publicIP := store.IPAddress(); publicIP != "" {
×
461
                        opts.IPAddresses = []string{publicIP}
×
462
                } else {
×
463
                        _, _ = log.Warning(setupTemplateIPNotFound)
×
464
                }
×
465
        }
466

467
        values, dErr := opts.newDefaultValues()
1✔
468
        if dErr != nil {
1✔
469
                return dErr
×
470
        }
×
471

472
        if opts.Confirm {
2✔
473
                opts.settings = defaultSettings
1✔
474
        } else {
1✔
475
                if err := opts.askConfirmDefaultQuestion(values); err != nil {
×
476
                        return err
×
477
                }
×
478
        }
479

480
        switch opts.settings {
1✔
481
        case customSettings:
×
482
                fmt.Print(setupTemplateIntro)
×
483

×
484
                if err := opts.interactiveSetup(); err != nil {
×
485
                        return err
×
486
                }
×
487
        case defaultSettings:
1✔
488
                opts.replaceWithDefaultSettings(values)
1✔
489
        case cancelSettings:
×
490
                _, _ = fmt.Println("user-aborted. Not creating cluster")
×
491
                return nil
×
492
        }
493

494
        // Create db user, access list and cluster
495
        if err := opts.createResources(); err != nil {
2✔
496
                return err
1✔
497
        }
1✔
498

499
        fmt.Printf(`We are deploying %s...
1✔
500
`, opts.ClusterName)
1✔
501

1✔
502
        fmt.Printf(setupTemplateStoreWarning, opts.DBUsername, opts.DBUserPassword)
1✔
503
        opts.setupCloseHandler()
1✔
504

1✔
505
        fmt.Print(setupTemplateCluster)
1✔
506

1✔
507
        // Watch cluster creation
1✔
508
        if _, er := opts.Watch(opts.clusterCreationWatcher); er != nil {
1✔
509
                return er
×
510
        }
×
511

512
        fmt.Println("Cluster created.")
1✔
513

1✔
514
        // Get cluster's connection string
1✔
515
        cluster, err := opts.store.LatestAtlasCluster(opts.ConfigProjectID(), opts.ClusterName)
1✔
516
        if err != nil {
1✔
517
                return err
×
518
        }
×
519

520
        opts.connectionString = cluster.ConnectionStrings.GetStandardSrv()
1✔
521

1✔
522
        fmt.Printf("Your connection string: %v\n", opts.connectionString)
1✔
523

1✔
524
        if err := opts.loadSampleData(); err != nil {
1✔
525
                return err
×
526
        }
×
527

528
        return opts.runConnectWith()
1✔
529
}
530

531
func (opts *Opts) runConnectWith() error {
1✔
532
        if opts.connectWith == "" {
2✔
533
                if opts.SkipMongosh { // deprecated flag --skipMongosh
2✔
534
                        return nil
1✔
535
                }
1✔
536

537
                if opts.Confirm { // --force
×
538
                        opts.connectWith = skipConnect
×
539
                } else {
×
540
                        if err := opts.promptConnect(); err != nil {
×
541
                                return err
×
542
                        }
×
543
                }
544
        }
545

546
        switch opts.connectWith {
×
547
        case skipConnect:
×
548
                _, _ = fmt.Fprintln(os.Stderr, "connection skipped")
×
549
        case compassConnect:
×
550
                if !compass.Detect() {
×
551
                        return compass.ErrCompassNotInstalled
×
552
                }
×
553
                if _, err := log.Warningln("Launching MongoDB Compass..."); err != nil {
×
554
                        return err
×
555
                }
×
556
                return compass.Run(opts.DBUsername, opts.DBUserPassword, opts.connectionString)
×
557
        case mongoshConnect:
×
558
                if !mongosh.Detect() {
×
559
                        return mongosh.ErrMongoshNotInstalled
×
560
                }
×
561
                return mongosh.Run(opts.DBUsername, opts.DBUserPassword, opts.connectionString)
×
562
        case vsCodeConnect:
×
563
                if !vscode.Detect() {
×
564
                        return vscode.ErrVsCodeCliNotInstalled
×
565
                }
×
566
                if _, err := log.Warningln("Launching VsCode..."); err != nil {
×
567
                        return err
×
568
                }
×
569
                return vscode.SaveConnection(opts.connectionString, opts.ClusterName, "atlas")
×
570
        }
571

572
        return nil
×
573
}
574

575
func (opts *Opts) promptConnect() error {
×
576
        p := &survey.Select{
×
577
                Message: "How would you like to connect to your cluster?",
×
578
                Options: connectWithOptions,
×
579
                Description: func(value string, _ int) string {
×
580
                        return connectWithDescription[value]
×
581
                },
×
582
        }
583

584
        return telemetry.TrackAskOne(p, &opts.connectWith, nil)
×
585
}
586

587
func (opts *Opts) PreRun(ctx context.Context) error {
1✔
588
        opts.skipRegister = true
1✔
589
        opts.skipLogin = true
1✔
590

1✔
591
        if err := validate.NoAPIKeys(); err != nil {
2✔
592
                // Why are we ignoring the error?
1✔
593
                // Because if the user has API keys, we just want to proceed with the flow
1✔
594
                // Then why not remove the error?
1✔
595
                // The error is useful in other components that call `validate.NoAPIKeys()`
1✔
596
                return nil
1✔
597
        }
1✔
598
        if err := opts.register.RefreshAccessToken(ctx); err != nil && errors.Is(err, cli.ErrInvalidRefreshToken) {
×
599
                opts.skipLogin = false
×
600
                return nil
×
601
        }
×
602
        if _, err := auth.AccountWithAccessToken(); err == nil {
×
603
                return nil
×
604
        }
×
605
        opts.skipRegister = false
×
606
        return nil
×
607
}
608

609
func (opts *Opts) initStore(ctx context.Context) func() error {
1✔
610
        return func() error {
2✔
611
                var err error
1✔
612
                opts.store, err = store.New(store.AuthenticatedPreset(config.Default()), store.WithContext(ctx))
1✔
613
                return err
1✔
614
        }
1✔
615
}
616

617
func (opts *Opts) setTier() {
1✔
618
        if config.CloudGovService == config.Service() && opts.Tier == DefaultAtlasTier {
1✔
619
                opts.Tier = defaultAtlasGovTier
×
620
        }
×
621
}
622

623
func (opts *Opts) SetupAtlasFlags(cmd *cobra.Command) {
1✔
624
        cmd.Flags().StringVar(&opts.Tier, flag.Tier, DefaultAtlasTier, usage.Tier)
1✔
625
        cmd.Flags().StringVar(&opts.Provider, flag.Provider, "", usage.Provider)
1✔
626
        cmd.Flags().StringVarP(&opts.Region, flag.Region, flag.RegionShort, "", usage.Region)
1✔
627
        cmd.Flags().StringSliceVar(&opts.IPAddresses, flag.AccessListIP, []string{}, usage.NetworkAccessListIPEntry)
1✔
628
        cmd.Flags().StringVar(&opts.DBUsername, flag.Username, "", usage.DBUsername)
1✔
629
        cmd.Flags().StringVar(&opts.DBUserPassword, flag.Password, "", usage.Password)
1✔
630
        cmd.Flags().BoolVar(&opts.EnableTerminationProtection, flag.EnableTerminationProtection, false, usage.EnableTerminationProtection)
1✔
631
        cmd.Flags().BoolVar(&opts.CurrentIP, flag.CurrentIP, false, usage.CurrentIPSimplified)
1✔
632
        cmd.Flags().StringToStringVar(&opts.Tag, flag.Tag, nil, usage.Tag)
1✔
633
        cmd.Flags().StringVar(&opts.AutoScalingMode, flag.AutoScalingMode, clusterWideScaling, usage.AutoScalingMode)
1✔
634

1✔
635
        opts.AddProjectOptsFlags(cmd)
1✔
636

1✔
637
        cmd.MarkFlagsMutuallyExclusive(flag.CurrentIP, flag.AccessListIP)
1✔
638
}
1✔
639

640
func (opts *Opts) SetupFlowFlags(cmd *cobra.Command) {
1✔
641
        cmd.Flags().BoolVar(&opts.SkipSampleData, flag.SkipSampleData, false, usage.SkipSampleData)
1✔
642
        cmd.Flags().BoolVar(&opts.SkipMongosh, flag.SkipMongosh, false, usage.SkipMongosh)
1✔
643
        cmd.Flags().BoolVar(&opts.Confirm, flag.Force, false, usage.ForceQuickstart)
1✔
644
        _ = cmd.Flags().MarkDeprecated(flag.SkipMongosh, "Use --connectWith instead")
1✔
645
        cmd.MarkFlagsMutuallyExclusive(flag.SkipMongosh, flag.ConnectWith)
1✔
646
}
1✔
647

648
func (opts *Opts) validateTier() error {
1✔
649
        opts.Tier = strings.ToUpper(opts.Tier)
1✔
650
        if opts.Tier == atlasM2 || opts.Tier == atlasM5 {
1✔
651
                _, _ = fmt.Fprintf(os.Stderr, deprecateMessageSharedTier, opts.Tier)
×
652
        }
×
653
        return nil
1✔
654
}
655

656
// Builder
657
// atlas setup
658
//
659
//        [--clusterName clusterName]
660
//        [--provider provider]
661
//        [--region regionName]
662
//        [--username username]
663
//        [--password password]
664
//        [--skipMongosh skipMongosh]
665
func Builder() *cobra.Command {
1✔
666
        opts := &Opts{}
1✔
667

1✔
668
        cmd := &cobra.Command{
1✔
669
                Use:     "setup",
1✔
670
                Aliases: []string{"quickstart"},
1✔
671
                Short:   "Register, authenticate, create, and access an Atlas cluster.",
1✔
672
                Long:    `This command takes you through registration, login, default profile creation, creating your first free tier cluster and connecting to it using MongoDB Shell.`,
1✔
673
                Example: `  # Override default cluster settings like name, provider, or database username by using the command options
1✔
674
  atlas setup --clusterName Test --provider GCP --username dbuserTest`,
1✔
675
                Hidden: false,
1✔
676
                Args:   require.NoArgs,
1✔
677
                PreRunE: func(cmd *cobra.Command, _ []string) error {
2✔
678
                        defaultProfile := config.Default()
1✔
679
                        opts.config = defaultProfile
1✔
680
                        opts.OutWriter = cmd.OutOrStdout()
1✔
681
                        opts.register.OutWriter = opts.OutWriter
1✔
682

1✔
683
                        if err := opts.register.SyncWithOAuthAccessProfile(defaultProfile)(); err != nil {
1✔
684
                                return err
×
685
                        }
×
686
                        if err := opts.register.InitFlow(defaultProfile)(); err != nil {
1✔
687
                                return err
×
688
                        }
×
689
                        if err := opts.PreRun(cmd.Context()); err != nil {
1✔
690
                                return nil
×
691
                        }
×
692
                        var preRun []prerun.CmdOpt
1✔
693
                        // registration pre run if applicable
1✔
694
                        if !opts.skipRegister {
1✔
695
                                preRun = append(preRun,
×
696
                                        opts.register.LoginPreRun(cmd.Context()),
×
697
                                        validate.NoAPIKeys,
×
698
                                        validate.NoAccessToken,
×
699
                                )
×
700
                        }
×
701

702
                        if !opts.skipLogin && opts.skipRegister {
1✔
703
                                preRun = append(preRun, opts.register.LoginPreRun(cmd.Context()))
×
704
                        }
×
705
                        preRun = append(preRun, opts.validateTier)
1✔
706
                        preRun = append(preRun, validate.AutoScalingMode(opts.AutoScalingMode))
1✔
707

1✔
708
                        return opts.PreRunE(preRun...)
1✔
709
                },
710
                RunE: func(cmd *cobra.Command, _ []string) error {
1✔
711
                        opts.flags = cmd.Flags()
1✔
712
                        return opts.Run(cmd.Context())
1✔
713
                },
1✔
714
        }
715

716
        // Register and login related
717
        cmd.Flags().BoolVar(&opts.register.IsGov, "gov", false, "Register with Atlas for Government.")
1✔
718
        cmd.Flags().BoolVar(&opts.register.NoBrowser, "noBrowser", false, "Don't try to open a browser session.")
1✔
719
        // Setup related
1✔
720
        cmd.Flags().StringVar(&opts.MDBVersion, flag.MDBVersion, "", usage.DeploymentMDBVersion)
1✔
721
        cmd.Flags().StringVar(&opts.connectWith, flag.ConnectWith, "", usage.ConnectWithAtlasSetup)
1✔
722
        opts.SetupAtlasFlags(cmd)
1✔
723
        opts.SetupFlowFlags(cmd)
1✔
724

1✔
725
        cmd.Flags().StringVar(&opts.ClusterName, flag.ClusterName, "", usage.ClusterName)
1✔
726
        cmd.Flags().BoolVarP(&opts.DefaultValue, flag.Default, "Y", false, usage.QuickstartDefault)
1✔
727
        _ = cmd.Flags().MarkDeprecated(flag.Default, "please use --force instead")
1✔
728

1✔
729
        return cmd
1✔
730
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc