Skip to content

Commit

Permalink
Added request logging to ecs custom resource. (#1154)
Browse files Browse the repository at this point in the history
* Added request logging to ecs custom resource.
Co-authored-by: Jack Brown <[email protected]>
  • Loading branch information
russellballestrini authored Sep 1, 2020
1 parent 4c57a09 commit 7ab6b86
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 17 deletions.
2 changes: 2 additions & 0 deletions pkg/cloudformation/customresources/customresources.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,8 @@ type timeoutProvisioner struct {
}

func (p *timeoutProvisioner) Provision(ctx context.Context, r Request) (string, interface{}, error) {
// TODO: how to make this a debug log level?
fmt.Printf("%+v\n", r)
ctx, cancel := context.WithTimeout(ctx, p.timeout)
defer cancel()

Expand Down
1 change: 1 addition & 0 deletions server/cloudformation/cloudformation.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ func (c *CustomResourceProvisioner) Handle(ctx context.Context, message *sqs.Mes
"resource_type", req.ResourceType,
"logical_resource_id", req.LogicalResourceId,
"physical_resource_id", req.PhysicalResourceId,
"request_payload", m.Message,
)

resp := customresources.NewResponseFromRequest(req)
Expand Down
99 changes: 82 additions & 17 deletions server/cloudformation/ecs.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,67 @@ type LoadBalancer struct {
TargetGroupArn *string
}

// Custom type because all the integer fields come through as strings, somehow.
// It has something to do with the passing from CloudFormation -> SNS -> SQS.
// Comments below copied out of the AWS SDK docs.
type DeploymentConfiguration struct {
// If a service is using the rolling update (ECS) deployment type, the maximum
// percent parameter represents an upper limit on the number of tasks in a
// service that are allowed in the RUNNING or PENDING state during a
// deployment, as a percentage of the desired number of tasks (rounded down to
// the nearest integer), and while any container instances are in the DRAINING
// state if the service contains tasks using the EC2 launch type. This
// parameter enables you to define the deployment batch size. For example, if
// your service has a desired number of four tasks and a maximum percent value
// of 200%, the scheduler may start four new tasks before stopping the four
// older tasks (provided that the cluster resources required to do this are
// available). The default value for maximum percent is 200%.
//
// If a service is using the blue/green (CODE_DEPLOY) or EXTERNAL deployment
// types and tasks that use the EC2 launch type, the maximum percent value is
// set to the default value and is used to define the upper limit on the
// number of the tasks in the service that remain in the RUNNING state while
// the container instances are in the DRAINING state. If the tasks in the
// service use the Fargate launch type, the maximum percent value is not used,
// although it is returned when describing your service.
MaximumPercent *customresources.IntValue

// If a service is using the rolling update (ECS) deployment type, the minimum
// healthy percent represents a lower limit on the number of tasks in a
// service that must remain in the RUNNING state during a deployment, as a
// percentage of the desired number of tasks (rounded up to the nearest
// integer), and while any container instances are in the DRAINING state if
// the service contains tasks using the EC2 launch type. This parameter
// enables you to deploy without using additional cluster capacity. For
// example, if your service has a desired number of four tasks and a minimum
// healthy percent of 50%, the scheduler may stop two existing tasks to free
// up cluster capacity before starting two new tasks. Tasks for services that
// do not use a load balancer are considered healthy if they are in the
// RUNNING state; tasks for services that do use a load balancer are
// considered healthy if they are in the RUNNING state and they are reported
// as healthy by the load balancer. The default value for minimum healthy
// percent is 100%.
//
// If a service is using the blue/green (CODE_DEPLOY) or EXTERNAL deployment
// types and tasks that use the EC2 launch type, the minimum healthy percent
// value is set to the default value and is used to define the lower limit on
// the number of the tasks in the service that remain in the RUNNING state
// while the container instances are in the DRAINING state. If the tasks in
// the service use the Fargate launch type, the minimum healthy percent value
// is not used, although it is returned when describing your service.
MinimumHealthyPercent *customresources.IntValue
}

// ECSServiceProperties represents the properties for the Custom::ECSService
// resource.
type ECSServiceProperties struct {
Cluster *string
DeploymentConfiguration *ecs.DeploymentConfiguration
DeploymentConfiguration *DeploymentConfiguration
DesiredCount *customresources.IntValue `hash:"ignore"`
LoadBalancers []LoadBalancer
PlacementConstraints []ECSPlacementConstraint
PlacementStrategy []ECSPlacementStrategy
PropagateTags *string
PropagateTags *string
Role *string
ServiceName *string
TaskDefinition *string `hash:"ignore"`
Expand Down Expand Up @@ -131,17 +182,20 @@ func (p *ECSServiceResource) Create(ctx context.Context, req customresources.Req
}

resp, err := p.ecs.CreateService(&ecs.CreateServiceInput{
ClientToken: aws.String(clientToken),
Cluster: properties.Cluster,
DeploymentConfiguration: properties.DeploymentConfiguration,
DesiredCount: properties.DesiredCount.Value(),
LoadBalancers: loadBalancers,
PlacementConstraints: placementConstraints,
PlacementStrategy: placementStrategy,
PropagateTags: properties.PropagateTags,
Role: properties.Role,
ServiceName: serviceName,
TaskDefinition: properties.TaskDefinition,
ClientToken: aws.String(clientToken),
Cluster: properties.Cluster,
DeploymentConfiguration: &ecs.DeploymentConfiguration{
MaximumPercent: properties.DeploymentConfiguration.MaximumPercent.Value(),
MinimumHealthyPercent: properties.DeploymentConfiguration.MinimumHealthyPercent.Value(),
},
DesiredCount: properties.DesiredCount.Value(),
LoadBalancers: loadBalancers,
PlacementConstraints: placementConstraints,
PlacementStrategy: placementStrategy,
PropagateTags: properties.PropagateTags,
Role: properties.Role,
ServiceName: serviceName,
TaskDefinition: properties.TaskDefinition,
})
if err != nil {
return "", nil, fmt.Errorf("error creating service: %v", err)
Expand Down Expand Up @@ -190,9 +244,13 @@ func (p *ECSServiceResource) Update(ctx context.Context, req customresources.Req
}

resp, err := p.ecs.UpdateService(&ecs.UpdateServiceInput{
Service: aws.String(req.PhysicalResourceId),
Cluster: properties.Cluster,
Cluster: properties.Cluster,
DeploymentConfiguration: &ecs.DeploymentConfiguration{
MaximumPercent: properties.DeploymentConfiguration.MaximumPercent.Value(),
MinimumHealthyPercent: properties.DeploymentConfiguration.MinimumHealthyPercent.Value(),
},
DesiredCount: desiredCount,
Service: aws.String(req.PhysicalResourceId),
TaskDefinition: properties.TaskDefinition,
})
if err != nil {
Expand All @@ -210,16 +268,23 @@ func (p *ECSServiceResource) Update(ctx context.Context, req customresources.Req
}

func (p *ECSServiceResource) Delete(ctx context.Context, req customresources.Request) error {
// TODO: how to make this a debug log level?
fmt.Printf("%+v\n", req)

properties := req.ResourceProperties.(*ECSServiceProperties)
service := aws.String(req.PhysicalResourceId)
cluster := properties.Cluster

// We have to scale the service down to 0, before we're able to
// destroy it.
if _, err := p.ecs.UpdateService(&ecs.UpdateServiceInput{
Service: service,
Cluster: cluster,
Cluster: cluster,
DeploymentConfiguration: &ecs.DeploymentConfiguration{
MaximumPercent: properties.DeploymentConfiguration.MaximumPercent.Value(),
MinimumHealthyPercent: properties.DeploymentConfiguration.MinimumHealthyPercent.Value(),
},
DesiredCount: aws.Int64(0),
Service: service,
}); err != nil {
if err, ok := err.(awserr.Error); ok && strings.Contains(err.Message(), "Service was not ACTIVE") {
// If the service is not active, it was probably manually
Expand Down

0 comments on commit 7ab6b86

Please sign in to comment.