Skip to content

Commit 01bbeca

Browse files
psharkeyallisaurus
authored andcommitted
Add support for --scheduling-strategy to compose service create and up
Adding scheduling strategy tests for service creation. Throwing an error if different scheduling strategy is specified on update and modifying/adding related tests.
1 parent e70f1b1 commit 01bbeca

File tree

4 files changed

+293
-29
lines changed

4 files changed

+293
-29
lines changed

ecs-cli/modules/cli/compose/entity/service/service.go

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ func (s *Service) Up() error {
266266
return nil
267267
}
268268

269-
func (s *Service) buildUpdateServiceInput(count int64, serviceName, taskDefinition string) (*ecs.UpdateServiceInput, error) {
269+
func (s *Service) buildUpdateServiceInput(count *int64, serviceName, taskDefinition string) (*ecs.UpdateServiceInput, error) {
270270
cluster := s.Context().CommandConfig.Cluster
271271
deploymentConfig := s.DeploymentConfig()
272272
forceDeployment := s.Context().CLIContext.Bool(flags.ForceDeploymentFlag)
@@ -276,7 +276,7 @@ func (s *Service) buildUpdateServiceInput(count int64, serviceName, taskDefiniti
276276
}
277277

278278
input := &ecs.UpdateServiceInput{
279-
DesiredCount: aws.Int64(count),
279+
DesiredCount: count,
280280
Service: aws.String(serviceName),
281281
Cluster: aws.String(cluster),
282282
DeploymentConfiguration: deploymentConfig,
@@ -303,6 +303,11 @@ func (s *Service) updateService(ecsService *ecs.Service, newTaskDefinition *ecs.
303303
return fmt.Errorf("Service Discovery can not be enabled on an existing ECS Service")
304304
}
305305

306+
schedulingStrategy := strings.ToUpper(s.Context().CLIContext.String(flags.SchedulingStrategyFlag))
307+
if schedulingStrategy != "" && schedulingStrategy != aws.StringValue(ecsService.SchedulingStrategy) {
308+
return fmt.Errorf("Scheduling Strategy cannot be updated on an existing ECS Service")
309+
}
310+
306311
ecsServiceName := aws.StringValue(ecsService.ServiceName)
307312
if s.loadBalancer != nil {
308313
log.WithFields(log.Fields{
@@ -312,22 +317,27 @@ func (s *Service) updateService(ecsService *ecs.Service, newTaskDefinition *ecs.
312317

313318
oldCount := aws.Int64Value(ecsService.DesiredCount)
314319
newCount := int64(1)
320+
count := &newCount
315321
if oldCount != 0 {
316-
newCount = oldCount // get the current non-zero count
322+
count = &oldCount // get the current non-zero count
317323
}
318324

319325
// if both the task definitions are the same, call update with the new count
320326
oldTaskDefinitionId := entity.GetIdFromArn(ecsService.TaskDefinition)
321327
newTaskDefinitionId := entity.GetIdFromArn(newTaskDefinition.TaskDefinitionArn)
322328

329+
if aws.StringValue(ecsService.SchedulingStrategy) == ecs.SchedulingStrategyDaemon {
330+
count = nil
331+
}
332+
323333
if oldTaskDefinitionId == newTaskDefinitionId {
324-
return s.updateServiceCount(newCount)
334+
return s.updateServiceCount(count)
325335
}
326336

327337
// if the task definitions were different, updateService with new task definition
328338
// this creates a deployment in ECS and slowly takes down the containers with old ones and starts new ones
329339

330-
updateServiceInput, err := s.buildUpdateServiceInput(newCount, ecsServiceName, newTaskDefinitionId)
340+
updateServiceInput, err := s.buildUpdateServiceInput(count, ecsServiceName, newTaskDefinitionId)
331341
if err != nil {
332342
return err
333343
}
@@ -338,7 +348,7 @@ func (s *Service) updateService(ecsService *ecs.Service, newTaskDefinition *ecs.
338348
}
339349

340350
message := "Updated the ECS service with a new task definition. " +
341-
"Old containers will be stopped automatically, and replaced with new ones"
351+
"Old containers will be stopped automatically, and replaced with new ones"
342352
s.logUpdateService(updateServiceInput, message)
343353

344354
return waitForServiceTasks(s, ecsServiceName)
@@ -354,13 +364,13 @@ func (s *Service) Info(filterProjectTasks bool) (project.InfoSet, error) {
354364

355365
// Scale the service desired count to be the specified count
356366
func (s *Service) Scale(count int) error {
357-
return s.updateServiceCount(int64(count))
367+
return s.updateServiceCount(aws.Int64(int64(count)))
358368
}
359369

360370
// Stop stops all the containers in the service by calling ECS.UpdateService(count=0)
361371
// TODO, Store the current desiredCount in a cache, so that number of tasks(group of containers) can be started again
362372
func (s *Service) Stop() error {
363-
return s.updateServiceCount(int64(0))
373+
return s.updateServiceCount(aws.Int64(0))
364374
}
365375

366376
// Down stops any running containers(tasks) by calling Stop() and deletes an active ECS Service
@@ -382,7 +392,7 @@ func (s *Service) Down() error {
382392
}
383393

384394
// stop any running tasks
385-
if aws.Int64Value(ecsService.DesiredCount) != 0 {
395+
if aws.Int64Value(ecsService.DesiredCount) != 0 && aws.StringValue(ecsService.SchedulingStrategy) != ecs.SchedulingStrategyDaemon {
386396
if err = s.Stop(); err != nil {
387397
return err
388398
}
@@ -434,6 +444,7 @@ func (s *Service) buildCreateServiceInput(serviceName, taskDefName string) (*ecs
434444
launchType := s.Context().CommandConfig.LaunchType
435445
cluster := s.Context().CommandConfig.Cluster
436446
ecsParams := s.ecsContext.ECSParams
447+
schedulingStrategy := strings.ToUpper(s.Context().CLIContext.String(flags.SchedulingStrategyFlag))
437448

438449
networkConfig, err := composeutils.ConvertToECSNetworkConfiguration(ecsParams)
439450
if err != nil {
@@ -458,7 +469,7 @@ func (s *Service) buildCreateServiceInput(serviceName, taskDefName string) (*ecs
458469
}
459470

460471
createServiceInput := &ecs.CreateServiceInput{
461-
DesiredCount: aws.Int64(0), // Required
472+
DesiredCount: aws.Int64(0), // Required unless DAEMON schedulingStrategy
462473
ServiceName: aws.String(serviceName), // Required
463474
TaskDefinition: aws.String(taskDefName), // Required
464475
Cluster: aws.String(cluster),
@@ -467,6 +478,13 @@ func (s *Service) buildCreateServiceInput(serviceName, taskDefName string) (*ecs
467478
Role: aws.String(s.role),
468479
}
469480

481+
if schedulingStrategy != "" {
482+
createServiceInput.SchedulingStrategy = aws.String(schedulingStrategy)
483+
if schedulingStrategy == ecs.SchedulingStrategyDaemon {
484+
createServiceInput.DesiredCount = nil
485+
}
486+
}
487+
470488
if s.healthCheckGP != nil {
471489
createServiceInput.HealthCheckGracePeriodSeconds = aws.Int64(*s.healthCheckGP)
472490
}
@@ -582,32 +600,40 @@ func (s *Service) startService() error {
582600
}
583601
return err
584602
}
603+
604+
serviceName := aws.StringValue(ecsService.ServiceName)
585605
desiredCount := aws.Int64Value(ecsService.DesiredCount)
586606
forceDeployment := s.Context().CLIContext.Bool(flags.ForceDeploymentFlag)
587-
if desiredCount != 0 {
588-
serviceName := aws.StringValue(ecsService.ServiceName)
607+
schedulingStrategy := aws.StringValue(ecsService.SchedulingStrategy)
608+
if desiredCount != 0 || schedulingStrategy == ecs.SchedulingStrategyDaemon {
589609
if forceDeployment {
590610
log.WithFields(log.Fields{
591-
"serviceName": serviceName,
592-
"desiredCount": desiredCount,
593-
"force-deployment": strconv.FormatBool(forceDeployment),
611+
"serviceName": serviceName,
612+
"desiredCount": desiredCount,
613+
"schedulingStrategy": schedulingStrategy,
614+
"force-deployment": strconv.FormatBool(forceDeployment),
594615
}).Info("Forcing new deployment of running ECS Service")
595-
return s.updateServiceCount(desiredCount)
616+
count := aws.Int64(desiredCount)
617+
if schedulingStrategy == ecs.SchedulingStrategyDaemon {
618+
count = nil
619+
}
620+
return s.updateServiceCount(count)
596621
}
597622
//NoOp
598623
log.WithFields(log.Fields{
599-
"serviceName": serviceName,
600-
"desiredCount": desiredCount,
624+
"serviceName": serviceName,
625+
"desiredCount": desiredCount,
626+
"schedulingStrategy": schedulingStrategy,
601627
}).Info("ECS Service is already running")
602628

603629
return waitForServiceTasks(s, serviceName)
604630
}
605-
return s.updateServiceCount(int64(1))
631+
return s.updateServiceCount(aws.Int64(1))
606632
}
607633

608634
// updateServiceCount calls the underlying ECS.UpdateService with the specified count
609635
// NOTE: If network configuration has changed in ECS Params, this will also be updated
610-
func (s *Service) updateServiceCount(count int64) error {
636+
func (s *Service) updateServiceCount(count *int64) error {
611637
serviceName := entity.GetServiceName(s)
612638

613639
updateServiceInput, err := s.buildUpdateServiceInput(count, serviceName, "")
@@ -626,7 +652,7 @@ func (s *Service) updateServiceCount(count int64) error {
626652

627653
func (s *Service) logUpdateService(input *ecs.UpdateServiceInput, message string) {
628654
fields := log.Fields{
629-
"service": aws.StringValue(input.Service),
655+
"service": aws.StringValue(input.Service),
630656
"desiredCount": aws.Int64Value(input.DesiredCount),
631657
}
632658
if s.deploymentConfig != nil && s.deploymentConfig.MaximumPercent != nil {

0 commit comments

Comments
 (0)