Skip to content

Commit ca2af82

Browse files
author
Juan Jesús Padrón Hernández
committed
solve pr comments
1 parent 9aec524 commit ca2af82

16 files changed

Lines changed: 265 additions & 143 deletions

File tree

‎internal/cmd/alpha/sca/application/application.go‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ package application
33
import (
44
"github.com/spf13/cobra"
55

6-
"github.com/stackitcloud/stackit-cli/internal/cmd/sca/application/create"
7-
createfrompayload "github.com/stackitcloud/stackit-cli/internal/cmd/sca/application/create-from-payload"
8-
"github.com/stackitcloud/stackit-cli/internal/cmd/sca/application/delete"
9-
"github.com/stackitcloud/stackit-cli/internal/cmd/sca/application/describe"
10-
generatepayload "github.com/stackitcloud/stackit-cli/internal/cmd/sca/application/generate-payload"
11-
"github.com/stackitcloud/stackit-cli/internal/cmd/sca/application/list"
12-
"github.com/stackitcloud/stackit-cli/internal/cmd/sca/application/update"
13-
updatefrompayload "github.com/stackitcloud/stackit-cli/internal/cmd/sca/application/update-from-payload"
6+
"github.com/stackitcloud/stackit-cli/internal/cmd/alpha/sca/application/create"
7+
createfrompayload "github.com/stackitcloud/stackit-cli/internal/cmd/alpha/sca/application/create-from-payload"
8+
"github.com/stackitcloud/stackit-cli/internal/cmd/alpha/sca/application/delete"
9+
"github.com/stackitcloud/stackit-cli/internal/cmd/alpha/sca/application/describe"
10+
generatepayload "github.com/stackitcloud/stackit-cli/internal/cmd/alpha/sca/application/generate-payload"
11+
"github.com/stackitcloud/stackit-cli/internal/cmd/alpha/sca/application/list"
12+
"github.com/stackitcloud/stackit-cli/internal/cmd/alpha/sca/application/update"
13+
updatefrompayload "github.com/stackitcloud/stackit-cli/internal/cmd/alpha/sca/application/update-from-payload"
1414
"github.com/stackitcloud/stackit-cli/internal/pkg/args"
1515
"github.com/stackitcloud/stackit-cli/internal/pkg/types"
1616
"github.com/stackitcloud/stackit-cli/internal/pkg/utils"

‎internal/cmd/alpha/sca/application/create-from-payload/create_from_payload.go‎

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func NewCmd(params *types.CmdParams) *cobra.Command {
3737
Use: "create-from-payload",
3838
Short: "Create a SCA application from payload",
3939
Long: fmt.Sprintf("%s\n%s\n%s",
40-
"Create a STACKIT Kubernetes Engine (SCA) application from payload.",
40+
"Create a STACKIT Container Applications (SCA) application from payload.",
4141
`The payload can be provided as a JSON string or a file path prefixed with "@".`,
4242
"See https://docs.api.stackit.cloud/documentation/sca/version/v1alpha#tag/Applications/operation/Applications_CreateApplication for information regarding the payload structure.",
4343
),
@@ -91,9 +91,7 @@ func NewCmd(params *types.CmdParams) *cobra.Command {
9191
}
9292
}
9393

94-
outputResult(params.Printer, model, resp)
95-
96-
return nil
94+
return outputResult(params.Printer, model, resp)
9795
},
9896
}
9997

@@ -106,13 +104,19 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *sca.APIClie
106104
CreateApplicationPayload(*model.Payload)
107105
}
108106

109-
func outputResult(p *print.Printer, model *inputModel, application *sca.Application) {
110-
operationState := "Created"
111-
if model.Async {
112-
operationState = "Triggered creation of"
107+
func outputResult(p *print.Printer, model *inputModel, application *sca.Application) error {
108+
if application == nil {
109+
return fmt.Errorf("create application response is empty")
113110
}
114111

115-
p.Outputf("%s application for environment %s. Application ID: %s\n", operationState, application.GetEnvironmentId(), application.GetId())
112+
return p.OutputResult(model.OutputFormat, application, func() error {
113+
operationState := "Created"
114+
if model.Async {
115+
operationState = "Triggered creation of"
116+
}
117+
p.Outputf("%s application for environment %s. Application ID: %s\n", operationState, application.GetEnvironmentId(), application.GetId())
118+
return nil
119+
})
116120
}
117121

118122
func configureFlags(cmd *cobra.Command) {
@@ -140,7 +144,14 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel,
140144
payload = &sca.CreateApplicationPayload{}
141145
err := json.Unmarshal([]byte(*payloadValue), payload)
142146
if err != nil {
143-
return nil, fmt.Errorf("enconde payload: %w", err)
147+
return nil, fmt.Errorf("encode payload: %w", err)
148+
}
149+
}
150+
151+
if payload == nil {
152+
return nil, &errors.FlagValidationError{
153+
Flag: payloadFlag,
154+
Details: "Received empty payload",
144155
}
145156
}
146157

‎internal/cmd/alpha/sca/application/create-from-payload/create_from_payload_test.go‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,13 @@ func TestParseInput(t *testing.T) {
147147
}),
148148
isValid: false,
149149
},
150+
{
151+
desc: "empty json",
152+
flagValues: fixtureFlagValues(func(flagValues map[string]string) {
153+
flagValues[payloadFlag] = "{}"
154+
}),
155+
isValid: false,
156+
},
150157
}
151158

