func()

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
}