From 898354cb9fc9c08a06f23450e073b325c4dd36ae Mon Sep 17 00:00:00 2001 From: Steven Craig Date: Wed, 7 Oct 2020 22:46:54 -0400 Subject: [PATCH 1/4] surprisingly, this might be pretty close to working in terms of accepting and parsing the flag. i do not think that it will actually take appropriate action on the flags though --- .gitignore | 1 + .../cli/compose/entity/service/service.go | 57 ++++++++++--- .../modules/cli/compose/project/project.go | 5 ++ .../service/compose_service_command.go | 18 +++- ecs-cli/modules/commands/flags/flags.go | 1 + ecs-cli/modules/utils/utils.go | 85 +++++++++++++++++-- 6 files changed, 148 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index 423c55157..949a13041 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ ecs-cli/vendor/pkg ecs-cli/.vscode/* ecs-cli/.idea .idea/* +.DS_Store \ No newline at end of file diff --git a/ecs-cli/modules/cli/compose/entity/service/service.go b/ecs-cli/modules/cli/compose/entity/service/service.go index 96c3f4463..2efae9e77 100644 --- a/ecs-cli/modules/cli/compose/entity/service/service.go +++ b/ecs-cli/modules/cli/compose/entity/service/service.go @@ -41,15 +41,16 @@ import ( // Service type is placeholder for a single task definition and its cache // and it performs operations on ECS Service level type Service struct { - taskDef *ecs.TaskDefinition - cache cache.Cache - ecsContext *context.ECSContext - deploymentConfig *ecs.DeploymentConfiguration - loadBalancers []*ecs.LoadBalancer - role string - healthCheckGP *int64 - serviceRegistries []*ecs.ServiceRegistry - tags []*ecs.Tag + taskDef *ecs.TaskDefinition + cache cache.Cache + ecsContext *context.ECSContext + deploymentConfig *ecs.DeploymentConfiguration + loadBalancers []*ecs.LoadBalancer + capacityProviderStrategy []*ecs.CapacityProviderStrategyItem + role string + healthCheckGP *int64 + serviceRegistries []*ecs.ServiceRegistry + tags []*ecs.Tag } const ( @@ -105,6 +106,9 @@ func (s *Service) LoadContext() error { return err } + // Capacity Provider Strategy + capacityProviders := s.Context().CLIContext.StringSlice(flags.CapacityProviderStrategyFlag) + // Health Check Grace Period healthCheckGP, err := getInt64FromCLIContext(s.Context(), flags.HealthCheckGracePeriodFlag) if err != nil { @@ -152,6 +156,12 @@ func (s *Service) LoadContext() error { return err } s.loadBalancers = append(s.loadBalancers, loadBalancers...) + + capacityProviderStrategy, err := utils.ParseCapacityProviders(capacityProviders) + if err != nil { + return err + } + s.capacityProviderStrategy = append(s.capacityProviderStrategy, capacityProviderStrategy...) } s.role = role return nil @@ -497,6 +507,8 @@ func (s *Service) GetTags() ([]*ecs.Tag, error) { // ----------- Commands' helper functions -------- +// i think this is what needs to be modified so that instead of just a launchType it could also take a capacity provider (strategy) + func (s *Service) buildCreateServiceInput(serviceName, taskDefName string, desiredCount int) (*ecs.CreateServiceInput, error) { launchType := s.Context().CommandConfig.LaunchType cluster := s.Context().CommandConfig.Cluster @@ -569,10 +581,31 @@ func (s *Service) buildCreateServiceInput(serviceName, taskDefName string, desir createServiceInput.PlacementStrategy = placementStrategy } - if launchType != "" { - createServiceInput.LaunchType = aws.String(launchType) + // i think this is getting a default value somewhere so it is never blank + // just comment it out entirely and substitute a hard-coded capacity provider + /* + if launchType != "" { + createServiceInput.LaunchType = aws.String(launchType) + } + */ + + // https://docs.aws.amazon.com/sdk-for-go/api/service/ecs/#CreateServiceInput + var strategyItemList []*ecs.CapacityProviderStrategyItem + + base := int64(1) + weight := int64(1) + strategy := "de-dev-application-capacity-provider" + + strategyItem := ecs.CapacityProviderStrategyItem{ + Base: &base, + CapacityProvider: &strategy, + Weight: &weight, } + strategyItemList = append(strategyItemList, &strategyItem) + + createServiceInput.CapacityProviderStrategy = strategyItemList + if err = createServiceInput.Validate(); err != nil { return nil, err } @@ -604,6 +637,8 @@ func (s *Service) buildCreateServiceInput(serviceName, taskDefName string, desir } } + // fmt.Println(createServiceInput) + return createServiceInput, nil } diff --git a/ecs-cli/modules/cli/compose/project/project.go b/ecs-cli/modules/cli/compose/project/project.go index 145f89fe3..a711d336a 100644 --- a/ecs-cli/modules/cli/compose/project/project.go +++ b/ecs-cli/modules/cli/compose/project/project.go @@ -221,6 +221,11 @@ func (p *ecsProject) transformTaskDefinition() error { } p.entity.SetTaskDefinition(taskDefinition) + + // i think this is where we can get the task definition out of here + // fmt.Println(taskDefinition) + // i can but really what i want is the create-service call + return nil } diff --git a/ecs-cli/modules/commands/compose/service/compose_service_command.go b/ecs-cli/modules/commands/compose/service/compose_service_command.go index 887d02aab..32a745fbc 100644 --- a/ecs-cli/modules/commands/compose/service/compose_service_command.go +++ b/ecs-cli/modules/commands/compose/service/compose_service_command.go @@ -68,7 +68,7 @@ func createServiceCommand(factory composeFactory.ProjectFactory) cli.Command { Name: "create", Usage: usage.ServiceCreate, Action: compose.WithProject(factory, compose.ProjectCreate, true), - Flags: flags.AppendFlags(deploymentConfigFlags(true), loadBalancerFlags(), flags.OptionalConfigFlags(), flags.OptionalLaunchTypeFlag(), flags.OptionalCreateLogsFlag(), serviceDiscoveryFlags(), flags.OptionalSchedulingStrategyFlag(), taggingFlags()), + Flags: flags.AppendFlags(deploymentConfigFlags(true), loadBalancerFlags(), capacityProviderStrategyFlags(), flags.OptionalConfigFlags(), flags.OptionalLaunchTypeFlag(), flags.OptionalCreateLogsFlag(), serviceDiscoveryFlags(), flags.OptionalSchedulingStrategyFlag(), taggingFlags()), OnUsageError: flags.UsageErrorFactory("create"), } } @@ -88,7 +88,7 @@ func upServiceCommand(factory composeFactory.ProjectFactory) cli.Command { Name: "up", Usage: usage.ServiceUp, Action: compose.WithProject(factory, compose.ProjectUp, true), - Flags: flags.AppendFlags(deploymentConfigFlags(true), loadBalancerFlags(), flags.OptionalConfigFlags(), ComposeServiceTimeoutFlag(), flags.OptionalLaunchTypeFlag(), flags.OptionalCreateLogsFlag(), ForceNewDeploymentFlag(), serviceDiscoveryFlags(), updateServiceDiscoveryFlags(), flags.OptionalSchedulingStrategyFlag(), taggingFlags()), + Flags: flags.AppendFlags(deploymentConfigFlags(true), loadBalancerFlags(), capacityProviderStrategyFlags(), flags.OptionalConfigFlags(), ComposeServiceTimeoutFlag(), flags.OptionalLaunchTypeFlag(), flags.OptionalCreateLogsFlag(), ForceNewDeploymentFlag(), serviceDiscoveryFlags(), updateServiceDiscoveryFlags(), flags.OptionalSchedulingStrategyFlag(), taggingFlags()), OnUsageError: flags.UsageErrorFactory("up"), } } @@ -226,7 +226,7 @@ func loadBalancerFlags() []cli.Flag { containerNameUsageString := fmt.Sprintf("[Deprecated] Specifies the container name (as it appears in a container definition). This parameter is required if --%s or --%s is specified.", flags.LoadBalancerNameFlag, flags.TargetGroupArnFlag) containerPortUsageString := fmt.Sprintf("[Deprecated] Specifies the port on the container to associate with the load balancer. This port must correspond to a containerPort in the service's task definition. This parameter is required if --%s or --%s is specified.", flags.LoadBalancerNameFlag, flags.TargetGroupArnFlag) loadBalancerNameUsageString := fmt.Sprintf("[Deprecated] Specifies the name of a previously configured Classic Elastic Load Balancing load balancer to associate with your service. NOTE: For Application Load Balancers or Network Load Balancers, use the --%s flag.", flags.TargetGroupArnFlag) - targetGroupsUsageString := fmt.Sprintf("[Optional] Specifies multiple target groups to register with a service. Can't be used with --%s flag or --%s at the same time. To specify multiple target groups, add multiple seperate --%s flags Example: ecs-cli compose service create --target-groups targetGroupArn=arn,containerName=nginx,containerPort=80 --target-groups targetGroupArn=arn,containerName=database,containerPort=3306", flags.LoadBalancerNameFlag, flags.TargetGroupArnFlag, flags.TargetGroupsFlag) + targetGroupsUsageString := fmt.Sprintf("[Optional] Specifies multiple target groups to register with a service. Can't be used with --%s flag or --%s at the same time. To specify multiple target groups, add multiple separate --%s flags Example: ecs-cli compose service create --target-groups targetGroupArn=arn,containerName=nginx,containerPort=80 --target-groups targetGroupArn=arn,containerName=database,containerPort=3306", flags.LoadBalancerNameFlag, flags.TargetGroupArnFlag, flags.TargetGroupsFlag) roleUsageString := fmt.Sprintf("[Optional] Specifies the name or full Amazon Resource Name (ARN) of the IAM role that allows Amazon ECS to make calls to your load balancer or target group on your behalf. This parameter requires either --%s or --%s to be specified.", flags.LoadBalancerNameFlag, flags.TargetGroupArnFlag) healthCheckGracePeriodString := "[Optional] Specifies the period of time, in seconds, that the Amazon ECS service scheduler should ignore unhealthy Elastic Load Balancing target health checks after a task has first started." @@ -263,6 +263,18 @@ func loadBalancerFlags() []cli.Flag { } } +func capacityProviderStrategyFlags() []cli.Flag { + capacityProviderStrategyUsageString := fmt.Sprintf("[Optional] Specifies multiple capacity providers to register with a service. Can't be used with --%s flag at the same time. To specify multiple capacity providers, add multiple separate --%s flags Example: ecs-cli compose service create --capacity-provider capacityProviderName=t3-large-capacity-provider,base=1,weight=1 --capacity-provider capacityProviderName=t3-nano-capacity-provider,weight=5", flags.LaunchTypeFlag, flags.CapacityProviderStrategyFlag) + + return []cli.Flag{ + cli.StringSliceFlag{ + Name: flags.CapacityProviderStrategyFlag, + Usage: capacityProviderStrategyUsageString, + Value: &cli.StringSlice{}, + }, + } +} + // ComposeServiceTimeoutFlag allows user to specify a custom timeout func ComposeServiceTimeoutFlag() []cli.Flag { return []cli.Flag{ diff --git a/ecs-cli/modules/commands/flags/flags.go b/ecs-cli/modules/commands/flags/flags.go index 51967b463..b727bce0b 100644 --- a/ecs-cli/modules/commands/flags/flags.go +++ b/ecs-cli/modules/commands/flags/flags.go @@ -135,6 +135,7 @@ const ( ComposeServiceTimeOutFlag = "timeout" ForceDeploymentFlag = "force-deployment" TargetGroupsFlag = "target-groups" + CapacityProviderStrategyFlag = "capacity-provider" // Registry Creds UpdateExistingSecretsFlag = "update-existing-secrets" diff --git a/ecs-cli/modules/utils/utils.go b/ecs-cli/modules/utils/utils.go index a0da96b38..1eb1a75a0 100644 --- a/ecs-cli/modules/utils/utils.go +++ b/ecs-cli/modules/utils/utils.go @@ -27,11 +27,14 @@ import ( const ( // ECSCLIResourcePrefix is prepended to the names of resources created through the ecs-cli - ECSCLIResourcePrefix = "amazon-ecs-cli-setup-" - containerNameParamKey = "containerName" - containerPortParamKey = "containerPort" - loadBalancerNameParamKey = "loadBalancerName" - targetGroupArnParamKey = "targetGroupArn" + ECSCLIResourcePrefix = "amazon-ecs-cli-setup-" + containerNameParamKey = "containerName" + containerPortParamKey = "containerPort" + loadBalancerNameParamKey = "loadBalancerName" + targetGroupArnParamKey = "targetGroupArn" + capacityProviderNameParamKey = "capacityProviderName" + capacityProviderBaseParamKey = "base" + capacityProviderWeightParamKey = "weight" ) // InSlice checks if the given string exists in the given slice: @@ -112,6 +115,78 @@ func GetPartition(region string) string { } } +// I think i need to create a new ParseCapacityProviders to parse the StringSlice array into an array of capacity providers struct, just like the target groups below + +// capacityProviderName=t3-large-capacity-provider,base=1,weight=1 + +// ParseCapacityProviders parses a StringSlice array into an array of capacity provider strategy item struct +// When you specify a capacity provider strategy, the number of capacity providers that can be specified is limited to six. +// A CapacityProviderItem is (https://docs.aws.amazon.com/sdk-for-go/v2/api/service/ecs/#CapacityProviderStrategyItem): +// need a string capacity provider name +// optionally, need an integer Base (but only one capacity provider in a capacity provider strategy can have a base defined) +// optionally, need an integer Weight + +// Input: ["capacityProviderName="...",base="...",weight=80","capacityProviderName="...",base="...",weight=40"] +func ParseCapacityProviders(flagValues []string) ([]*ecs.CapacityProviderStrategyItem, error) { + var list []*ecs.CapacityProviderStrategyItem + + if len(flagValues) > 6 { + return nil, fmt.Errorf("ECS only permits 6 Capacity providers, you provided %s", len(flagValues)) + } + + for _, flagValue := range flagValues { + m := make(map[string]string) + + validFlags := []string{capacityProviderNameParamKey, capacityProviderBaseParamKey, capacityProviderWeightParamKey} + currentFlags := map[string]bool{ + "capacityProviderName": false, + "base": false, + "weight": false, + } + + keyValPairs := strings.Split(flagValue, ",") + + for _, kv := range keyValPairs { + pair := strings.SplitN(kv, "=", -1) + + if len(pair) != 2 { + return nil, fmt.Errorf("There is an (key=value) initialization error, please check to see if you are using = accordingly on %s", pair[0]) + } + key, val := pair[0], pair[1] + + if ok := contains(validFlags, key); !ok { + return nil, fmt.Errorf("[--%s] is an invalid flag", key) + } + m[key] = val + if currentFlags[key] { + return nil, fmt.Errorf("%s already exists", key) + } + currentFlags[key] = true + } + for key, value := range currentFlags { + if value == false { + return nil, fmt.Errorf("--%s must be specified", key) + } + } + + base, err := strconv.ParseInt(m["base"], 10, 64) + if err != nil { + return nil, fmt.Errorf("Fail to capacity provider base %s for capacity provider %s", m["base"], m["capacityProviderName"]) + } + weight, err := strconv.ParseInt(m["weight"], 10, 64) + if err != nil { + return nil, fmt.Errorf("Fail to parse capacity provider weight %s for capacity provider %s", m["weight"], m["capacityProviderName"]) + } + + list = append(list, &ecs.CapacityProviderStrategyItem{ + CapacityProvider: aws.String(m["capacityProviderName"]), + Base: aws.Int64((base)), + Weight: aws.Int64((weight)), + }) + } + return list, nil +} + // ParseLoadBalancers parses a StringSlice array into an array of load balancers struct // Input: ["targetGroupArn="...",containerName="...",containerPort=80","targetGroupArn="...",containerName="...",containerPort=40"] func ParseLoadBalancers(flagValues []string) ([]*ecs.LoadBalancer, error) { From 5a08441afdd942f03111bc1cf03213fbbcc470ce Mon Sep 17 00:00:00 2001 From: Steven Craig Date: Thu, 8 Oct 2020 15:14:22 -0400 Subject: [PATCH 2/4] this is working, woah --- .../cli/compose/entity/service/service.go | 32 ++++++------------- .../modules/cli/compose/project/project.go | 4 --- 2 files changed, 9 insertions(+), 27 deletions(-) diff --git a/ecs-cli/modules/cli/compose/entity/service/service.go b/ecs-cli/modules/cli/compose/entity/service/service.go index 2efae9e77..9f2f0146e 100644 --- a/ecs-cli/modules/cli/compose/entity/service/service.go +++ b/ecs-cli/modules/cli/compose/entity/service/service.go @@ -156,13 +156,16 @@ func (s *Service) LoadContext() error { return err } s.loadBalancers = append(s.loadBalancers, loadBalancers...) + } + if len(capacityProviders) != 0 { capacityProviderStrategy, err := utils.ParseCapacityProviders(capacityProviders) if err != nil { return err } s.capacityProviderStrategy = append(s.capacityProviderStrategy, capacityProviderStrategy...) } + s.role = role return nil } @@ -581,31 +584,14 @@ func (s *Service) buildCreateServiceInput(serviceName, taskDefName string, desir createServiceInput.PlacementStrategy = placementStrategy } - // i think this is getting a default value somewhere so it is never blank - // just comment it out entirely and substitute a hard-coded capacity provider - /* - if launchType != "" { - createServiceInput.LaunchType = aws.String(launchType) - } - */ - - // https://docs.aws.amazon.com/sdk-for-go/api/service/ecs/#CreateServiceInput - var strategyItemList []*ecs.CapacityProviderStrategyItem - - base := int64(1) - weight := int64(1) - strategy := "de-dev-application-capacity-provider" - - strategyItem := ecs.CapacityProviderStrategyItem{ - Base: &base, - CapacityProvider: &strategy, - Weight: &weight, + // just let capacity provider take precedence if it is set + // otherwise, fall back on the launch type + if len(s.capacityProviderStrategy) > 0 { + createServiceInput.CapacityProviderStrategy = s.capacityProviderStrategy + } else if launchType != "" { + createServiceInput.LaunchType = aws.String(launchType) } - strategyItemList = append(strategyItemList, &strategyItem) - - createServiceInput.CapacityProviderStrategy = strategyItemList - if err = createServiceInput.Validate(); err != nil { return nil, err } diff --git a/ecs-cli/modules/cli/compose/project/project.go b/ecs-cli/modules/cli/compose/project/project.go index a711d336a..8baf979c9 100644 --- a/ecs-cli/modules/cli/compose/project/project.go +++ b/ecs-cli/modules/cli/compose/project/project.go @@ -222,10 +222,6 @@ func (p *ecsProject) transformTaskDefinition() error { p.entity.SetTaskDefinition(taskDefinition) - // i think this is where we can get the task definition out of here - // fmt.Println(taskDefinition) - // i can but really what i want is the create-service call - return nil } From b205fdb250b4dab8937828a13a55b7a7a58fb031 Mon Sep 17 00:00:00 2001 From: Steven Craig Date: Thu, 8 Oct 2020 15:18:34 -0400 Subject: [PATCH 3/4] clean out some comments --- ecs-cli/modules/cli/compose/entity/service/service.go | 4 ---- ecs-cli/modules/cli/compose/project/project.go | 1 - .../commands/compose/service/compose_service_command.go | 2 +- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/ecs-cli/modules/cli/compose/entity/service/service.go b/ecs-cli/modules/cli/compose/entity/service/service.go index 9f2f0146e..6beb774f2 100644 --- a/ecs-cli/modules/cli/compose/entity/service/service.go +++ b/ecs-cli/modules/cli/compose/entity/service/service.go @@ -510,8 +510,6 @@ func (s *Service) GetTags() ([]*ecs.Tag, error) { // ----------- Commands' helper functions -------- -// i think this is what needs to be modified so that instead of just a launchType it could also take a capacity provider (strategy) - func (s *Service) buildCreateServiceInput(serviceName, taskDefName string, desiredCount int) (*ecs.CreateServiceInput, error) { launchType := s.Context().CommandConfig.LaunchType cluster := s.Context().CommandConfig.Cluster @@ -623,8 +621,6 @@ func (s *Service) buildCreateServiceInput(serviceName, taskDefName string, desir } } - // fmt.Println(createServiceInput) - return createServiceInput, nil } diff --git a/ecs-cli/modules/cli/compose/project/project.go b/ecs-cli/modules/cli/compose/project/project.go index 8baf979c9..145f89fe3 100644 --- a/ecs-cli/modules/cli/compose/project/project.go +++ b/ecs-cli/modules/cli/compose/project/project.go @@ -221,7 +221,6 @@ func (p *ecsProject) transformTaskDefinition() error { } p.entity.SetTaskDefinition(taskDefinition) - return nil } diff --git a/ecs-cli/modules/commands/compose/service/compose_service_command.go b/ecs-cli/modules/commands/compose/service/compose_service_command.go index 32a745fbc..92dcf7bb9 100644 --- a/ecs-cli/modules/commands/compose/service/compose_service_command.go +++ b/ecs-cli/modules/commands/compose/service/compose_service_command.go @@ -264,7 +264,7 @@ func loadBalancerFlags() []cli.Flag { } func capacityProviderStrategyFlags() []cli.Flag { - capacityProviderStrategyUsageString := fmt.Sprintf("[Optional] Specifies multiple capacity providers to register with a service. Can't be used with --%s flag at the same time. To specify multiple capacity providers, add multiple separate --%s flags Example: ecs-cli compose service create --capacity-provider capacityProviderName=t3-large-capacity-provider,base=1,weight=1 --capacity-provider capacityProviderName=t3-nano-capacity-provider,weight=5", flags.LaunchTypeFlag, flags.CapacityProviderStrategyFlag) + capacityProviderStrategyUsageString := fmt.Sprintf("[Optional] Specifies multiple capacity providers to register with a service. Can't be used with --%s flag at the same time. To specify multiple capacity providers, add multiple separate --%s flags. Only one capacity provider can have a base > 0, set the base of all others to zero. Example: ecs-cli compose service create --capacity-provider capacityProviderName=t3-large-capacity-provider,base=1,weight=1 --capacity-provider capacityProviderName=t3-nano-capacity-provider,base=0,weight=5", flags.LaunchTypeFlag, flags.CapacityProviderStrategyFlag) return []cli.Flag{ cli.StringSliceFlag{ From 38c4fb17c4782c88427a48eb5d4c0d8c8288f933 Mon Sep 17 00:00:00 2001 From: Steven Craig Date: Thu, 8 Oct 2020 22:24:21 -0400 Subject: [PATCH 4/4] remove more comments --- ecs-cli/modules/utils/utils.go | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/ecs-cli/modules/utils/utils.go b/ecs-cli/modules/utils/utils.go index 1eb1a75a0..c3a07a4c3 100644 --- a/ecs-cli/modules/utils/utils.go +++ b/ecs-cli/modules/utils/utils.go @@ -115,17 +115,8 @@ func GetPartition(region string) string { } } -// I think i need to create a new ParseCapacityProviders to parse the StringSlice array into an array of capacity providers struct, just like the target groups below - -// capacityProviderName=t3-large-capacity-provider,base=1,weight=1 - -// ParseCapacityProviders parses a StringSlice array into an array of capacity provider strategy item struct +// ParseCapacityProviders parses a StringSlice array into an array of CapacityProviderItem // When you specify a capacity provider strategy, the number of capacity providers that can be specified is limited to six. -// A CapacityProviderItem is (https://docs.aws.amazon.com/sdk-for-go/v2/api/service/ecs/#CapacityProviderStrategyItem): -// need a string capacity provider name -// optionally, need an integer Base (but only one capacity provider in a capacity provider strategy can have a base defined) -// optionally, need an integer Weight - // Input: ["capacityProviderName="...",base="...",weight=80","capacityProviderName="...",base="...",weight=40"] func ParseCapacityProviders(flagValues []string) ([]*ecs.CapacityProviderStrategyItem, error) { var list []*ecs.CapacityProviderStrategyItem @@ -140,8 +131,6 @@ func ParseCapacityProviders(flagValues []string) ([]*ecs.CapacityProviderStrateg validFlags := []string{capacityProviderNameParamKey, capacityProviderBaseParamKey, capacityProviderWeightParamKey} currentFlags := map[string]bool{ "capacityProviderName": false, - "base": false, - "weight": false, } keyValPairs := strings.Split(flagValue, ",") @@ -171,11 +160,11 @@ func ParseCapacityProviders(flagValues []string) ([]*ecs.CapacityProviderStrateg base, err := strconv.ParseInt(m["base"], 10, 64) if err != nil { - return nil, fmt.Errorf("Fail to capacity provider base %s for capacity provider %s", m["base"], m["capacityProviderName"]) + return nil, fmt.Errorf("Failed to parse capacity provider base for capacity provider %s; set base to zero on all providers except one", m["capacityProviderName"]) } weight, err := strconv.ParseInt(m["weight"], 10, 64) if err != nil { - return nil, fmt.Errorf("Fail to parse capacity provider weight %s for capacity provider %s", m["weight"], m["capacityProviderName"]) + return nil, fmt.Errorf("Failed to parse capacity provider weight for capacity provider %s", m["capacityProviderName"]) } list = append(list, &ecs.CapacityProviderStrategyItem{