in upup/pkg/fi/cloudup/awstasks/autoscalinggroup.go [329:665]
func (v *AutoscalingGroup) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *AutoscalingGroup) error {
// @step: did we find an autoscaling group?
if a == nil {
klog.V(2).Infof("Creating autoscaling group with name: %s", fi.StringValue(e.Name))
request := &autoscaling.CreateAutoScalingGroupInput{
AutoScalingGroupName: e.Name,
MinSize: e.MinSize,
MaxSize: e.MaxSize,
NewInstancesProtectedFromScaleIn: e.InstanceProtection,
Tags: v.AutoscalingGroupTags(),
VPCZoneIdentifier: fi.String(strings.Join(e.AutoscalingGroupSubnets(), ",")),
}
for _, k := range e.LoadBalancers {
if k.LoadBalancerName == nil {
lbDesc, err := t.Cloud.FindELBByNameTag(fi.StringValue(k.GetName()))
if err != nil {
return err
}
if lbDesc == nil {
return fmt.Errorf("could not find load balancer to attach")
}
request.LoadBalancerNames = append(request.LoadBalancerNames, lbDesc.LoadBalancerName)
} else {
request.LoadBalancerNames = append(request.LoadBalancerNames, k.LoadBalancerName)
}
}
for _, tg := range e.TargetGroups {
request.TargetGroupARNs = append(request.TargetGroupARNs, tg.ARN)
}
// @check are we using mixed instances policy, or launch template
if e.UseMixedInstancesPolicy() {
request.MixedInstancesPolicy = &autoscaling.MixedInstancesPolicy{
InstancesDistribution: &autoscaling.InstancesDistribution{
OnDemandPercentageAboveBaseCapacity: e.MixedOnDemandAboveBase,
OnDemandBaseCapacity: e.MixedOnDemandBase,
SpotAllocationStrategy: e.MixedSpotAllocationStrategy,
SpotInstancePools: e.MixedSpotInstancePools,
SpotMaxPrice: e.MixedSpotMaxPrice,
},
LaunchTemplate: &autoscaling.LaunchTemplate{
LaunchTemplateSpecification: &autoscaling.LaunchTemplateSpecification{
LaunchTemplateId: e.LaunchTemplate.ID,
Version: aws.String("$Latest"),
},
},
}
p := request.MixedInstancesPolicy.LaunchTemplate
for _, x := range e.MixedInstanceOverrides {
p.Overrides = append(p.Overrides, &autoscaling.LaunchTemplateOverrides{
InstanceType: fi.String(x),
},
)
}
if e.InstanceRequirements != nil {
p.Overrides = append(p.Overrides, overridesFromInstanceRequirements(e.InstanceRequirements))
}
} else if e.LaunchTemplate != nil {
request.LaunchTemplate = &autoscaling.LaunchTemplateSpecification{
LaunchTemplateId: e.LaunchTemplate.ID,
Version: aws.String("$Latest"),
}
} else {
return fmt.Errorf("could not find one of launch template or mixed instances policy")
}
// @step: attempt to create the autoscaling group for us
if _, err := t.Cloud.Autoscaling().CreateAutoScalingGroup(request); err != nil {
code := awsup.AWSErrorCode(err)
message := awsup.AWSErrorMessage(err)
if code == "ValidationError" && strings.Contains(message, "Invalid IAM Instance Profile name") {
klog.V(4).Infof("error creating AutoscalingGroup: %s", message)
return fi.NewTryAgainLaterError("waiting for the IAM Instance Profile to be propagated")
}
return fmt.Errorf("error creating AutoScalingGroup: %s", message)
}
// @step: attempt to enable the metrics for us
if _, err := t.Cloud.Autoscaling().EnableMetricsCollection(&autoscaling.EnableMetricsCollectionInput{
AutoScalingGroupName: e.Name,
Granularity: e.Granularity,
Metrics: aws.StringSlice(e.Metrics),
}); err != nil {
return fmt.Errorf("error enabling metrics collection for AutoscalingGroup: %v", err)
}
if len(*e.SuspendProcesses) > 0 {
toSuspend := []*string{}
for _, p := range *e.SuspendProcesses {
toSuspend = append(toSuspend, &p)
}
processQuery := &autoscaling.ScalingProcessQuery{}
processQuery.AutoScalingGroupName = e.Name
processQuery.ScalingProcesses = toSuspend
if _, err := t.Cloud.Autoscaling().SuspendProcesses(processQuery); err != nil {
return fmt.Errorf("error suspending processes: %v", err)
}
}
} else {
// @logic: else we have found a autoscaling group and we need to evaluate the difference
request := &autoscaling.UpdateAutoScalingGroupInput{
AutoScalingGroupName: e.Name,
}
setup := func(req *autoscaling.UpdateAutoScalingGroupInput) *autoscaling.MixedInstancesPolicy {
if req.MixedInstancesPolicy == nil {
req.MixedInstancesPolicy = &autoscaling.MixedInstancesPolicy{
InstancesDistribution: &autoscaling.InstancesDistribution{},
}
}
return req.MixedInstancesPolicy
}
// We have to update LaunchTemplate to remove mixedInstancesPolicy when it is removed from spec.
if changes.LaunchTemplate != nil || a.UseMixedInstancesPolicy() && !e.UseMixedInstancesPolicy() {
spec := &autoscaling.LaunchTemplateSpecification{
LaunchTemplateId: e.LaunchTemplate.ID,
Version: aws.String("$Latest"),
}
if e.UseMixedInstancesPolicy() {
setup(request).LaunchTemplate = &autoscaling.LaunchTemplate{LaunchTemplateSpecification: spec}
} else {
request.LaunchTemplate = spec
}
changes.LaunchTemplate = nil
}
if changes.MixedOnDemandAboveBase != nil {
setup(request).InstancesDistribution.OnDemandPercentageAboveBaseCapacity = e.MixedOnDemandAboveBase
changes.MixedOnDemandAboveBase = nil
}
if changes.MixedOnDemandBase != nil {
setup(request).InstancesDistribution.OnDemandBaseCapacity = e.MixedOnDemandBase
changes.MixedOnDemandBase = nil
}
if changes.MixedSpotAllocationStrategy != nil {
setup(request).InstancesDistribution.SpotAllocationStrategy = e.MixedSpotAllocationStrategy
changes.MixedSpotAllocationStrategy = nil
}
if changes.MixedSpotInstancePools != nil {
setup(request).InstancesDistribution.SpotInstancePools = e.MixedSpotInstancePools
changes.MixedSpotInstancePools = nil
}
if changes.MixedSpotMaxPrice != nil {
setup(request).InstancesDistribution.SpotMaxPrice = e.MixedSpotMaxPrice
changes.MixedSpotMaxPrice = nil
}
if changes.MixedInstanceOverrides != nil || changes.InstanceRequirements != nil {
if setup(request).LaunchTemplate == nil {
setup(request).LaunchTemplate = &autoscaling.LaunchTemplate{
LaunchTemplateSpecification: &autoscaling.LaunchTemplateSpecification{
LaunchTemplateId: e.LaunchTemplate.ID,
Version: aws.String("$Latest"),
},
}
}
if changes.MixedInstanceOverrides != nil {
p := request.MixedInstancesPolicy.LaunchTemplate
for _, x := range changes.MixedInstanceOverrides {
p.Overrides = append(p.Overrides, &autoscaling.LaunchTemplateOverrides{InstanceType: fi.String(x)})
}
changes.MixedInstanceOverrides = nil
}
if changes.InstanceRequirements != nil {
p := request.MixedInstancesPolicy.LaunchTemplate
p.Overrides = append(p.Overrides, overridesFromInstanceRequirements(changes.InstanceRequirements))
changes.InstanceRequirements = nil
}
}
if changes.MinSize != nil {
request.MinSize = e.MinSize
changes.MinSize = nil
}
if changes.MaxSize != nil {
request.MaxSize = e.MaxSize
changes.MaxSize = nil
}
if changes.Subnets != nil {
request.VPCZoneIdentifier = aws.String(strings.Join(e.AutoscalingGroupSubnets(), ","))
changes.Subnets = nil
}
var updateTagsRequest *autoscaling.CreateOrUpdateTagsInput
var deleteTagsRequest *autoscaling.DeleteTagsInput
if changes.Tags != nil {
updateTagsRequest = &autoscaling.CreateOrUpdateTagsInput{Tags: e.AutoscalingGroupTags()}
if a != nil && len(a.Tags) > 0 {
deleteTagsRequest = &autoscaling.DeleteTagsInput{}
deleteTagsRequest.Tags = e.getASGTagsToDelete(a.Tags)
}
changes.Tags = nil
}
var attachLBRequest *autoscaling.AttachLoadBalancersInput
var detachLBRequest *autoscaling.DetachLoadBalancersInput
if changes.LoadBalancers != nil {
if e != nil && len(e.LoadBalancers) > 0 {
attachLBRequest = &autoscaling.AttachLoadBalancersInput{
AutoScalingGroupName: e.Name,
LoadBalancerNames: e.AutoscalingLoadBalancers(),
}
}
if a != nil && len(a.LoadBalancers) > 0 {
detachLBRequest = &autoscaling.DetachLoadBalancersInput{AutoScalingGroupName: e.Name}
detachLBRequest.LoadBalancerNames = e.getLBsToDetach(a.LoadBalancers)
}
changes.LoadBalancers = nil
}
var attachTGRequest *autoscaling.AttachLoadBalancerTargetGroupsInput
var detachTGRequest *autoscaling.DetachLoadBalancerTargetGroupsInput
if changes.TargetGroups != nil {
if e != nil && len(e.TargetGroups) > 0 {
attachTGRequest = &autoscaling.AttachLoadBalancerTargetGroupsInput{
AutoScalingGroupName: e.Name,
TargetGroupARNs: e.AutoscalingTargetGroups(),
}
}
if a != nil && len(a.TargetGroups) > 0 {
detachTGRequest = &autoscaling.DetachLoadBalancerTargetGroupsInput{
AutoScalingGroupName: e.Name,
TargetGroupARNs: e.getTGsToDetach(a.TargetGroups),
}
}
changes.TargetGroups = nil
}
if changes.Metrics != nil || changes.Granularity != nil {
// TODO: Support disabling metrics?
if len(e.Metrics) != 0 {
_, err := t.Cloud.Autoscaling().EnableMetricsCollection(&autoscaling.EnableMetricsCollectionInput{
AutoScalingGroupName: e.Name,
Granularity: e.Granularity,
Metrics: aws.StringSlice(e.Metrics),
})
if err != nil {
return fmt.Errorf("error enabling metrics collection for AutoscalingGroup: %v", err)
}
changes.Metrics = nil
changes.Granularity = nil
}
}
if changes.SuspendProcesses != nil {
toSuspend := processCompare(e.SuspendProcesses, a.SuspendProcesses)
toResume := processCompare(a.SuspendProcesses, e.SuspendProcesses)
if len(toSuspend) > 0 {
suspendProcessQuery := &autoscaling.ScalingProcessQuery{}
suspendProcessQuery.AutoScalingGroupName = e.Name
suspendProcessQuery.ScalingProcesses = toSuspend
_, err := t.Cloud.Autoscaling().SuspendProcesses(suspendProcessQuery)
if err != nil {
return fmt.Errorf("error suspending processes: %v", err)
}
}
if len(toResume) > 0 {
resumeProcessQuery := &autoscaling.ScalingProcessQuery{}
resumeProcessQuery.AutoScalingGroupName = e.Name
resumeProcessQuery.ScalingProcesses = toResume
_, err := t.Cloud.Autoscaling().ResumeProcesses(resumeProcessQuery)
if err != nil {
return fmt.Errorf("error resuming processes: %v", err)
}
}
changes.SuspendProcesses = nil
}
if changes.InstanceProtection != nil {
request.NewInstancesProtectedFromScaleIn = e.InstanceProtection
changes.InstanceProtection = nil
}
empty := &AutoscalingGroup{}
if !reflect.DeepEqual(empty, changes) {
klog.Warningf("cannot apply changes to AutoScalingGroup: %v", changes)
}
klog.V(2).Infof("Updating autoscaling group %s", fi.StringValue(e.Name))
if _, err := t.Cloud.Autoscaling().UpdateAutoScalingGroup(request); err != nil {
return fmt.Errorf("error updating AutoscalingGroup: %v", err)
}
if deleteTagsRequest != nil && len(deleteTagsRequest.Tags) > 0 {
if _, err := t.Cloud.Autoscaling().DeleteTags(deleteTagsRequest); err != nil {
return fmt.Errorf("error deleting old AutoscalingGroup tags: %v", err)
}
}
if updateTagsRequest != nil {
if _, err := t.Cloud.Autoscaling().CreateOrUpdateTags(updateTagsRequest); err != nil {
return fmt.Errorf("error updating AutoscalingGroup tags: %v", err)
}
}
if detachLBRequest != nil {
if _, err := t.Cloud.Autoscaling().DetachLoadBalancers(detachLBRequest); err != nil {
return fmt.Errorf("error detatching LoadBalancers: %v", err)
}
}
if attachLBRequest != nil {
if _, err := t.Cloud.Autoscaling().AttachLoadBalancers(attachLBRequest); err != nil {
return fmt.Errorf("error attaching LoadBalancers: %v", err)
}
}
if detachTGRequest != nil {
if _, err := t.Cloud.Autoscaling().DetachLoadBalancerTargetGroups(detachTGRequest); err != nil {
return fmt.Errorf("error detaching TargetGroups: %v", err)
}
}
if attachTGRequest != nil {
if _, err := t.Cloud.Autoscaling().AttachLoadBalancerTargetGroups(attachTGRequest); err != nil {
return fmt.Errorf("error attaching TargetGroups: %v", err)
}
}
}
return nil
}