Skip to content

Commit c73361f

Browse files
hcsa73Henrique Santos
andauthored
MongoDBFlex instance creation uses latest available version by default (#63)
* Add functionality * Generate docs * Fix tests --------- Co-authored-by: Henrique Santos <[email protected]>
1 parent 6aa2e57 commit c73361f

File tree

6 files changed

+123
-18
lines changed

6 files changed

+123
-18
lines changed

docs/stackit_mongodbflex_instance_create.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ stackit mongodbflex instance create [flags]
3636
--storage-class string Storage class (default "premium-perf2-mongodb")
3737
--storage-size int Storage size (in GB) (default 10)
3838
--type string Instance type, one of ["Replica" "Sharded" "Single"] (default "Replica")
39-
--version string Version (default "6.0")
39+
--version string MongoDB version. Defaults to the latest version available
4040
```
4141

4242
### Options inherited from parent commands

internal/cmd/mongodbflex/instance/create/create.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ const (
3838
defaultStorageClass = "premium-perf2-mongodb"
3939
defaultStorageSize = 10
4040
defaultType = "Replica"
41-
defaultVersion = "6.0"
4241
)
4342

4443
type inputModel struct {
@@ -100,6 +99,15 @@ func NewCmd() *cobra.Command {
10099
}
101100
}
102101

102+
// Fill in version, if needed
103+
if model.Version == nil {
104+
version, err := mongodbflexUtils.GetLatestMongoDBVersion(ctx, apiClient, model.ProjectId)
105+
if err != nil {
106+
return fmt.Errorf("get latest MongoDB version: %w", err)
107+
}
108+
model.Version = &version
109+
}
110+
103111
// Call API
104112
req, err := buildRequest(ctx, model, apiClient)
105113
if err != nil {
@@ -145,7 +153,7 @@ func configureFlags(cmd *cobra.Command) {
145153
cmd.Flags().Int64(ramFlag, 0, "Amount of RAM (in GB)")
146154
cmd.Flags().String(storageClassFlag, defaultStorageClass, "Storage class")
147155
cmd.Flags().Int64(storageSizeFlag, defaultStorageSize, "Storage size (in GB)")
148-
cmd.Flags().String(versionFlag, defaultVersion, "Version")
156+
cmd.Flags().String(versionFlag, "", "MongoDB version. Defaults to the latest version available")
149157
cmd.Flags().Var(flags.EnumFlag(false, defaultType, typeFlagOptions...), typeFlag, fmt.Sprintf("Instance type, one of %q", typeFlagOptions))
150158

151159
err := flags.MarkFlagsRequired(cmd, instanceNameFlag, aclFlag)
@@ -187,7 +195,7 @@ func parseInput(cmd *cobra.Command) (*inputModel, error) {
187195
RAM: ram,
188196
StorageClass: utils.Ptr(flags.FlagWithDefaultToStringValue(cmd, storageClassFlag)),
189197
StorageSize: &storageSize,
190-
Version: utils.Ptr(flags.FlagWithDefaultToStringValue(cmd, versionFlag)),
198+
Version: flags.FlagToStringPointer(cmd, versionFlag),
191199
Type: utils.Ptr(flags.FlagWithDefaultToStringValue(cmd, typeFlag)),
192200
}, nil
193201
}

internal/cmd/mongodbflex/instance/create/create_test.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,6 @@ func TestParseInput(t *testing.T) {
136136
description: "with defaults",
137137
flagValues: fixtureFlagValues(func(flagValues map[string]string) {
138138
delete(flagValues, backupScheduleFlag)
139-
delete(flagValues, versionFlag)
140139
delete(flagValues, typeFlag)
141140
}),
142141
isValid: true,
@@ -204,6 +203,16 @@ func TestParseInput(t *testing.T) {
204203
}),
205204
isValid: false,
206205
},
206+
{
207+
description: "no version",
208+
flagValues: fixtureFlagValues(func(flagValues map[string]string) {
209+
delete(flagValues, versionFlag)
210+
}),
211+
isValid: true,
212+
expectedModel: fixtureInputModel(func(model *inputModel) {
213+
model.Version = nil
214+
}),
215+
},
207216
{
208217
description: "repeated acl flags",
209218
flagValues: fixtureFlagValues(),

internal/cmd/postgresflex/instance/create/create.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ func NewCmd() *cobra.Command {
9999
}
100100
}
101101

102-
// Fill in defautl version, if needed
102+
// Fill in version, if needed
103103
if model.Version == nil {
104104
version, err := postgresflexUtils.GetLatestPostgreSQLVersion(ctx, apiClient, model.ProjectId)
105105
if err != nil {

internal/pkg/services/mongodbflex/utils/utils.go

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"strings"
77

88
"github.com/stackitcloud/stackit-cli/internal/pkg/errors"
9+
"golang.org/x/mod/semver"
910

1011
"github.com/stackitcloud/stackit-sdk-go/services/mongodbflex"
1112
)
@@ -17,14 +18,6 @@ var instanceTypeToReplicas = map[string]int64{
1718
"Sharded": 9,
1819
}
1920

20-
func GetUserName(ctx context.Context, apiClient MongoDBFlexClient, projectId, instanceId, userId string) (string, error) {
21-
resp, err := apiClient.GetUserExecute(ctx, projectId, instanceId, userId)
22-
if err != nil {
23-
return "", fmt.Errorf("get MongoDBFlex user: %w", err)
24-
}
25-
return *resp.Item.Username, nil
26-
}
27-
2821
func AvailableInstanceTypes() []string {
2922
instanceTypes := make([]string, len(instanceTypeToReplicas))
3023
i := 0
@@ -118,14 +111,45 @@ func LoadFlavorId(cpu, ram int64, flavors *[]mongodbflex.HandlersInfraFlavor) (*
118111
}
119112

120113
type MongoDBFlexClient interface {
114+
ListVersionsExecute(ctx context.Context, projectId string) (*mongodbflex.ListVersionsResponse, error)
121115
GetInstanceExecute(ctx context.Context, projectId, instanceId string) (*mongodbflex.GetInstanceResponse, error)
122116
GetUserExecute(ctx context.Context, projectId, instanceId, userId string) (*mongodbflex.GetUserResponse, error)
123117
}
124118

119+
func GetLatestMongoDBVersion(ctx context.Context, apiClient MongoDBFlexClient, projectId string) (string, error) {
120+
resp, err := apiClient.ListVersionsExecute(ctx, projectId)
121+
if err != nil {
122+
return "", fmt.Errorf("get MongoDB versions: %w", err)
123+
}
124+
versions := *resp.Versions
125+
126+
latestVersion := "0"
127+
for i := range versions {
128+
oldSemVer := fmt.Sprintf("v%s", latestVersion)
129+
newSemVer := fmt.Sprintf("v%s", versions[i])
130+
if semver.Compare(newSemVer, oldSemVer) != 1 {
131+
continue
132+
}
133+
latestVersion = versions[i]
134+
}
135+
if latestVersion == "0" {
136+
return "", fmt.Errorf("no MongoDB versions found")
137+
}
138+
return latestVersion, nil
139+
}
140+
125141
func GetInstanceName(ctx context.Context, apiClient MongoDBFlexClient, projectId, instanceId string) (string, error) {
126142
resp, err := apiClient.GetInstanceExecute(ctx, projectId, instanceId)
127143
if err != nil {
128144
return "", fmt.Errorf("get MongoDBFlex instance: %w", err)
129145
}
130146
return *resp.Item.Name, nil
131147
}
148+
149+
func GetUserName(ctx context.Context, apiClient MongoDBFlexClient, projectId, instanceId, userId string) (string, error) {
150+
resp, err := apiClient.GetUserExecute(ctx, projectId, instanceId, userId)
151+
if err != nil {
152+
return "", fmt.Errorf("get MongoDBFlex user: %w", err)
153+
}
154+
return *resp.Item.Username, nil
155+
}

internal/pkg/services/mongodbflex/utils/utils_test.go

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,19 @@ const (
2424
)
2525

2626
type mongoDBFlexClientMocked struct {
27-
getInstanceFails bool
28-
getInstanceResp *mongodbflex.GetInstanceResponse
29-
getUserFails bool
30-
getUserResp *mongodbflex.GetUserResponse
27+
listVersionsFails bool
28+
listVersionsResp *mongodbflex.ListVersionsResponse
29+
getInstanceFails bool
30+
getInstanceResp *mongodbflex.GetInstanceResponse
31+
getUserFails bool
32+
getUserResp *mongodbflex.GetUserResponse
33+
}
34+
35+
func (m *mongoDBFlexClientMocked) ListVersionsExecute(_ context.Context, _ string) (*mongodbflex.ListVersionsResponse, error) {
36+
if m.listVersionsFails {
37+
return nil, fmt.Errorf("could not list versions")
38+
}
39+
return m.listVersionsResp, nil
3140
}
3241

3342
func (m *mongoDBFlexClientMocked) GetInstanceExecute(_ context.Context, _, _ string) (*mongodbflex.GetInstanceResponse, error) {
@@ -355,6 +364,61 @@ func TestLoadFlavorId(t *testing.T) {
355364
}
356365
}
357366

367+
func TestGetLatestPostgreSQLVersion(t *testing.T) {
368+
tests := []struct {
369+
description string
370+
listVersionsFails bool
371+
listVersionsResp *mongodbflex.ListVersionsResponse
372+
isValid bool
373+
expectedOutput string
374+
}{
375+
{
376+
description: "base",
377+
listVersionsResp: &mongodbflex.ListVersionsResponse{
378+
Versions: &[]string{"8", "10", "9"},
379+
},
380+
isValid: true,
381+
expectedOutput: "10",
382+
},
383+
{
384+
description: "get instance fails",
385+
listVersionsFails: true,
386+
isValid: false,
387+
},
388+
{
389+
description: "no versions",
390+
listVersionsResp: &mongodbflex.ListVersionsResponse{
391+
Versions: &[]string{},
392+
},
393+
isValid: false,
394+
},
395+
}
396+
397+
for _, tt := range tests {
398+
t.Run(tt.description, func(t *testing.T) {
399+
client := &mongoDBFlexClientMocked{
400+
listVersionsFails: tt.listVersionsFails,
401+
listVersionsResp: tt.listVersionsResp,
402+
}
403+
404+
output, err := GetLatestMongoDBVersion(context.Background(), client, testProjectId)
405+
406+
if tt.isValid && err != nil {
407+
t.Errorf("failed on valid input")
408+
}
409+
if !tt.isValid && err == nil {
410+
t.Errorf("did not fail on invalid input")
411+
}
412+
if !tt.isValid {
413+
return
414+
}
415+
if output != tt.expectedOutput {
416+
t.Errorf("expected output to be %s, got %s", tt.expectedOutput, output)
417+
}
418+
})
419+
}
420+
}
421+
358422
func TestGetInstanceName(t *testing.T) {
359423
tests := []struct {
360424
description string

0 commit comments

Comments
 (0)