152159
for _, tt := range tests {

‎internal/cmd/alpha/sca/application/create/create.go‎

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,13 @@ const (
2424
environmentIDFlag = "environment-id"
2525
nameFlag = "name"
2626
// Container config
27-
imageFlag = "image"
28-
cpuFlag = "cpu"
29-
memoryFlag = "memory"
30-
envVarsFlag = "environment-vars"
31-
commandsFlag = "commands"
32-
argsFlag = "args"
27+
containerNameFlag = "container-name"
28+
imageFlag = "image"
29+
cpuFlag = "cpu"
30+
memoryFlag = "memory"
31+
envVarsFlag = "environment-vars"
32+
commandsFlag = "commands"
33+
argsFlag = "args"
3334
// Scaling
3435
instancesFlag = "instances"
3536
minInstancesFlag = "min-instances"
@@ -40,9 +41,7 @@ const (
4041
// Networking
4142
publicFlag = "public"
4243
externalPortFlag = "external-port"
43-
)
4444

45-
const (
4645
scalingTypeManual = "manual"
4746
scalingTypeAuto = "auto"
4847

@@ -65,6 +64,7 @@ type inputModel struct {
6564
*globalflags.GlobalFlagModel
6665
EnvironmentID string
6766
Name string
67+
ContainerName string
6868
Image string
6969
CPU int32
7070
Memory int32
@@ -86,7 +86,7 @@ func NewCmd(params *types.CmdParams) *cobra.Command {
8686
cmd := &cobra.Command{
8787
Use: "create",
8888
Short: "Create a SCA application",
89-
Long: "Create a STACKIT Kubernetes Engine (SCA) application.",
89+
Long: "Create a STACKIT Container Applications (SCA) application.",
9090
Args: args.NoArgs,
9191
Example: examples.Build(
9292
examples.NewExample(
@@ -97,7 +97,7 @@ func NewCmd(params *types.CmdParams) *cobra.Command {
9797
"$ stackit alpha sca application create --name application-name --image my-image --instances 2"),
9898
examples.NewExample(
9999
`Create a SCA application with name "application-name" and image "my-image" exposing port 8888 of the container`,
100-
"$ stackit alpha sca application create --name application-name --image my-image --port 8888"),
100+
"$ stackit alpha sca application create --name application-name --image my-image --external-port 8888"),
101101
examples.NewExample(
102102
`Create a SCA application with name "application-name" and image "my-image" disabling public networking`,
103103
"$ stackit alpha sca application create --name application-name --image my-image --public=false"),
@@ -141,9 +141,7 @@ func NewCmd(params *types.CmdParams) *cobra.Command {
141141
}
142142
}
143143

144-
outputResult(params.Printer, model, resp)
145-
146-
return nil
144+
return outputResult(params.Printer, model, resp)
147145
},
148146
}
149147

@@ -217,19 +215,26 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *sca.APIClie
217215
CreateApplicationPayload(payload)
218216
}
219217

220-
func outputResult(p *print.Printer, model *inputModel, application *sca.Application) {
221-
operationState := "Created"
222-
if model.Async {
223-
operationState = "Triggered creation of"
218+
func outputResult(p *print.Printer, model *inputModel, application *sca.Application) error {
219+
if application == nil {
220+
return fmt.Errorf("create application response is empty")
224221
}
225222

226-
p.Outputf("%s application for environment %s. Application ID: %s\n", operationState, application.GetEnvironmentId(), application.GetId())
223+
return p.OutputResult(model.OutputFormat, application, func() error {
224+
operationState := "Created"
225+
if model.Async {
226+
operationState = "Triggered creation of"
227+
}
228+
p.Outputf("%s application for environment %s. Application ID: %s\n", operationState, application.GetEnvironmentId(), application.GetId())
229+
return nil
230+
})
227231
}
228232

229233
func configureFlags(cmd *cobra.Command) {
230234
cmd.Flags().Var(flags.UUIDFlag(), environmentIDFlag, "Environment ID (uses default environment if not set)")
231235
cmd.Flags().String(nameFlag, "", "Application display name")
232236
// container
237+
cmd.Flags().String(containerNameFlag, defaultContainerName, "Container name")
233238
cmd.Flags().String(imageFlag, "", "Container image")
234239
cmd.Flags().Int32(cpuFlag, defaultCPU, "The dedicated virtual CPU processing power allocated per container instance")
235240
cmd.Flags().Int32(memoryFlag, defaultMemory, "The total amount of memory (RAM) allocated per container instance")
@@ -240,7 +245,7 @@ func configureFlags(cmd *cobra.Command) {
240245
scalingTypeFlag.Register(cmd.Flags())
241246
cmd.Flags().Int32(instancesFlag, defaultInstances, "The number of application instances (if manually scaled)")
242247
cmd.Flags().Int32(minInstancesFlag, 1, "The minimum number of application instances (if autoscaling is enabled)")
243-
cmd.Flags().Int32(maxInstancesFlag, 1, "The maximum number of application instances (if autoscaling is enabled)")
248+
cmd.Flags().Int32(maxInstancesFlag, 0, "The maximum number of application instances (if autoscaling is enabled)")
244249
cmd.Flags().Int32(rpsFlag, 0, "Target number of requests per second to trigger autoscaling (if autoscaling is enabled)")
245250
cmd.Flags().Int32(concurrencyFlag, 0, "Target number of in-flight requests to trigger autoscaling (if autoscaling is enabled)")
246251
cmd.Flags().Bool(scaleToZeroFlag, false, "Enable scale to zero (if autoscaling is enabled)")
@@ -283,11 +288,11 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel,
283288
}
284289
}
285290

286-
maxInstances := flags.FlagWithDefaultToInt32Value(p, cmd, maxInstancesFlag)
287-
if maxInstances == 0 {
288-
maxInstances = minInstances
291+
maxInstances := minInstances
292+
if i := flags.FlagToInt32Pointer(p, cmd, maxInstancesFlag); i != nil {
293+
maxInstances = *i
289294
}
290-
if maxInstances < minInstances || minInstances > 10 {
295+
if maxInstances < minInstances || maxInstances > 10 {
291296
return nil, &errors.FlagValidationError{
292297
Flag: minInstancesFlag,
293298
Details: fmt.Sprintf("must be an integer between minInstances (%d) and 10", minInstances),
@@ -303,10 +308,10 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel,
303308
}
304309

305310
cpu := flags.FlagWithDefaultToInt32Value(p, cmd, cpuFlag)
306-
if cpu%1000 != 0 {
311+
if cpu <= 0 || cpu%1000 != 0 {
307312
return nil, &errors.FlagValidationError{
308-
Flag: instancesFlag,
309-
Details: "must be divisible by 1000",
313+
Flag: cpuFlag,
314+
Details: "must be a valid value divisible by 1000",
310315
}
311316
}
312317

@@ -324,6 +329,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel,
324329
GlobalFlagModel: globalFlags,
325330
EnvironmentID: environmentID,
326331
Name: flags.FlagToStringValue(p, cmd, nameFlag),
332+
ContainerName: flags.FlagWithDefaultToStringValue(p, cmd, containerNameFlag),
327333
Image: flags.FlagToStringValue(p, cmd, imageFlag),
328334
CPU: cpu,
329335
Memory: flags.FlagWithDefaultToInt32Value(p, cmd, memoryFlag),

‎internal/cmd/alpha/sca/application/create/create_test.go‎

Lines changed: 77 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,17 @@ func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]st
3232

3333
environmentIDFlag: testEnvironmentID,
3434
nameFlag: "test-application-name",
35+
containerNameFlag: "my-container",
3536
imageFlag: "test-image",
3637
externalPortFlag: "8888",
3738
cpuFlag: "2000",
3839
memoryFlag: "2048",
3940
instancesFlag: "2",
4041
publicFlag: "true",
4142
scalingTypeFlag.Name(): scalingTypeManual,
42-
// minInstancesFlag: "",
43-
// maxInstancesFlag: "",
44-
// scaleToZeroFlag: "",
45-
envVarsFlag: "ENV1=val1,ENV2=val2",
46-
commandsFlag: "/bin/sh,-c",
47-
argsFlag: "echo 'test'",
43+
envVarsFlag: "ENV1=val1,ENV2=val2",
44+
commandsFlag: "/bin/sh,-c",
45+
argsFlag: "echo 'test'",
4846
}
4947
for _, mod := range mods {
5048
mod(flagValues)
@@ -61,13 +59,16 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel {
6159
},
6260
EnvironmentID: testEnvironmentID,
6361
Name: "test-application-name",
62+
ContainerName: "my-container",
6463
Image: "test-image",
6564
ContainerExternalPort: 8888,
6665
ScalingType: scalingTypeManual,
6766
Public: true,
6867
CPU: 2000,
6968
Memory: 2048,
7069
Instances: 2,
70+
MinInstances: 1,
71+
MaxInstances: 1,
7172
EnvironmentVars: map[string]string{
7273
"ENV1": "val1",
7374
"ENV2": "val2",
@@ -98,8 +99,10 @@ func fixturePayload(mods ...func(payload *sca.CreateApplicationPayload)) sca.Cre
9899
Port: new(int32(8888)),
99100
},
100101
Scaling: sca.Scaling{
101-
Type: sca.SCALINGTYPE_SCALING_TYPE_MANUAL,
102-
ManualScaling: &sca.ManualScaling{},
102+
Type: sca.SCALINGTYPE_SCALING_TYPE_MANUAL,
103+
ManualScaling: &sca.ManualScaling{
104+
Instances: 2,
105+
},
103106
},
104107
Containers: []sca.Container{{
105108
Name: "container-1",
@@ -222,6 +225,72 @@ func TestParseInput(t *testing.T) {
222225
}),
223226
isValid: false,
224227
},
228+
{
229+
desc: "invalid min instances",
230+
flagValues: fixtureFlagValues(func(flagValues map[string]string) {
231+
flagValues[minInstancesFlag] = "-2"
232+
}),
233+
isValid: false,
234+
},
235+
{
236+
desc: "valid autoscaling config",
237+
flagValues: fixtureFlagValues(func(flagValues map[string]string) {
238+
flagValues[scalingTypeFlag.Name()] = scalingTypeAuto
239+
delete(flagValues, instancesFlag)
240+
flagValues[minInstancesFlag] = "2"
241+
flagValues[maxInstancesFlag] = "3"
242+
flagValues[rpsFlag] = "5"
243+
}),
244+
expectedModel: fixtureInputModel(func(model *inputModel) {
245+
model.ScalingType = scalingTypeAuto
246+
model.Instances = defaultInstances
247+
model.MinInstances = 2
248+
model.MaxInstances = 3
249+
model.RPS = 5
250+
}),
251+
isValid: true,
252+
},
253+
{
254+
desc: "set min instances as max instances if not defined",
255+
flagValues: fixtureFlagValues(func(flagValues map[string]string) {
256+
flagValues[scalingTypeFlag.Name()] = scalingTypeAuto
257+
delete(flagValues, instancesFlag)
258+
delete(flagValues, maxInstancesFlag)
259+
flagValues[minInstancesFlag] = "2"
260+
flagValues[rpsFlag] = "5"
261+
}),
262+
expectedModel: fixtureInputModel(func(model *inputModel) {
263+
model.ScalingType = scalingTypeAuto
264+
model.Instances = defaultInstances
265+
model.MinInstances = 2
266+
model.MaxInstances = 2
267+
model.RPS = 5
268+
}),
269+
isValid: true,
270+
},
271+
{
272+
desc: "invalid max instances",
273+
flagValues: fixtureFlagValues(func(flagValues map[string]string) {
274+
// scalingTypeFlag.Set()
275+
flagValues[scalingTypeFlag.Name()] = scalingTypeAuto
276+
delete(flagValues, instancesFlag)
277+
flagValues[minInstancesFlag] = "2"
278+
flagValues[maxInstancesFlag] = "1"
279+
flagValues[rpsFlag] = "5"
280+
}),
281+
isValid: false,
282+
},
283+
{
284+
desc: "missing rps and concurrency if autoscaling is enabled",
285+
flagValues: fixtureFlagValues(func(flagValues map[string]string) {
286+
// scalingTypeFlag.Set()
287+
flagValues[scalingTypeFlag.Name()] = scalingTypeAuto
288+
delete(flagValues, instancesFlag)
289+
flagValues[minInstancesFlag] = "2"
290+
flagValues[maxInstancesFlag] = "5"
291+
}),
292+
isValid: false,
293+
},
225294
}
226295

227296
for _, tt := range tests {

0 commit comments

Comments
 (0)