Merge pull request #10151 from hakman/launch-template-versions

Use LaunchTemplate versions instead of timestamped LaunchTemplates
This commit is contained in:
Kubernetes Prow Robot 2020-11-10 23:23:48 -08:00 committed by GitHub
commit 9b3f13d93f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 404 additions and 358 deletions

View File

@ -30,7 +30,7 @@ func (m *MockAutoscaling) AttachInstances(input *autoscaling.AttachInstancesInpu
m.mutex.Lock()
defer m.mutex.Unlock()
klog.V(2).Infof("AttachInstances %v", input)
klog.V(2).Infof("Mock AttachInstances %v", input)
g := m.Groups[aws.StringValue(input.AutoScalingGroupName)]
if g == nil {
@ -48,7 +48,8 @@ func (m *MockAutoscaling) CreateAutoScalingGroup(input *autoscaling.CreateAutoSc
m.mutex.Lock()
defer m.mutex.Unlock()
klog.V(2).Infof("CreateAutoScalingGroup %v", input)
klog.V(2).Infof("Mock CreateAutoScalingGroup %v", input)
createdTime := time.Now().UTC()
g := &autoscaling.Group{
@ -75,6 +76,13 @@ func (m *MockAutoscaling) CreateAutoScalingGroup(input *autoscaling.CreateAutoSc
VPCZoneIdentifier: input.VPCZoneIdentifier,
}
if input.LaunchTemplate != nil {
g.LaunchTemplate.LaunchTemplateName = input.AutoScalingGroupName
if g.LaunchTemplate.LaunchTemplateId == nil {
return nil, fmt.Errorf("AutoScalingGroup has LaunchTemplate without ID")
}
}
for _, tag := range input.Tags {
g.Tags = append(g.Tags, &autoscaling.TagDescription{
Key: tag.Key,
@ -97,7 +105,7 @@ func (m *MockAutoscaling) EnableMetricsCollection(request *autoscaling.EnableMet
m.mutex.Lock()
defer m.mutex.Unlock()
klog.Infof("EnableMetricsCollection: %v", request)
klog.V(2).Infof("Mock EnableMetricsCollection: %v", request)
g := m.Groups[*request.AutoScalingGroupName]
if g == nil {
@ -129,7 +137,7 @@ func (m *MockAutoscaling) SuspendProcesses(input *autoscaling.ScalingProcessQuer
m.mutex.Lock()
defer m.mutex.Unlock()
klog.Infof("EnableMetricsCollection: %v", input)
klog.V(2).Infof("Mock SuspendProcesses: %v", input)
g := m.Groups[*input.AutoScalingGroupName]
if g == nil {
@ -157,6 +165,8 @@ func (m *MockAutoscaling) DescribeAutoScalingGroups(input *autoscaling.DescribeA
m.mutex.Lock()
defer m.mutex.Unlock()
klog.V(2).Infof("Mock DescribeAutoScalingGroups: %v", input)
groups := []*autoscaling.Group{}
for _, group := range m.Groups {
match := false
@ -236,7 +246,7 @@ func (m *MockAutoscaling) DeleteAutoScalingGroup(request *autoscaling.DeleteAuto
m.mutex.Lock()
defer m.mutex.Unlock()
klog.Infof("DeleteAutoScalingGroup: %v", request)
klog.V(2).Infof("Mock DeleteAutoScalingGroup: %v", request)
id := aws.StringValue(request.AutoScalingGroupName)
o := m.Groups[id]

View File

@ -18,9 +18,11 @@ package mockec2
import (
"fmt"
"strings"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"k8s.io/klog/v2"
)
type launchTemplateInfo struct {
@ -28,21 +30,59 @@ type launchTemplateInfo struct {
name *string
}
// DescribeLaunchTemplatesPages mocks the describing the launch templates
func (m *MockEC2) DescribeLaunchTemplatesPages(request *ec2.DescribeLaunchTemplatesInput, callback func(*ec2.DescribeLaunchTemplatesOutput, bool) bool) error {
page, err := m.DescribeLaunchTemplates(request)
if err != nil {
return err
}
callback(page, false)
return nil
}
// DescribeLaunchTemplates mocks the describing the launch templates
func (m *MockEC2) DescribeLaunchTemplates(request *ec2.DescribeLaunchTemplatesInput) (*ec2.DescribeLaunchTemplatesOutput, error) {
m.mutex.Lock()
defer m.mutex.Unlock()
klog.V(2).Infof("Mock DescribeLaunchTemplates: %v", request)
o := &ec2.DescribeLaunchTemplatesOutput{}
if m.LaunchTemplates == nil {
return o, nil
}
for _, ltInfo := range m.LaunchTemplates {
o.LaunchTemplates = append(o.LaunchTemplates, &ec2.LaunchTemplate{
LaunchTemplateName: ltInfo.name,
})
for id, ltInfo := range m.LaunchTemplates {
launchTemplatetName := aws.StringValue(ltInfo.name)
allFiltersMatch := true
for _, filter := range request.Filters {
filterName := aws.StringValue(filter.Name)
filterValue := aws.StringValue(filter.Values[0])
filterMatches := false
if filterName == "tag:Name" && filterValue == launchTemplatetName {
filterMatches = true
}
if strings.HasPrefix(filterName, "tag:kubernetes.io/cluster/") {
filterMatches = true
}
if !filterMatches {
allFiltersMatch = false
break
}
}
if allFiltersMatch {
o.LaunchTemplates = append(o.LaunchTemplates, &ec2.LaunchTemplate{
LaunchTemplateName: aws.String(launchTemplatetName),
LaunchTemplateId: aws.String(id),
})
}
}
return o, nil
@ -53,6 +93,8 @@ func (m *MockEC2) DescribeLaunchTemplateVersions(request *ec2.DescribeLaunchTemp
m.mutex.Lock()
defer m.mutex.Unlock()
klog.V(2).Infof("Mock DescribeLaunchTemplateVersions: %v", request)
o := &ec2.DescribeLaunchTemplateVersionsOutput{}
if m.LaunchTemplates == nil {
@ -78,6 +120,8 @@ func (m *MockEC2) CreateLaunchTemplate(request *ec2.CreateLaunchTemplateInput) (
m.mutex.Lock()
defer m.mutex.Unlock()
klog.V(2).Infof("Mock CreateLaunchTemplate: %v", request)
m.launchTemplateNumber++
n := m.launchTemplateNumber
id := fmt.Sprintf("lt-%d", n)
@ -86,7 +130,7 @@ func (m *MockEC2) CreateLaunchTemplate(request *ec2.CreateLaunchTemplateInput) (
m.LaunchTemplates = make(map[string]*launchTemplateInfo)
}
if m.LaunchTemplates[id] != nil {
return nil, fmt.Errorf("duplicate LaunchTemplateName %s", id)
return nil, fmt.Errorf("duplicate LaunchTemplateId %s", id)
}
resp := &ec2.ResponseLaunchTemplateData{
DisableApiTermination: request.LaunchTemplateData.DisableApiTermination,
@ -190,13 +234,15 @@ func (m *MockEC2) DeleteLaunchTemplate(request *ec2.DeleteLaunchTemplateInput) (
m.mutex.Lock()
defer m.mutex.Unlock()
klog.V(2).Infof("Mock DeleteLaunchTemplate: %v", request)
o := &ec2.DeleteLaunchTemplateOutput{}
if m.LaunchTemplates == nil {
return o, nil
}
for id, lt := range m.LaunchTemplates {
if aws.StringValue(lt.name) == aws.StringValue(request.LaunchTemplateName) {
for id := range m.LaunchTemplates {
if id == aws.StringValue(request.LaunchTemplateId) {
delete(m.LaunchTemplates, id)
}
}

View File

@ -145,7 +145,7 @@ func ListResourcesAWS(cloud awsup.AWSCloud, clusterName string) (map[string]*res
if err != nil {
return nil, err
}
lts, err := FindAutoScalingLaunchTemplateConfigurations(cloud, securityGroups)
lts, err := FindAutoScalingLaunchTemplates(cloud, clusterName)
if err != nil {
return nil, err
}
@ -1179,47 +1179,35 @@ func ListAutoScalingGroups(cloud fi.Cloud, clusterName string) ([]*resources.Res
return resourceTrackers, nil
}
// FindAutoScalingLaunchTemplateConfigurations finds any launch configurations which reference the security groups
func FindAutoScalingLaunchTemplateConfigurations(cloud fi.Cloud, securityGroups sets.String) ([]*resources.Resource, error) {
// FindAutoScalingLaunchTemplates finds any launch templates owned by the cluster (by tag).
func FindAutoScalingLaunchTemplates(cloud fi.Cloud, clusterName string) ([]*resources.Resource, error) {
c := cloud.(awsup.AWSCloud)
klog.V(2).Infof("Finding all AutoScaling LaunchTemplates owned by the cluster")
input := &ec2.DescribeLaunchTemplatesInput{
Filters: []*ec2.Filter{
{
Name: aws.String("tag:kubernetes.io/cluster/" + clusterName),
Values: []*string{aws.String("owned")},
},
},
}
var list []*resources.Resource
c, ok := cloud.(awsup.AWSCloud)
if !ok {
return nil, errors.New("expected a aws cloud provider")
}
klog.V(2).Infof("Finding all Autoscaling LaunchTemplates associated to security groups")
resp, err := c.EC2().DescribeLaunchTemplates(&ec2.DescribeLaunchTemplatesInput{MaxResults: fi.Int64(100)})
err := c.EC2().DescribeLaunchTemplatesPages(input, func(p *ec2.DescribeLaunchTemplatesOutput, lastPage bool) (shouldContinue bool) {
for _, lt := range p.LaunchTemplates {
list = append(list, &resources.Resource{
Name: aws.StringValue(lt.LaunchTemplateName),
ID: aws.StringValue(lt.LaunchTemplateId),
Type: TypeAutoscalingLaunchConfig,
Deleter: DeleteAutoScalingGroupLaunchTemplate,
})
}
return true
})
if err != nil {
return list, nil
}
for _, x := range resp.LaunchTemplates {
// @step: grab the actual launch template
req, err := c.EC2().DescribeLaunchTemplateVersions(&ec2.DescribeLaunchTemplateVersionsInput{
LaunchTemplateName: x.LaunchTemplateName,
})
if err != nil {
return list, err
}
for _, j := range req.LaunchTemplateVersions {
// @check if the security group references the security group above
var s []*string
for _, ni := range j.LaunchTemplateData.NetworkInterfaces {
s = append(s, ni.Groups...)
}
s = append(s, j.LaunchTemplateData.SecurityGroupIds...)
for _, y := range s {
if securityGroups.Has(fi.StringValue(y)) {
list = append(list, &resources.Resource{
Name: aws.StringValue(x.LaunchTemplateName),
ID: aws.StringValue(x.LaunchTemplateName),
Type: TypeAutoscalingLaunchConfig,
Deleter: DeleteAutoScalingGroupLaunchTemplate,
})
}
}
}
return nil, fmt.Errorf("error listing AutoScaling LaunchTemplates: %v", err)
}
return list, nil
@ -1377,7 +1365,7 @@ func DeleteAutoScalingGroupLaunchTemplate(cloud fi.Cloud, r *resources.Resource)
klog.V(2).Infof("Deleting EC2 LaunchTemplate %q", r.ID)
if _, err := c.EC2().DeleteLaunchTemplate(&ec2.DeleteLaunchTemplateInput{
LaunchTemplateName: fi.String(r.ID),
LaunchTemplateId: fi.String(r.ID),
}); err != nil {
return fmt.Errorf("error deleting ec2 LaunchTemplate %q: %v", r.ID, err)
}

View File

@ -429,7 +429,7 @@ resource "aws_launch_template" "bastion-bastionuserdata-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "bastion.bastionuserdata.example.com-"
name = "bastion.bastionuserdata.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -493,7 +493,7 @@ resource "aws_launch_template" "master-us-test-1a-masters-bastionuserdata-exampl
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1a.masters.bastionuserdata.example.com-"
name = "master-us-test-1a.masters.bastionuserdata.example.com"
network_interfaces {
associate_public_ip_address = false
delete_on_termination = true
@ -553,7 +553,7 @@ resource "aws_launch_template" "nodes-bastionuserdata-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "nodes.bastionuserdata.example.com-"
name = "nodes.bastionuserdata.example.com"
network_interfaces {
associate_public_ip_address = false
delete_on_termination = true

View File

@ -297,7 +297,7 @@ resource "aws_launch_template" "master-us-test-1a-masters-complex-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1a.masters.complex.example.com-"
name = "master-us-test-1a.masters.complex.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -374,7 +374,7 @@ resource "aws_launch_template" "nodes-complex-example-com" {
monitoring {
enabled = true
}
name_prefix = "nodes.complex.example.com-"
name = "nodes.complex.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true

View File

@ -387,7 +387,7 @@ resource "aws_launch_template" "master-us-test-1a-masters-existing-iam-example-c
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1a.masters.existing-iam.example.com-"
name = "master-us-test-1a.masters.existing-iam.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -451,7 +451,7 @@ resource "aws_launch_template" "master-us-test-1b-masters-existing-iam-example-c
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1b.masters.existing-iam.example.com-"
name = "master-us-test-1b.masters.existing-iam.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -515,7 +515,7 @@ resource "aws_launch_template" "master-us-test-1c-masters-existing-iam-example-c
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1c.masters.existing-iam.example.com-"
name = "master-us-test-1c.masters.existing-iam.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -575,7 +575,7 @@ resource "aws_launch_template" "nodes-existing-iam-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "nodes.existing-iam.example.com-"
name = "nodes.existing-iam.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true

View File

@ -468,7 +468,7 @@ resource "aws_launch_template" "master-us-test-1a-masters-existingsg-example-com
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1a.masters.existingsg.example.com-"
name = "master-us-test-1a.masters.existingsg.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -532,7 +532,7 @@ resource "aws_launch_template" "master-us-test-1b-masters-existingsg-example-com
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1b.masters.existingsg.example.com-"
name = "master-us-test-1b.masters.existingsg.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -596,7 +596,7 @@ resource "aws_launch_template" "master-us-test-1c-masters-existingsg-example-com
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1c.masters.existingsg.example.com-"
name = "master-us-test-1c.masters.existingsg.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -656,7 +656,7 @@ resource "aws_launch_template" "nodes-existingsg-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "nodes.existingsg.example.com-"
name = "nodes.existingsg.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true

View File

@ -280,7 +280,7 @@ resource "aws_launch_template" "master-us-test-1a-masters-externallb-example-com
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1a.masters.externallb.example.com-"
name = "master-us-test-1a.masters.externallb.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -340,7 +340,7 @@ resource "aws_launch_template" "nodes-externallb-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "nodes.externallb.example.com-"
name = "nodes.externallb.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true

View File

@ -345,7 +345,7 @@ resource "aws_launch_template" "master-us-test-1a-masters-externalpolicies-examp
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1a.masters.externalpolicies.example.com-"
name = "master-us-test-1a.masters.externalpolicies.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -414,7 +414,7 @@ resource "aws_launch_template" "nodes-externalpolicies-example-com" {
monitoring {
enabled = true
}
name_prefix = "nodes.externalpolicies.example.com-"
name = "nodes.externalpolicies.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true

View File

@ -439,7 +439,7 @@ resource "aws_launch_template" "master-us-test-1a-masters-ha-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1a.masters.ha.example.com-"
name = "master-us-test-1a.masters.ha.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -503,7 +503,7 @@ resource "aws_launch_template" "master-us-test-1b-masters-ha-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1b.masters.ha.example.com-"
name = "master-us-test-1b.masters.ha.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -567,7 +567,7 @@ resource "aws_launch_template" "master-us-test-1c-masters-ha-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1c.masters.ha.example.com-"
name = "master-us-test-1c.masters.ha.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -627,7 +627,7 @@ resource "aws_launch_template" "nodes-ha-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "nodes.ha.example.com-"
name = "nodes.ha.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true

View File

@ -294,7 +294,7 @@
},
"aws_launch_template": {
"master-us-test-1a-masters-minimal-json-example-com": {
"name_prefix": "master-us-test-1a.masters.minimal-json.example.com-",
"name": "master-us-test-1a.masters.minimal-json.example.com",
"lifecycle": {
"create_before_destroy": true
},
@ -369,7 +369,7 @@
"user_data": "${file(\"${path.module}/data/aws_launch_template_master-us-test-1a.masters.minimal-json.example.com_user_data\")}"
},
"nodes-minimal-json-example-com": {
"name_prefix": "nodes.minimal-json.example.com-",
"name": "nodes.minimal-json.example.com",
"lifecycle": {
"create_before_destroy": true
},

View File

@ -277,7 +277,7 @@ resource "aws_launch_template" "master-us-test-1a-masters-minimal-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1a.masters.minimal.example.com-"
name = "master-us-test-1a.masters.minimal.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -337,7 +337,7 @@ resource "aws_launch_template" "nodes-minimal-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "nodes.minimal.example.com-"
name = "nodes.minimal.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true

View File

@ -457,7 +457,7 @@ resource "aws_launch_template" "master-us-test-1a-masters-mixedinstances-example
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1a.masters.mixedinstances.example.com-"
name = "master-us-test-1a.masters.mixedinstances.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -521,7 +521,7 @@ resource "aws_launch_template" "master-us-test-1b-masters-mixedinstances-example
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1b.masters.mixedinstances.example.com-"
name = "master-us-test-1b.masters.mixedinstances.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -585,7 +585,7 @@ resource "aws_launch_template" "master-us-test-1c-masters-mixedinstances-example
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1c.masters.mixedinstances.example.com-"
name = "master-us-test-1c.masters.mixedinstances.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -645,7 +645,7 @@ resource "aws_launch_template" "nodes-mixedinstances-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "nodes.mixedinstances.example.com-"
name = "nodes.mixedinstances.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true

View File

@ -457,7 +457,7 @@ resource "aws_launch_template" "master-us-test-1a-masters-mixedinstances-example
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1a.masters.mixedinstances.example.com-"
name = "master-us-test-1a.masters.mixedinstances.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -521,7 +521,7 @@ resource "aws_launch_template" "master-us-test-1b-masters-mixedinstances-example
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1b.masters.mixedinstances.example.com-"
name = "master-us-test-1b.masters.mixedinstances.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -585,7 +585,7 @@ resource "aws_launch_template" "master-us-test-1c-masters-mixedinstances-example
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1c.masters.mixedinstances.example.com-"
name = "master-us-test-1c.masters.mixedinstances.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -645,7 +645,7 @@ resource "aws_launch_template" "nodes-mixedinstances-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "nodes.mixedinstances.example.com-"
name = "nodes.mixedinstances.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true

View File

@ -401,7 +401,7 @@ resource "aws_launch_template" "bastion-private-shared-subnet-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "bastion.private-shared-subnet.example.com-"
name = "bastion.private-shared-subnet.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -464,7 +464,7 @@ resource "aws_launch_template" "master-us-test-1a-masters-private-shared-subnet-
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1a.masters.private-shared-subnet.example.com-"
name = "master-us-test-1a.masters.private-shared-subnet.example.com"
network_interfaces {
associate_public_ip_address = false
delete_on_termination = true
@ -524,7 +524,7 @@ resource "aws_launch_template" "nodes-private-shared-subnet-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "nodes.private-shared-subnet.example.com-"
name = "nodes.private-shared-subnet.example.com"
network_interfaces {
associate_public_ip_address = false
delete_on_termination = true

View File

@ -429,7 +429,7 @@ resource "aws_launch_template" "bastion-privatecalico-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "bastion.privatecalico.example.com-"
name = "bastion.privatecalico.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -492,7 +492,7 @@ resource "aws_launch_template" "master-us-test-1a-masters-privatecalico-example-
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1a.masters.privatecalico.example.com-"
name = "master-us-test-1a.masters.privatecalico.example.com"
network_interfaces {
associate_public_ip_address = false
delete_on_termination = true
@ -552,7 +552,7 @@ resource "aws_launch_template" "nodes-privatecalico-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "nodes.privatecalico.example.com-"
name = "nodes.privatecalico.example.com"
network_interfaces {
associate_public_ip_address = false
delete_on_termination = true

View File

@ -429,7 +429,7 @@ resource "aws_launch_template" "bastion-privatecanal-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "bastion.privatecanal.example.com-"
name = "bastion.privatecanal.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -492,7 +492,7 @@ resource "aws_launch_template" "master-us-test-1a-masters-privatecanal-example-c
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1a.masters.privatecanal.example.com-"
name = "master-us-test-1a.masters.privatecanal.example.com"
network_interfaces {
associate_public_ip_address = false
delete_on_termination = true
@ -552,7 +552,7 @@ resource "aws_launch_template" "nodes-privatecanal-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "nodes.privatecanal.example.com-"
name = "nodes.privatecanal.example.com"
network_interfaces {
associate_public_ip_address = false
delete_on_termination = true

View File

@ -429,7 +429,7 @@ resource "aws_launch_template" "bastion-privatecilium-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "bastion.privatecilium.example.com-"
name = "bastion.privatecilium.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -492,7 +492,7 @@ resource "aws_launch_template" "master-us-test-1a-masters-privatecilium-example-
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1a.masters.privatecilium.example.com-"
name = "master-us-test-1a.masters.privatecilium.example.com"
network_interfaces {
associate_public_ip_address = false
delete_on_termination = true
@ -552,7 +552,7 @@ resource "aws_launch_template" "nodes-privatecilium-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "nodes.privatecilium.example.com-"
name = "nodes.privatecilium.example.com"
network_interfaces {
associate_public_ip_address = false
delete_on_termination = true

View File

@ -429,7 +429,7 @@ resource "aws_launch_template" "bastion-privatecilium-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "bastion.privatecilium.example.com-"
name = "bastion.privatecilium.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -492,7 +492,7 @@ resource "aws_launch_template" "master-us-test-1a-masters-privatecilium-example-
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1a.masters.privatecilium.example.com-"
name = "master-us-test-1a.masters.privatecilium.example.com"
network_interfaces {
associate_public_ip_address = false
delete_on_termination = true
@ -552,7 +552,7 @@ resource "aws_launch_template" "nodes-privatecilium-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "nodes.privatecilium.example.com-"
name = "nodes.privatecilium.example.com"
network_interfaces {
associate_public_ip_address = false
delete_on_termination = true

View File

@ -443,7 +443,7 @@ resource "aws_launch_template" "bastion-privateciliumadvanced-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "bastion.privateciliumadvanced.example.com-"
name = "bastion.privateciliumadvanced.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -506,7 +506,7 @@ resource "aws_launch_template" "master-us-test-1a-masters-privateciliumadvanced-
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1a.masters.privateciliumadvanced.example.com-"
name = "master-us-test-1a.masters.privateciliumadvanced.example.com"
network_interfaces {
associate_public_ip_address = false
delete_on_termination = true
@ -566,7 +566,7 @@ resource "aws_launch_template" "nodes-privateciliumadvanced-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "nodes.privateciliumadvanced.example.com-"
name = "nodes.privateciliumadvanced.example.com"
network_interfaces {
associate_public_ip_address = false
delete_on_termination = true

View File

@ -473,7 +473,7 @@ resource "aws_launch_template" "bastion-privatedns1-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "bastion.privatedns1.example.com-"
name = "bastion.privatedns1.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -542,7 +542,7 @@ resource "aws_launch_template" "master-us-test-1a-masters-privatedns1-example-co
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1a.masters.privatedns1.example.com-"
name = "master-us-test-1a.masters.privatedns1.example.com"
network_interfaces {
associate_public_ip_address = false
delete_on_termination = true
@ -608,7 +608,7 @@ resource "aws_launch_template" "nodes-privatedns1-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "nodes.privatedns1.example.com-"
name = "nodes.privatedns1.example.com"
network_interfaces {
associate_public_ip_address = false
delete_on_termination = true

View File

@ -415,7 +415,7 @@ resource "aws_launch_template" "bastion-privatedns2-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "bastion.privatedns2.example.com-"
name = "bastion.privatedns2.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -478,7 +478,7 @@ resource "aws_launch_template" "master-us-test-1a-masters-privatedns2-example-co
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1a.masters.privatedns2.example.com-"
name = "master-us-test-1a.masters.privatedns2.example.com"
network_interfaces {
associate_public_ip_address = false
delete_on_termination = true
@ -538,7 +538,7 @@ resource "aws_launch_template" "nodes-privatedns2-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "nodes.privatedns2.example.com-"
name = "nodes.privatedns2.example.com"
network_interfaces {
associate_public_ip_address = false
delete_on_termination = true

View File

@ -429,7 +429,7 @@ resource "aws_launch_template" "bastion-privateflannel-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "bastion.privateflannel.example.com-"
name = "bastion.privateflannel.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -492,7 +492,7 @@ resource "aws_launch_template" "master-us-test-1a-masters-privateflannel-example
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1a.masters.privateflannel.example.com-"
name = "master-us-test-1a.masters.privateflannel.example.com"
network_interfaces {
associate_public_ip_address = false
delete_on_termination = true
@ -552,7 +552,7 @@ resource "aws_launch_template" "nodes-privateflannel-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "nodes.privateflannel.example.com-"
name = "nodes.privateflannel.example.com"
network_interfaces {
associate_public_ip_address = false
delete_on_termination = true

View File

@ -435,7 +435,7 @@ resource "aws_launch_template" "bastion-privatekopeio-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "bastion.privatekopeio.example.com-"
name = "bastion.privatekopeio.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -498,7 +498,7 @@ resource "aws_launch_template" "master-us-test-1a-masters-privatekopeio-example-
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1a.masters.privatekopeio.example.com-"
name = "master-us-test-1a.masters.privatekopeio.example.com"
network_interfaces {
associate_public_ip_address = false
delete_on_termination = true
@ -558,7 +558,7 @@ resource "aws_launch_template" "nodes-privatekopeio-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "nodes.privatekopeio.example.com-"
name = "nodes.privatekopeio.example.com"
network_interfaces {
associate_public_ip_address = false
delete_on_termination = true

View File

@ -429,7 +429,7 @@ resource "aws_launch_template" "bastion-privateweave-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "bastion.privateweave.example.com-"
name = "bastion.privateweave.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -492,7 +492,7 @@ resource "aws_launch_template" "master-us-test-1a-masters-privateweave-example-c
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1a.masters.privateweave.example.com-"
name = "master-us-test-1a.masters.privateweave.example.com"
network_interfaces {
associate_public_ip_address = false
delete_on_termination = true
@ -552,7 +552,7 @@ resource "aws_launch_template" "nodes-privateweave-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "nodes.privateweave.example.com-"
name = "nodes.privateweave.example.com"
network_interfaces {
associate_public_ip_address = false
delete_on_termination = true

View File

@ -304,7 +304,7 @@ resource "aws_launch_template" "master-us-test-1a-masters-minimal-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1a.masters.minimal.example.com-"
name = "master-us-test-1a.masters.minimal.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -364,7 +364,7 @@ resource "aws_launch_template" "nodes-minimal-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "nodes.minimal.example.com-"
name = "nodes.minimal.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true

View File

@ -263,7 +263,7 @@ resource "aws_launch_template" "master-us-test-1a-masters-sharedsubnet-example-c
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1a.masters.sharedsubnet.example.com-"
name = "master-us-test-1a.masters.sharedsubnet.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -323,7 +323,7 @@ resource "aws_launch_template" "nodes-sharedsubnet-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "nodes.sharedsubnet.example.com-"
name = "nodes.sharedsubnet.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true

View File

@ -263,7 +263,7 @@ resource "aws_launch_template" "master-us-test-1a-masters-sharedvpc-example-com"
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1a.masters.sharedvpc.example.com-"
name = "master-us-test-1a.masters.sharedvpc.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -323,7 +323,7 @@ resource "aws_launch_template" "nodes-sharedvpc-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "nodes.sharedvpc.example.com-"
name = "nodes.sharedvpc.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true

View File

@ -406,7 +406,7 @@ resource "aws_launch_template" "bastion-unmanaged-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "bastion.unmanaged.example.com-"
name = "bastion.unmanaged.example.com"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -469,7 +469,7 @@ resource "aws_launch_template" "master-us-test-1a-masters-unmanaged-example-com"
lifecycle {
create_before_destroy = true
}
name_prefix = "master-us-test-1a.masters.unmanaged.example.com-"
name = "master-us-test-1a.masters.unmanaged.example.com"
network_interfaces {
associate_public_ip_address = false
delete_on_termination = true
@ -529,7 +529,7 @@ resource "aws_launch_template" "nodes-unmanaged-example-com" {
lifecycle {
create_before_destroy = true
}
name_prefix = "nodes.unmanaged.example.com-"
name = "nodes.unmanaged.example.com"
network_interfaces {
associate_public_ip_address = false
delete_on_termination = true

View File

@ -20,19 +20,16 @@ import (
"fmt"
"reflect"
"sort"
"strconv"
"strings"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/autoscaling"
"k8s.io/klog/v2"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/cloudup/awsup"
"k8s.io/kops/upup/pkg/fi/cloudup/cloudformation"
"k8s.io/kops/upup/pkg/fi/cloudup/terraform"
"k8s.io/kops/util/pkg/maps"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/autoscaling"
"github.com/aws/aws-sdk-go/service/ec2"
"k8s.io/klog/v2"
)
// CloudTagInstanceGroupRolePrefix is a cloud tag that defines the instance role
@ -202,7 +199,10 @@ func (e *AutoscalingGroup) Find(c *fi.Context) (*AutoscalingGroup, error) {
actual.LaunchConfiguration = &LaunchConfiguration{ID: g.LaunchConfigurationName}
}
if g.LaunchTemplate != nil {
actual.LaunchTemplate = &LaunchTemplate{ID: g.LaunchTemplate.LaunchTemplateName}
actual.LaunchTemplate = &LaunchTemplate{
Name: g.LaunchTemplate.LaunchTemplateName,
ID: g.LaunchTemplate.LaunchTemplateId,
}
}
if g.MixedInstancesPolicy != nil {
@ -219,7 +219,10 @@ func (e *AutoscalingGroup) Find(c *fi.Context) (*AutoscalingGroup, error) {
if g.MixedInstancesPolicy.LaunchTemplate != nil {
if g.MixedInstancesPolicy.LaunchTemplate.LaunchTemplateSpecification != nil {
actual.LaunchTemplate = &LaunchTemplate{ID: g.MixedInstancesPolicy.LaunchTemplate.LaunchTemplateSpecification.LaunchTemplateName}
actual.LaunchTemplate = &LaunchTemplate{
Name: g.MixedInstancesPolicy.LaunchTemplate.LaunchTemplateSpecification.LaunchTemplateName,
ID: g.MixedInstancesPolicy.LaunchTemplate.LaunchTemplateSpecification.LaunchTemplateId,
}
}
for _, n := range g.MixedInstancesPolicy.LaunchTemplate.Overrides {
@ -363,8 +366,8 @@ func (v *AutoscalingGroup) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *Autos
},
LaunchTemplate: &autoscaling.LaunchTemplate{
LaunchTemplateSpecification: &autoscaling.LaunchTemplateSpecification{
LaunchTemplateName: e.LaunchTemplate.ID,
Version: aws.String("1"),
LaunchTemplateId: e.LaunchTemplate.ID,
Version: aws.String("$Latest"),
},
},
}
@ -376,11 +379,11 @@ func (v *AutoscalingGroup) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *Autos
}
} else if e.LaunchTemplate != nil {
request.LaunchTemplate = &autoscaling.LaunchTemplateSpecification{
LaunchTemplateName: e.LaunchTemplate.ID,
Version: aws.String("1"),
LaunchTemplateId: e.LaunchTemplate.ID,
Version: aws.String("$Latest"),
}
} else {
return fmt.Errorf("could not find one of launch configuration, mixed instances policy, or launch template")
return fmt.Errorf("could not find one of launch template, mixed instances policy, or launch configuration")
}
// @step: attempt to create the autoscaling group for us
@ -441,23 +444,10 @@ func (v *AutoscalingGroup) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *Autos
return req.MixedInstancesPolicy
}
launchTemplateVersion := "1"
if e.LaunchTemplate != nil {
dltRequest := &ec2.DescribeLaunchTemplatesInput{
LaunchTemplateNames: []*string{e.LaunchTemplate.ID},
}
dltResponse, err := t.Cloud.EC2().DescribeLaunchTemplates(dltRequest)
if err != nil {
klog.Warningf("could not find existing LaunchTemplate: %v", err)
} else {
launchTemplateVersion = strconv.FormatInt(*dltResponse.LaunchTemplates[0].LatestVersionNumber, 10)
}
}
if changes.LaunchTemplate != nil {
spec := &autoscaling.LaunchTemplateSpecification{
LaunchTemplateName: changes.LaunchTemplate.ID,
Version: &launchTemplateVersion,
LaunchTemplateId: changes.LaunchTemplate.ID,
Version: aws.String("$Latest"),
}
if e.UseMixedInstancesPolicy() {
setup(request).LaunchTemplate = &autoscaling.LaunchTemplate{LaunchTemplateSpecification: spec}
@ -491,8 +481,8 @@ func (v *AutoscalingGroup) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *Autos
if setup(request).LaunchTemplate == nil {
setup(request).LaunchTemplate = &autoscaling.LaunchTemplate{
LaunchTemplateSpecification: &autoscaling.LaunchTemplateSpecification{
LaunchTemplateName: e.LaunchTemplate.ID,
Version: &launchTemplateVersion,
LaunchTemplateId: changes.LaunchTemplate.ID,
Version: aws.String("$Latest"),
},
}
}

View File

@ -20,16 +20,16 @@ import (
"fmt"
"sort"
"github.com/aws/aws-sdk-go/aws"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/cloudup/awsup"
"github.com/aws/aws-sdk-go/aws"
"k8s.io/klog/v2"
)
// LaunchTemplate defines the specification for a launch template.
// +kops:fitask
type LaunchTemplate struct {
// ID is the launch configuration name
ID *string
// Name is the name of the configuration
Name *string
// Lifecycle is the resource lifecycle
@ -41,10 +41,11 @@ type LaunchTemplate struct {
BlockDeviceMappings []*BlockDeviceMapping
// IAMInstanceProfile is the IAM profile to assign to the nodes
IAMInstanceProfile *IAMInstanceProfile
// ID is the launch configuration name
ID *string
// ImageID is the AMI to use for the instances
ImageID *string
// InstanceInterruptionBehavior defines if a spot instance should be terminated, hibernated,
// or stopped after interruption
InstanceInterruptionBehavior *string
// InstanceMonitoring indicates if monitoring is enabled
InstanceMonitoring *bool
// InstanceType is the type of instance we are using
@ -73,9 +74,6 @@ type LaunchTemplate struct {
Tenancy *string
// UserData is the user data configuration
UserData *fi.ResourceHolder
// InstanceInterruptionBehavior defines if a spot instance should be terminated, hibernated,
// or stopped after interruption
InstanceInterruptionBehavior *string
}
var (
@ -89,11 +87,6 @@ func (t *LaunchTemplate) CompareWithID() *string {
return t.ID
}
// LaunchTemplateName returns the lanuch template name
func (t *LaunchTemplate) LaunchTemplateName() string {
return fmt.Sprintf("%s-%s", fi.StringValue(t.Name), fi.BuildTimestampString())
}
// buildRootDevice is responsible for retrieving a boot device mapping from the image name
func (t *LaunchTemplate) buildRootDevice(cloud awsup.AWSCloud) (map[string]*BlockDeviceMapping, error) {
image := fi.StringValue(t.ImageID)
@ -154,22 +147,16 @@ func (t *LaunchTemplate) CheckChanges(a, e, changes *LaunchTemplate) error {
func (t *LaunchTemplate) FindDeletions(c *fi.Context) ([]fi.Deletion, error) {
var removals []fi.Deletion
configurations, err := t.findLaunchTemplates(c)
list, err := t.findAllLaunchTemplates(c)
if err != nil {
return nil, err
}
if len(configurations) <= RetainLaunchConfigurationCount() {
return nil, nil
for _, lt := range list {
if aws.StringValue(lt.LaunchTemplateName) != aws.StringValue(t.Name) {
removals = append(removals, &deleteLaunchTemplate{lc: lt})
}
}
configurations = configurations[:len(configurations)-RetainLaunchConfigurationCount()]
for _, configuration := range configurations {
removals = append(removals, &deleteLaunchTemplate{lc: configuration})
}
klog.V(2).Infof("will delete launch template: %v", removals)
return removals, nil
}

View File

@ -20,44 +20,36 @@ import (
"encoding/base64"
"fmt"
"sort"
"strings"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/cloudup/awsup"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"k8s.io/klog/v2"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/cloudup/awsup"
)
// RenderAWS is responsible for performing creating / updating the launch template
func (t *LaunchTemplate) RenderAWS(c *awsup.AWSAPITarget, a, ep, changes *LaunchTemplate) error {
name := t.LaunchTemplateName()
func (t *LaunchTemplate) RenderAWS(c *awsup.AWSAPITarget, a, e, changes *LaunchTemplate) error {
// @step: resolve the image id to an AMI for us
image, err := c.Cloud.ResolveImage(fi.StringValue(t.ImageID))
if err != nil {
return err
}
// @step: lets build the launch template input
input := &ec2.CreateLaunchTemplateInput{
LaunchTemplateData: &ec2.RequestLaunchTemplateData{
DisableApiTermination: fi.Bool(false),
EbsOptimized: t.RootVolumeOptimization,
ImageId: image.ImageId,
InstanceType: t.InstanceType,
NetworkInterfaces: []*ec2.LaunchTemplateInstanceNetworkInterfaceSpecificationRequest{
{
AssociatePublicIpAddress: t.AssociatePublicIP,
DeleteOnTermination: aws.Bool(true),
DeviceIndex: fi.Int64(0),
},
// @step: lets build the launch template data
data := &ec2.RequestLaunchTemplateData{
DisableApiTermination: fi.Bool(false),
EbsOptimized: t.RootVolumeOptimization,
ImageId: image.ImageId,
InstanceType: t.InstanceType,
NetworkInterfaces: []*ec2.LaunchTemplateInstanceNetworkInterfaceSpecificationRequest{
{
AssociatePublicIpAddress: t.AssociatePublicIP,
DeleteOnTermination: aws.Bool(true),
DeviceIndex: fi.Int64(0),
},
},
LaunchTemplateName: aws.String(name),
}
lc := input.LaunchTemplateData
// @step: add the actual block device mappings
rootDevices, err := t.buildRootDevice(c.Cloud)
@ -74,54 +66,50 @@ func (t *LaunchTemplate) RenderAWS(c *awsup.AWSAPITarget, a, ep, changes *Launch
}
for _, x := range []map[string]*BlockDeviceMapping{rootDevices, ephemeralDevices, additionalDevices} {
for name, device := range x {
input.LaunchTemplateData.BlockDeviceMappings = append(input.LaunchTemplateData.BlockDeviceMappings, device.ToLaunchTemplateBootDeviceRequest(name))
data.BlockDeviceMappings = append(data.BlockDeviceMappings, device.ToLaunchTemplateBootDeviceRequest(name))
}
}
// @step: add the ssh key
if t.SSHKey != nil {
lc.KeyName = t.SSHKey.Name
data.KeyName = t.SSHKey.Name
}
// @step: add the security groups
for _, sg := range t.SecurityGroups {
lc.NetworkInterfaces[0].Groups = append(lc.NetworkInterfaces[0].Groups, sg.ID)
data.NetworkInterfaces[0].Groups = append(data.NetworkInterfaces[0].Groups, sg.ID)
}
// @step: add any tenancy details
if t.Tenancy != nil {
lc.Placement = &ec2.LaunchTemplatePlacementRequest{Tenancy: t.Tenancy}
data.Placement = &ec2.LaunchTemplatePlacementRequest{Tenancy: t.Tenancy}
}
// @step: set the instance monitoring
lc.Monitoring = &ec2.LaunchTemplatesMonitoringRequest{Enabled: fi.Bool(false)}
data.Monitoring = &ec2.LaunchTemplatesMonitoringRequest{Enabled: fi.Bool(false)}
if t.InstanceMonitoring != nil {
lc.Monitoring = &ec2.LaunchTemplatesMonitoringRequest{Enabled: t.InstanceMonitoring}
data.Monitoring = &ec2.LaunchTemplatesMonitoringRequest{Enabled: t.InstanceMonitoring}
}
// @step: add the iam instance profile
if t.IAMInstanceProfile != nil {
lc.IamInstanceProfile = &ec2.LaunchTemplateIamInstanceProfileSpecificationRequest{
data.IamInstanceProfile = &ec2.LaunchTemplateIamInstanceProfileSpecificationRequest{
Name: t.IAMInstanceProfile.Name,
}
}
// @step: add the tags
var tags []*ec2.Tag
if len(t.Tags) > 0 {
var tags []*ec2.Tag
for k, v := range t.Tags {
tags = append(tags, &ec2.Tag{
Key: aws.String(k),
Value: aws.String(v),
})
}
lc.TagSpecifications = append(lc.TagSpecifications, &ec2.LaunchTemplateTagSpecificationRequest{
data.TagSpecifications = append(data.TagSpecifications, &ec2.LaunchTemplateTagSpecificationRequest{
ResourceType: aws.String(ec2.ResourceTypeInstance),
Tags: tags,
})
lc.TagSpecifications = append(lc.TagSpecifications, &ec2.LaunchTemplateTagSpecificationRequest{
data.TagSpecifications = append(data.TagSpecifications, &ec2.LaunchTemplateTagSpecificationRequest{
ResourceType: aws.String(ec2.ResourceTypeVolume),
Tags: tags,
})
input.TagSpecifications = append(input.TagSpecifications, &ec2.TagSpecification{
ResourceType: aws.String(ec2.ResourceTypeLaunchTemplate),
Tags: tags,
})
}
// @step: add the userdata
if t.UserData != nil {
@ -129,7 +117,7 @@ func (t *LaunchTemplate) RenderAWS(c *awsup.AWSAPITarget, a, ep, changes *Launch
if err != nil {
return fmt.Errorf("error rendering LaunchTemplate UserData: %v", err)
}
lc.UserData = aws.String(base64.StdEncoding.EncodeToString(d))
data.UserData = aws.String(base64.StdEncoding.EncodeToString(d))
}
// @step: add market options
if fi.StringValue(t.SpotPrice) != "" {
@ -138,18 +126,45 @@ func (t *LaunchTemplate) RenderAWS(c *awsup.AWSAPITarget, a, ep, changes *Launch
InstanceInterruptionBehavior: t.InstanceInterruptionBehavior,
MaxPrice: t.SpotPrice,
}
lc.InstanceMarketOptions = &ec2.LaunchTemplateInstanceMarketOptionsRequest{
data.InstanceMarketOptions = &ec2.LaunchTemplateInstanceMarketOptionsRequest{
MarketType: fi.String("spot"),
SpotOptions: s,
}
}
// @step: attempt to create the launch template
if _, err = c.Cloud.EC2().CreateLaunchTemplate(input); err != nil {
return fmt.Errorf("error creating LaunchTemplate: %v", err)
if a == nil {
input := &ec2.CreateLaunchTemplateInput{
LaunchTemplateName: t.Name,
LaunchTemplateData: data,
TagSpecifications: []*ec2.TagSpecification{
{
ResourceType: aws.String(ec2.ResourceTypeLaunchTemplate),
Tags: tags,
},
},
}
output, err := c.Cloud.EC2().CreateLaunchTemplate(input)
if err != nil || output.LaunchTemplate == nil {
return fmt.Errorf("error creating LaunchTemplate %q: %v", fi.StringValue(t.Name), err)
}
e.ID = output.LaunchTemplate.LaunchTemplateId
} else {
input := &ec2.CreateLaunchTemplateVersionInput{
LaunchTemplateName: t.Name,
LaunchTemplateData: data,
}
if _, err = c.Cloud.EC2().CreateLaunchTemplateVersion(input); err != nil {
return fmt.Errorf("error creating LaunchTemplateVersion: %v", err)
}
if changes.Tags != nil {
err = c.UpdateTags(fi.StringValue(a.ID), e.Tags)
if err != nil {
return fmt.Errorf("error updating LaunchTemplate tags: %v", err)
}
}
e.ID = a.ID
}
ep.ID = fi.String(name)
return nil
}
@ -161,7 +176,7 @@ func (t *LaunchTemplate) Find(c *fi.Context) (*LaunchTemplate, error) {
}
// @step: get the latest launch template version
lt, err := t.findLatestLaunchTemplate(c)
lt, err := t.findLatestLaunchTemplateVersion(c)
if err != nil {
return nil, err
}
@ -173,7 +188,7 @@ func (t *LaunchTemplate) Find(c *fi.Context) (*LaunchTemplate, error) {
actual := &LaunchTemplate{
AssociatePublicIP: fi.Bool(false),
ID: lt.LaunchTemplateName,
ID: lt.LaunchTemplateId,
ImageID: lt.LaunchTemplateData.ImageId,
InstanceMonitoring: fi.Bool(false),
InstanceType: lt.LaunchTemplateData.InstanceType,
@ -285,104 +300,65 @@ func (t *LaunchTemplate) Find(c *fi.Context) (*LaunchTemplate, error) {
// findAllLaunchTemplates returns all the launch templates for us
func (t *LaunchTemplate) findAllLaunchTemplates(c *fi.Context) ([]*ec2.LaunchTemplate, error) {
var list []*ec2.LaunchTemplate
cloud := c.Cloud.(awsup.AWSCloud)
var next *string
for {
resp, err := cloud.EC2().DescribeLaunchTemplates(&ec2.DescribeLaunchTemplatesInput{
NextToken: next,
})
if err != nil {
return nil, err
}
list = append(list, resp.LaunchTemplates...)
if resp.NextToken == nil {
return list, nil
}
next = resp.NextToken
}
}
// findLaunchTemplates returns a list of launch templates
func (t *LaunchTemplate) findLaunchTemplates(c *fi.Context) ([]*ec2.LaunchTemplateVersion, error) {
cloud, ok := c.Cloud.(awsup.AWSCloud)
if !ok {
return []*ec2.LaunchTemplateVersion{}, fmt.Errorf("invalid cloud provider: %v, expected: awsup.AWSCloud", c.Cloud)
return nil, fmt.Errorf("invalid cloud provider: %v, expected: %s", c.Cloud, "awsup.AWSCloud")
}
// @step: get a list of the launch templates
templates, err := t.findAllLaunchTemplates(c)
if err != nil {
return nil, err
input := &ec2.DescribeLaunchTemplatesInput{
Filters: []*ec2.Filter{
{
Name: aws.String("tag:Name"),
Values: []*string{t.Name},
},
},
}
prefix := fmt.Sprintf("%s-", fi.StringValue(t.Name))
// @step: get the launch template versions for the templates we are interested in
var list []*ec2.LaunchTemplateVersion
var next *string
for _, x := range templates {
if strings.HasPrefix(aws.StringValue(x.LaunchTemplateName), prefix) {
err := func() error {
for {
resp, err := cloud.EC2().DescribeLaunchTemplateVersions(&ec2.DescribeLaunchTemplateVersionsInput{
LaunchTemplateName: x.LaunchTemplateName,
NextToken: next,
})
if err != nil {
return err
}
list = append(list, resp.LaunchTemplateVersions...)
if resp.NextToken == nil {
return nil
}
next = resp.NextToken
}
}()
if err != nil {
return nil, err
}
}
}
// @step: sort the configurations in chronological order
sort.Slice(list, func(i, j int) bool {
ti := list[i].CreateTime
tj := list[j].CreateTime
if tj == nil {
return true
}
if ti == nil {
return false
}
return ti.UnixNano() < tj.UnixNano()
var list []*ec2.LaunchTemplate
err := cloud.EC2().DescribeLaunchTemplatesPages(input, func(p *ec2.DescribeLaunchTemplatesOutput, lastPage bool) (shouldContinue bool) {
list = append(list, p.LaunchTemplates...)
return true
})
if err != nil {
return nil, fmt.Errorf("error listing AutoScaling LaunchTemplates: %v", err)
}
return list, nil
}
// findLatestLaunchTemplate returns the latest template
func (t *LaunchTemplate) findLatestLaunchTemplate(c *fi.Context) (*ec2.LaunchTemplateVersion, error) {
// @step: get a list of configuration
configurations, err := t.findLaunchTemplates(c)
if err != nil {
return nil, err
// findLatestLaunchTemplateVersion returns the latest template version
func (t *LaunchTemplate) findLatestLaunchTemplateVersion(c *fi.Context) (*ec2.LaunchTemplateVersion, error) {
cloud, ok := c.Cloud.(awsup.AWSCloud)
if !ok {
return nil, fmt.Errorf("invalid cloud provider: %v, expected: awsup.AWSCloud", c.Cloud)
}
if len(configurations) == 0 {
input := &ec2.DescribeLaunchTemplateVersionsInput{
LaunchTemplateName: t.Name,
Versions: []*string{aws.String("$Latest")},
}
output, err := cloud.EC2().DescribeLaunchTemplateVersions(input)
if err != nil {
if awsup.AWSErrorCode(err) == "InvalidLaunchTemplateName.NotFoundException" {
klog.V(4).Infof("Got InvalidLaunchTemplateName.NotFoundException error describing latest launch template version: %q", aws.StringValue(t.Name))
return nil, nil
} else {
return nil, err
}
}
if len(output.LaunchTemplateVersions) == 0 {
return nil, nil
}
return configurations[len(configurations)-1], nil
return output.LaunchTemplateVersions[0], nil
}
// deleteLaunchTemplate tracks a LaunchConfiguration that we're going to delete
// It implements fi.Deletion
type deleteLaunchTemplate struct {
lc *ec2.LaunchTemplateVersion
lc *ec2.LaunchTemplate
}
var _ fi.Deletion = &deleteLaunchTemplate{}

View File

@ -109,8 +109,8 @@ type terraformLaunchTemplateTagSpecification struct {
}
type terraformLaunchTemplate struct {
// NamePrefix is the name of the launch template
NamePrefix *string `json:"name_prefix,omitempty" cty:"name_prefix"`
// Name is the name of the launch template
Name *string `json:"name,omitempty" cty:"name"`
// Lifecycle is the terraform lifecycle
Lifecycle *terraform.Lifecycle `json:"lifecycle,omitempty" cty:"lifecycle"`
@ -168,7 +168,7 @@ func (t *LaunchTemplate) RenderTerraform(target *terraform.TerraformTarget, a, e
}
tf := terraformLaunchTemplate{
NamePrefix: fi.String(fi.StringValue(e.Name) + "-"),
Name: e.Name,
EBSOptimized: e.RootVolumeOptimization,
ImageID: image,
InstanceType: e.InstanceType,

View File

@ -75,7 +75,7 @@ resource "aws_launch_template" "test" {
monitoring {
enabled = true
}
name_prefix = "test-"
name = "test"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true
@ -154,7 +154,7 @@ resource "aws_launch_template" "test" {
monitoring {
enabled = true
}
name_prefix = "test-"
name = "test"
network_interfaces {
associate_public_ip_address = true
delete_on_termination = true

View File

@ -50,9 +50,19 @@ func (t *AWSAPITarget) AddAWSTags(id string, expected map[string]string) error {
return t.Cloud.AddAWSTags(id, expected)
}
func (t *AWSAPITarget) GetTags(id string) (map[string]string, error) {
return t.Cloud.GetTags(id)
}
func (t *AWSAPITarget) CreateTags(id string, tags map[string]string) error {
return t.Cloud.CreateTags(id, tags)
}
func (t *AWSAPITarget) DeleteTags(id string, tags map[string]string) error {
return t.Cloud.DeleteTags(id, tags)
}
func (t *AWSAPITarget) UpdateTags(id string, tags map[string]string) error {
return t.Cloud.UpdateTags(id, tags)
}
func (t *AWSAPITarget) AddELBV2Tags(ResourceArn string, expected map[string]string) error {
actual, err := t.Cloud.GetELBV2Tags(ResourceArn)
if err != nil {

View File

@ -122,9 +122,12 @@ type AWSCloud interface {
// GetTags will fetch the tags for the specified resource, retrying (up to MaxDescribeTagsAttempts) if it hits an eventual-consistency type error
GetTags(resourceId string) (map[string]string, error)
// CreateTags will add tags to the specified resource, retrying up to MaxCreateTagsAttempts times if it hits an eventual-consistency type error
// CreateTags will add/modify tags to the specified resource, retrying up to MaxCreateTagsAttempts times if it hits an eventual-consistency type error
CreateTags(resourceId string, tags map[string]string) error
// DeleteTags will remove tags from the specified resource, retrying up to MaxCreateTagsAttempts times if it hits an eventual-consistency type error
DeleteTags(resourceId string, tags map[string]string) error
// UpdateTags will update tags of the specified resource to match tags, using getTags(), createTags() and deleteTags()
UpdateTags(resourceId string, tags map[string]string) error
AddAWSTags(id string, expected map[string]string) error
GetELBTags(loadBalancerName string) (map[string]string, error)
@ -137,9 +140,6 @@ type AWSCloud interface {
RemoveELBTags(loadBalancerName string, tags map[string]string) error
RemoveELBV2Tags(ResourceArn string, tags map[string]string) error
// DeleteTags will delete tags from the specified resource, retrying up to MaxCreateTagsAttempts times if it hits an eventual-consistency type error
DeleteTags(id string, tags map[string]string) error
// DescribeInstance is a helper that queries for the specified instance by id
DescribeInstance(instanceID string) (*ec2.Instance, error)
@ -694,52 +694,44 @@ func findAutoscalingGroupLaunchConfiguration(c AWSCloud, g *autoscaling.Group) (
}
// @check the launch template then
var launchTemplate *autoscaling.LaunchTemplateSpecification
if g.LaunchTemplate != nil {
name = aws.StringValue(g.LaunchTemplate.LaunchTemplateName)
version := aws.StringValue(g.LaunchTemplate.Version)
if name != "" {
launchTemplate := name + ":" + version
return launchTemplate, nil
}
launchTemplate = g.LaunchTemplate
} else if g.MixedInstancesPolicy != nil && g.MixedInstancesPolicy.LaunchTemplate != nil && g.MixedInstancesPolicy.LaunchTemplate.LaunchTemplateSpecification != nil {
launchTemplate = g.MixedInstancesPolicy.LaunchTemplate.LaunchTemplateSpecification
} else {
return "", fmt.Errorf("error finding launch template or configuration for autoscaling group: %s", aws.StringValue(g.AutoScalingGroupName))
}
// @check: ok, lets check the mixed instance policy
if g.MixedInstancesPolicy != nil {
if g.MixedInstancesPolicy.LaunchTemplate != nil {
if g.MixedInstancesPolicy.LaunchTemplate.LaunchTemplateSpecification != nil {
var version string
name = aws.StringValue(g.MixedInstancesPolicy.LaunchTemplate.LaunchTemplateSpecification.LaunchTemplateName)
//See what version the ASG is set to use
mixedVersion := aws.StringValue(g.MixedInstancesPolicy.LaunchTemplate.LaunchTemplateSpecification.Version)
//Correctly Handle Default and Latest Versions
if mixedVersion == "" || mixedVersion == "$Default" || mixedVersion == "$Latest" {
request := &ec2.DescribeLaunchTemplatesInput{
LaunchTemplateNames: []*string{&name},
}
dltResponse, err := c.EC2().DescribeLaunchTemplates(request)
if err != nil {
return "", fmt.Errorf("error describing launch templates: %v", err)
}
launchTemplate := dltResponse.LaunchTemplates[0]
if mixedVersion == "" || mixedVersion == "$Default" {
version = strconv.FormatInt(*launchTemplate.DefaultVersionNumber, 10)
} else {
version = strconv.FormatInt(*launchTemplate.LatestVersionNumber, 10)
}
} else {
version = mixedVersion
}
klog.V(4).Infof("Launch Template Version Specified By ASG: %v", mixedVersion)
klog.V(4).Infof("Launch Template Version we are using for compare: %v", version)
if name != "" {
launchTemplate := name + ":" + version
return launchTemplate, nil
}
}
}
id := aws.StringValue(launchTemplate.LaunchTemplateId)
if id == "" {
return "", fmt.Errorf("error finding launch template ID for autoscaling group: %s", aws.StringValue(g.AutoScalingGroupName))
}
return "", fmt.Errorf("error finding launch template or configuration for autoscaling group: %s", aws.StringValue(g.AutoScalingGroupName))
version := aws.StringValue(launchTemplate.Version)
//Correctly Handle Default and Latest Versions
klog.V(4).Infof("Launch Template Version Specified By ASG: %v", version)
if version == "" || version == "$Default" || version == "$Latest" {
input := &ec2.DescribeLaunchTemplatesInput{
LaunchTemplateIds: []*string{&id},
}
output, err := c.EC2().DescribeLaunchTemplates(input)
if err != nil {
return "", fmt.Errorf("error describing launch templates: %q", err)
}
if len(output.LaunchTemplates) == 0 {
return "", fmt.Errorf("error finding launch template by ID: %q", id)
}
launchTemplate := output.LaunchTemplates[0]
if version == "$Latest" {
version = strconv.FormatInt(*launchTemplate.LatestVersionNumber, 10)
} else {
version = strconv.FormatInt(*launchTemplate.DefaultVersionNumber, 10)
}
}
klog.V(4).Infof("Launch Template Version used for compare: %q", version)
return fmt.Sprintf("%s:%s", id, version), nil
}
// findInstanceLaunchConfiguration is responsible for discoverying the launch configuration for an instance
@ -751,10 +743,10 @@ func findInstanceLaunchConfiguration(i *autoscaling.Instance) string {
// else we need to check the launch template
if i.LaunchTemplate != nil {
name = aws.StringValue(i.LaunchTemplate.LaunchTemplateName)
id := aws.StringValue(i.LaunchTemplate.LaunchTemplateId)
version := aws.StringValue(i.LaunchTemplate.Version)
if name != "" {
launchTemplate := name + ":" + version
if id != "" {
launchTemplate := id + ":" + version
return launchTemplate
}
}
@ -1087,6 +1079,49 @@ func deleteTags(c AWSCloud, resourceID string, tags map[string]string) error {
}
}
// UpdateTags will update tags of the specified resource to match tags,
// using getTags(), createTags() and deleteTags()
func (c *awsCloudImplementation) UpdateTags(resourceID string, tags map[string]string) error {
return updateTags(c, resourceID, tags)
}
func updateTags(c AWSCloud, resourceID string, expectedTags map[string]string) error {
actual, err := getTags(c, resourceID)
if err != nil {
return err
}
missing := make(map[string]string)
for k, v := range expectedTags {
if actual[k] != v {
missing[k] = v
}
}
if len(missing) > 0 {
klog.V(4).Infof("Adding tags to %q: %v", resourceID, missing)
err = createTags(c, resourceID, missing)
if err != nil {
return err
}
}
extra := make(map[string]string)
for k, v := range actual {
if _, ok := expectedTags[k]; !ok {
extra[k] = v
}
}
if len(extra) > 0 {
klog.V(4).Infof("Removing tags from %q: %v", resourceID, missing)
err := deleteTags(c, resourceID, extra)
if err != nil {
return err
}
}
return nil
}
func (c *awsCloudImplementation) AddAWSTags(id string, expected map[string]string) error {
return addAWSTags(c, id, expected)
}

View File

@ -158,6 +158,10 @@ func (c *MockAWSCloud) GetTags(resourceID string) (map[string]string, error) {
return getTags(c, resourceID)
}
func (c *MockAWSCloud) UpdateTags(id string, tags map[string]string) error {
return updateTags(c, id, tags)
}
func (c *MockAWSCloud) GetELBTags(loadBalancerName string) (map[string]string, error) {
return getELBTags(c, loadBalancerName)
}