@@ -16,21 +16,28 @@ package clusters
1616
1717import (
1818 "context"
19+ "errors"
1920 "fmt"
2021
2122 "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli"
2223 "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/require"
2324 "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/config"
2425 "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/file"
2526 "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/flag"
27+ "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/pointer"
2628 "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/store"
2729 "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/usage"
2830 "github.com/spf13/afero"
2931 "github.com/spf13/cobra"
32+ atlasv2 "go.mongodb.org/atlas-sdk/v20241113002/admin"
3033 atlas "go.mongodb.org/atlas/mongodbatlas"
3134)
3235
33- const upgradeTemplate = "Upgrading cluster '{{.Name}}'.\n "
36+ const (
37+ upgradeTemplate = "Upgrading cluster '{{.Name}}'.\n "
38+ replicaSetNodeCount = 3
39+ replicaSetPriority = 7
40+ )
3441
3542type UpgradeOpts struct {
3643 cli.ProjectOpts
@@ -42,6 +49,7 @@ type UpgradeOpts struct {
4249 filename string
4350 enableTerminationProtection bool
4451 disableTerminationProtection bool
52+ isFlexCluster bool
4553 tag map [string ]string
4654 fs afero.Fs
4755 store store.AtlasSharedClusterGetterUpgrader
@@ -56,6 +64,28 @@ func (opts *UpgradeOpts) initStore(ctx context.Context) func() error {
5664}
5765
5866func (opts * UpgradeOpts ) Run () error {
67+ if opts .isFlexCluster {
68+ return opts .RunFlexCluster ()
69+ }
70+
71+ return opts .RunSharedCluster ()
72+ }
73+
74+ func (opts * UpgradeOpts ) RunFlexCluster () error {
75+ cluster , err := opts .atlasTenantClusterUpgradeRequest20240805 ()
76+ if err != nil {
77+ return err
78+ }
79+
80+ r , err := opts .store .UpgradeFlexCluster (opts .ConfigProjectID (), cluster )
81+ if err != nil {
82+ return err
83+ }
84+
85+ return opts .Print (r )
86+ }
87+
88+ func (opts * UpgradeOpts ) RunSharedCluster () error {
5989 cluster , err := opts .cluster ()
6090 if err != nil {
6191 return err
@@ -72,18 +102,113 @@ func (opts *UpgradeOpts) Run() error {
72102 return opts .Print (r )
73103}
74104
105+ func (opts * UpgradeOpts ) atlasTenantClusterUpgradeRequest20240805 () (* atlasv2.AtlasTenantClusterUpgradeRequest20240805 , error ) {
106+ var cluster * atlasv2.AtlasTenantClusterUpgradeRequest20240805
107+ if opts .filename != "" {
108+ err := file .Load (opts .fs , opts .filename , & cluster )
109+ if err != nil {
110+ return nil , err
111+ }
112+
113+ if opts .name == "" {
114+ opts .name = cluster .Name
115+ }
116+ return cluster , nil
117+ }
118+
119+ flexClusterDescription , err := opts .store .FlexCluster (opts .ProjectID , opts .name )
120+ if err != nil {
121+ return nil , err
122+ }
123+
124+ return opts .newAtlasTenantClusterUpgradeRequestFromFlexClusterDescription (flexClusterDescription ), nil
125+ }
126+
127+ func (opts * UpgradeOpts ) newAtlasTenantClusterUpgradeRequestFromFlexClusterDescription (flexCluster * atlasv2.FlexClusterDescription20241113 ) * atlasv2.AtlasTenantClusterUpgradeRequest20240805 {
128+ mdbVersion := flexCluster .MongoDBVersion
129+ if opts .mdbVersion != "" {
130+ mdbVersion = & opts .mdbVersion
131+ }
132+
133+ terminationProtectionEnabled := flexCluster .TerminationProtectionEnabled
134+ if opts .disableTerminationProtection {
135+ terminationProtectionEnabled = pointer .Get (false )
136+ }
137+
138+ if opts .enableTerminationProtection {
139+ terminationProtectionEnabled = pointer .Get (true )
140+ }
141+
142+ var tags []atlasv2.ResourceTag
143+ if flexCluster .Tags != nil {
144+ tags = * flexCluster .Tags
145+ }
146+
147+ if len (opts .tag ) > 0 {
148+ newTags := newResourceTags (opts .tag )
149+ tags = append (tags , * newTags ... )
150+ }
151+
152+ backupEnabled := false
153+ if flexCluster .BackupSettings != nil {
154+ backupEnabled = * flexCluster .BackupSettings .Enabled
155+ }
156+
157+ return & atlasv2.AtlasTenantClusterUpgradeRequest20240805 {
158+ BackupEnabled : & backupEnabled ,
159+ ClusterType : flexCluster .ClusterType ,
160+ GroupId : flexCluster .GroupId ,
161+ MongoDBVersion : mdbVersion ,
162+ Name : * flexCluster .Name ,
163+ Tags : & tags ,
164+ TerminationProtectionEnabled : terminationProtectionEnabled ,
165+ VersionReleaseSystem : flexCluster .VersionReleaseSystem ,
166+ ReplicationSpecs : opts .newReplicationSpecFromOpts (flexCluster ),
167+ }
168+ }
169+
170+ func (opts * UpgradeOpts ) newReplicationSpecFromOpts (flexCluster * atlasv2.FlexClusterDescription20241113 ) * []atlasv2.ReplicationSpec20240805 {
171+ if opts .tier == "" {
172+ return nil
173+ }
174+
175+ diskSizeGb := flexCluster .ProviderSettings .DiskSizeGB
176+ if opts .diskSizeGB != 0 {
177+ diskSizeGb = & opts .diskSizeGB
178+ }
179+
180+ replicaSpec := atlasv2.ReplicationSpec20240805 {
181+ RegionConfigs : & []atlasv2.CloudRegionConfig20240805 {
182+ {
183+ ElectableSpecs : & atlasv2.HardwareSpec20240805 {
184+ InstanceSize : & opts .tier ,
185+ DiskSizeGB : diskSizeGb ,
186+ NodeCount : pointer .Get (replicaSetNodeCount ),
187+ },
188+ ProviderName : flexCluster .ProviderSettings .BackingProviderName ,
189+ RegionName : flexCluster .ProviderSettings .RegionName ,
190+ Priority : pointer .Get (replicaSetPriority ),
191+ },
192+ },
193+ }
194+
195+ return & []atlasv2.ReplicationSpec20240805 {replicaSpec }
196+ }
197+
75198func (opts * UpgradeOpts ) cluster () (* atlas.Cluster , error ) {
76199 var cluster * atlas.Cluster
77200 if opts .filename != "" {
78201 err := file .Load (opts .fs , opts .filename , & cluster )
79202 if err != nil {
80203 return nil , err
81204 }
205+
82206 if opts .name == "" {
83207 opts .name = cluster .Name
84208 }
85209 return cluster , nil
86210 }
211+
87212 return opts .store .AtlasSharedCluster (opts .ProjectID , opts .name )
88213}
89214
@@ -129,6 +254,26 @@ func isTenant(instanceSizeName string) bool {
129254 instanceSizeName == atlasM5
130255}
131256
257+ // newIsFlexCluster sets the opts.isFlexCluster that indicates if the cluster to create is
258+ // a FlexCluster. The function calls the AtlasSharedAPI to get the cluster, and it sets the opts.isFlexCluster = true
259+ // in the event of a cannotUseFlexWithClusterApisErrorCode.
260+ func (opts * UpgradeOpts ) newIsFlexCluster () error {
261+ _ , err := opts .store .AtlasSharedCluster (opts .ProjectID , opts .name )
262+ var errorResponse * atlas.ErrorResponse
263+ ok := errors .As (err , & errorResponse )
264+ if ! ok {
265+ opts .isFlexCluster = false
266+ return err
267+ }
268+
269+ if errorResponse .ErrorCode != cannotUseFlexWithClusterApisErrorCode {
270+ return err
271+ }
272+
273+ opts .isFlexCluster = true
274+ return nil
275+ }
276+
132277// UpgradeBuilder builds a cobra.Command that can run as:
133278// atlas cluster(s) upgrade [clusterName] --projectId projectId [--tier M#] [--diskSizeGB N] [--mdbVersion] [--tag key=value].
134279func UpgradeBuilder () * cobra.Command {
@@ -152,6 +297,7 @@ func UpgradeBuilder() *cobra.Command {
152297 opts .ValidateProjectID ,
153298 opts .initStore (cmd .Context ()),
154299 opts .InitOutput (cmd .OutOrStdout (), upgradeTemplate ),
300+ opts .newIsFlexCluster ,
155301 )
156302 },
157303 RunE : func (_ * cobra.Command , _ []string ) error {
0 commit comments