@@ -15,25 +15,31 @@ import (
1515 "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags"
1616 "github.com/stackitcloud/stackit-cli/internal/pkg/print"
1717 "github.com/stackitcloud/stackit-cli/internal/pkg/services/sca/client"
18+ "github.com/stackitcloud/stackit-cli/internal/pkg/services/sca/utils"
1819 "github.com/stackitcloud/stackit-cli/internal/pkg/spinner"
1920 "github.com/stackitcloud/stackit-cli/internal/pkg/types"
2021)
2122
2223const (
2324 environmentIDFlag = "environment-id"
2425 nameFlag = "name"
25- imageFlag = "image"
26- publicFlag = "public"
27- externalPortFlag = "external-port"
28- cpuFlag = "cpu"
29- memoryFlag = "memory"
30- instancesFlag = "instances"
31- minInstancesFlag = "min-instances"
32- maxInstancesFlag = "max-instances"
33- scaleToZeroFlag = "scale-to-zero"
34- envVarsFlag = "environment-vars"
35- commandsFlag = "commands"
36- argsFlag = "args"
26+ // Container config
27+ imageFlag = "image"
28+ cpuFlag = "cpu"
29+ memoryFlag = "memory"
30+ envVarsFlag = "environment-vars"
31+ commandsFlag = "commands"
32+ argsFlag = "args"
33+ // Scaling
34+ instancesFlag = "instances"
35+ minInstancesFlag = "min-instances"
36+ maxInstancesFlag = "max-instances"
37+ scaleToZeroFlag = "scale-to-zero"
38+ rpsFlag = "http-rule-rps"
39+ concurrencyFlag = "http-rule-concurrency"
40+ // Networking
41+ publicFlag = "public"
42+ externalPortFlag = "external-port"
3743)
3844
3945const (
@@ -60,20 +66,20 @@ type inputModel struct {
6066 EnvironmentID string
6167 Name string
6268 Image string
63- ScalingType string
64- Public bool
65- ContainerExternalPort int32
6669 CPU int32
6770 Memory int32
71+ EnvironmentVars map [string ]string
72+ Commands []string
73+ Args []string
74+ ScalingType string
6875 Instances int32
6976 MinInstances int32
7077 MaxInstances int32
7178 ScaleToZero bool
7279 Concurrency int32
7380 RPS int32
74- EnvironmentVars map [string ]string
75- Commands []string
76- Args []string
81+ Public bool
82+ ContainerExternalPort int32
7783}
7884
7985func NewCmd (params * types.CmdParams ) * cobra.Command {
@@ -171,6 +177,7 @@ func buildScalingRules(model *inputModel) []sca.ScaleRule {
171177 if model .Concurrency != 0 || model .RPS != 0 {
172178 scaleRules = append (scaleRules , sca.ScaleRule {
173179 Type : sca .RULETYPE_RULE_TYPE_HTTP ,
180+ Name : "http-scaling-rule" ,
174181 HttpRule : & sca.HttpScaleRule {
175182 Concurrency : & model .Concurrency ,
176183 Rps : & model .RPS ,
@@ -187,17 +194,7 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *sca.APIClie
187194 Port : & model .ContainerExternalPort ,
188195 }
189196
190- var envVars []sca.EnvVar
191- if model .EnvironmentVars != nil {
192- envVars = make ([]sca.EnvVar , 0 , len (model .EnvironmentVars ))
193- for k , v := range model .EnvironmentVars {
194- envVars = append (envVars , sca.EnvVar {
195- Key : k ,
196- Value : v ,
197- Origin : sca .ENVVARTYPE_ENV_FROM_SOURCE_TYPE_MANUAL .Ptr (),
198- })
199- }
200- }
197+ envVars := utils .EnvironmentVariablesFromMap (model .EnvironmentVars )
201198
202199 container := sca.Container {
203200 Name : defaultContainerName ,
@@ -232,19 +229,24 @@ func outputResult(p *print.Printer, model *inputModel, application *sca.Applicat
232229func configureFlags (cmd * cobra.Command ) {
233230 cmd .Flags ().Var (flags .UUIDFlag (), environmentIDFlag , "Environment ID (uses default environment if not set)" )
234231 cmd .Flags ().String (nameFlag , "" , "Application display name" )
232+ // container
235233 cmd .Flags ().String (imageFlag , "" , "Container image" )
236- cmd .Flags ().Bool (publicFlag , defaultPublic , "Exposes your application securely to the public internet via HTTPS endpoint" )
237- cmd .Flags ().Int32 (externalPortFlag , defaultPort , "Container external exposed port" )
238234 cmd .Flags ().Int32 (cpuFlag , defaultCPU , "The dedicated virtual CPU processing power allocated per container instance" )
239235 cmd .Flags ().Int32 (memoryFlag , defaultMemory , "The total amount of memory (RAM) allocated per container instance" )
240- scalingTypeFlag .Register (cmd .Flags ())
241- cmd .Flags ().Int32 (instancesFlag , defaultInstances , "The number of application instances (if manually scaled)" )
242- cmd .Flags ().Int32 (minInstancesFlag , 0 , "The minimum number of application instances (if autoscaling is enabled)" )
243- cmd .Flags ().Int32 (maxInstancesFlag , 0 , "The maximum number of application instances (if autoscaling is enabled)" )
244- cmd .Flags ().Bool (scaleToZeroFlag , false , "Enable scale to zero (if autoscaling is enabled)" )
245236 cmd .Flags ().StringToString (envVarsFlag , nil , "Environment variables to inject into the application" )
246237 cmd .Flags ().StringSlice (commandsFlag , nil , "Commands to execute in the application container" )
247238 cmd .Flags ().StringSlice (argsFlag , nil , "Arguments to pass to the application container command" )
239+ // scaling
240+ scalingTypeFlag .Register (cmd .Flags ())
241+ cmd .Flags ().Int32 (instancesFlag , defaultInstances , "The number of application instances (if manually scaled)" )
242+ 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)" )
244+ cmd .Flags ().Int32 (rpsFlag , 0 , "Target number of requests per second to trigger autoscaling (if autoscaling is enabled)" )
245+ cmd .Flags ().Int32 (concurrencyFlag , 0 , "Target number of in-flight requests to trigger autoscaling (if autoscaling is enabled)" )
246+ cmd .Flags ().Bool (scaleToZeroFlag , false , "Enable scale to zero (if autoscaling is enabled)" )
247+ // networking
248+ cmd .Flags ().Bool (publicFlag , defaultPublic , "Exposes your application securely to the public internet via HTTPS endpoint" )
249+ cmd .Flags ().Int32 (externalPortFlag , defaultPort , "Container external exposed port" )
248250
249251 cobra .CheckErr (flags .MarkFlagsRequired (cmd , nameFlag ))
250252 cobra .CheckErr (flags .MarkFlagsRequired (cmd , imageFlag ))
@@ -261,12 +263,8 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel,
261263 scalingType = * scalingTypeFlagValue
262264 }
263265
264- extertalPort := flags .FlagWithDefaultToInt32Value (p , cmd , externalPortFlag )
265- if extertalPort <= 1024 || extertalPort > 65535 {
266- return nil , & errors.FlagValidationError {
267- Flag : externalPortFlag ,
268- Details : "must be a valid non-privileged port (from 1025 to 65535)" ,
269- }
266+ if err := validateScalingInput (cmd , scalingType ); err != nil {
267+ return nil , err
270268 }
271269
272270 instances := flags .FlagWithDefaultToInt32Value (p , cmd , instancesFlag )
@@ -277,6 +275,33 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel,
277275 }
278276 }
279277
278+ minInstances := flags .FlagWithDefaultToInt32Value (p , cmd , minInstancesFlag )
279+ if minInstances < 0 || minInstances > 10 {
280+ return nil , & errors.FlagValidationError {
281+ Flag : minInstancesFlag ,
282+ Details : "must be an integer between 0 and 10" ,
283+ }
284+ }
285+
286+ maxInstances := flags .FlagWithDefaultToInt32Value (p , cmd , maxInstancesFlag )
287+ if maxInstances == 0 {
288+ maxInstances = minInstances
289+ }
290+ if maxInstances < minInstances || minInstances > 10 {
291+ return nil , & errors.FlagValidationError {
292+ Flag : minInstancesFlag ,
293+ Details : fmt .Sprintf ("must be an integer between minInstances (%d) and 10" , minInstances ),
294+ }
295+ }
296+
297+ extertalPort := flags .FlagWithDefaultToInt32Value (p , cmd , externalPortFlag )
298+ if extertalPort <= 1024 || extertalPort > 65535 {
299+ return nil , & errors.FlagValidationError {
300+ Flag : externalPortFlag ,
301+ Details : "must be a valid non-privileged port (from 1025 to 65535)" ,
302+ }
303+ }
304+
280305 cpu := flags .FlagWithDefaultToInt32Value (p , cmd , cpuFlag )
281306 if cpu % 1000 != 0 {
282307 return nil , & errors.FlagValidationError {
@@ -300,20 +325,57 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel,
300325 EnvironmentID : environmentID ,
301326 Name : flags .FlagToStringValue (p , cmd , nameFlag ),
302327 Image : flags .FlagToStringValue (p , cmd , imageFlag ),
303- Public : flags .FlagToBoolValue (p , cmd , publicFlag ),
304- ContainerExternalPort : extertalPort ,
305328 CPU : cpu ,
306329 Memory : flags .FlagWithDefaultToInt32Value (p , cmd , memoryFlag ),
307- Instances : instances ,
308- ScalingType : scalingType ,
309- MinInstances : flags .FlagWithDefaultToInt32Value (p , cmd , minInstancesFlag ),
310- MaxInstances : flags .FlagWithDefaultToInt32Value (p , cmd , maxInstancesFlag ),
311- ScaleToZero : flags .FlagToBoolValue (p , cmd , scaleToZeroFlag ),
312330 EnvironmentVars : envVars ,
313331 Commands : flags .FlagToStringSliceValue (p , cmd , commandsFlag ),
314332 Args : flags .FlagToStringSliceValue (p , cmd , argsFlag ),
333+ ScalingType : scalingType ,
334+ Instances : instances ,
335+ MinInstances : minInstances ,
336+ MaxInstances : maxInstances ,
337+ ScaleToZero : flags .FlagToBoolValue (p , cmd , scaleToZeroFlag ),
338+ RPS : flags .FlagWithDefaultToInt32Value (p , cmd , rpsFlag ),
339+ Concurrency : flags .FlagWithDefaultToInt32Value (p , cmd , concurrencyFlag ),
340+ Public : flags .FlagToBoolValue (p , cmd , publicFlag ),
341+ ContainerExternalPort : extertalPort ,
315342 }
316343
317344 p .DebugInputModel (model )
318345 return & model , nil
319346}
347+
348+ func validateScalingInput (cmd * cobra.Command , scalingType string ) error {
349+ switch scalingType {
350+ case scalingTypeManual :
351+ autoFlags := []string {minInstancesFlag , maxInstancesFlag , scaleToZeroFlag , concurrencyFlag , rpsFlag }
352+ for _ , flagName := range autoFlags {
353+ if cmd .Flags ().Changed (flagName ) {
354+ return & errors.FlagValidationError {
355+ Flag : flagName ,
356+ Details : fmt .Sprintf ("is only valid when --scaling-type is %q" , scalingTypeAuto ),
357+ }
358+ }
359+ }
360+ case scalingTypeAuto :
361+ if cmd .Flags ().Changed (instancesFlag ) {
362+ return & errors.FlagValidationError {
363+ Flag : instancesFlag ,
364+ Details : fmt .Sprintf ("is only valid when --scaling-type is %q" , scalingTypeManual ),
365+ }
366+ }
367+ if ! cmd .Flags ().Changed (rpsFlag ) && ! cmd .Flags ().Changed (concurrencyFlag ) {
368+ return & errors.OneOfFlagsIsMissing {
369+ MissingFlags : []string {rpsFlag , concurrencyFlag },
370+ SetFlag : fmt .Sprintf ("--%s=%s" , scalingTypeFlag .Name (), scalingTypeAuto ),
371+ }
372+ }
373+ default :
374+ return & errors.FlagValidationError {
375+ Flag : scalingType ,
376+ Details : "invalid scaling type" ,
377+ }
378+ }
379+
380+ return nil
381+ }
0 commit comments