Merge pull request #9794 from rdrgmnzs/lb-attachment

Prevent unintended resource updates to LB attatchments
This commit is contained in:
Kubernetes Prow Robot 2020-10-28 15:18:59 -07:00 committed by GitHub
commit f466403912
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 377 additions and 836 deletions

View File

@ -74,6 +74,20 @@ has been updated by a newer version of kops unless it is given the `--allow-kops
* See note about [Openstack Cinder plugin](#openstack-cinder-plugin) above.
* Terraform users, in order to prevent downtime you will have to remove the state of any existing ELB or TargetGroup attatchments from your Terraform state file. This is due to migrating the attachments to the in-line `aws_autoscaling_group` fields. See the [terraform documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/autoscaling_group) for more information about the difference. This migration is required due to a bug described in [#9913](https://github.com/kubernetes/kops/issues/9913).
To prevent downtime, follow these steps with the new version of Kops:
```
kops update cluster --target terraform ...
terraform plan
terraform state list | grep aws_autoscaling_attachment | xargs -L1 terraform state rm
terraform plan
# Ensure these resources are no longer being destroyed and recreated
terraform apply
```
* If you are using Terraform with an additional .tf file and using "aws_autoscaling_attachment" to attach additional Load Balancers or ALB/NLB Target Groups you'll need to migrate to [attaching them through the InstanceGroup spec instead](https://kops.sigs.k8s.io/instance_groups/#externalloadbalancers).
# Deprecations
* Support for Kubernetes versions 1.11 and 1.12 are deprecated and will be removed in kops 1.20.

View File

@ -25,7 +25,6 @@ import (
"k8s.io/klog/v2"
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/dns"
"k8s.io/kops/pkg/featureflag"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/cloudup/awstasks"
)
@ -273,20 +272,6 @@ func (b *APILoadBalancerBuilder) Build(c *fi.ModelBuilderContext) error {
elb.ForAPIServer = true
}
// When Spotinst Elastigroups are used, there is no need to create
// a separate task for the attachment of the load balancer since this
// is already done as part of the Elastigroup's creation, if needed.
if !featureflag.Spotinst.Enabled() {
for _, ig := range b.MasterInstanceGroups() {
c.AddTask(&awstasks.LoadBalancerAttachment{
Name: fi.String("api-" + ig.ObjectMeta.Name),
Lifecycle: b.Lifecycle,
AutoscalingGroup: b.LinkToAutoscalingGroup(ig),
LoadBalancer: b.LinkToELB("api"),
})
}
}
return nil
}

View File

@ -91,10 +91,6 @@ func (b *AutoscalingGroupModelBuilder) Build(c *fi.ModelBuilderContext) error {
}
c.AddTask(tsk)
// @step: add any external load balancer attachments
if err := b.buildExternalLoadBalancerTasks(c, ig); err != nil {
return err
}
}
return nil
@ -353,6 +349,40 @@ func (b *AutoscalingGroupModelBuilder) buildAutoScalingGroupTask(c *fi.ModelBuil
t.InstanceProtection = ig.Spec.InstanceProtection
// When Spotinst Elastigroups are used, there is no need to create
// a separate task for the attachment of the load balancer since this
// is already done as part of the Elastigroup's creation, if needed.
if !featureflag.Spotinst.Enabled() {
if b.UseLoadBalancerForAPI() && ig.Spec.Role == kops.InstanceGroupRoleMaster {
t.LoadBalancers = append(t.LoadBalancers, b.LinkToELB("api"))
}
if ig.Spec.Role == kops.InstanceGroupRoleBastion {
t.LoadBalancers = append(t.LoadBalancers, b.LinkToELB("bastion"))
}
}
for _, extLB := range ig.Spec.ExternalLoadBalancers {
if extLB.LoadBalancerName != nil {
t.LoadBalancers = append(t.LoadBalancers, &awstasks.LoadBalancer{Name: extLB.LoadBalancerName})
c.AddTask(&awstasks.LoadBalancer{
Name: extLB.LoadBalancerName,
Shared: fi.Bool(true),
})
}
if extLB.TargetGroupARN != nil {
t.TargetGroups = append(t.TargetGroups, &awstasks.TargetGroup{Name: extLB.TargetGroupARN, ARN: extLB.TargetGroupARN})
c.AddTask(&awstasks.TargetGroup{
Name: extLB.TargetGroupARN,
ARN: extLB.TargetGroupARN,
Shared: fi.Bool(true),
})
}
}
// @step: are we using a mixed instance policy
if ig.Spec.MixedInstancesPolicy != nil {
spec := ig.Spec.MixedInstancesPolicy
@ -368,28 +398,3 @@ func (b *AutoscalingGroupModelBuilder) buildAutoScalingGroupTask(c *fi.ModelBuil
return t, nil
}
// buildExternlLoadBalancerTasks is responsible for adding any ELB attachment tasks to the model
func (b *AutoscalingGroupModelBuilder) buildExternalLoadBalancerTasks(c *fi.ModelBuilderContext, ig *kops.InstanceGroup) error {
for _, x := range ig.Spec.ExternalLoadBalancers {
if x.LoadBalancerName != nil {
c.AddTask(&awstasks.ExternalLoadBalancerAttachment{
Name: fi.String("extlb-" + *x.LoadBalancerName + "-" + ig.Name),
Lifecycle: b.Lifecycle,
LoadBalancerName: *x.LoadBalancerName,
AutoscalingGroup: b.LinkToAutoscalingGroup(ig),
})
}
if x.TargetGroupARN != nil {
c.AddTask(&awstasks.ExternalTargetGroupAttachment{
Name: fi.String("exttg-" + *x.TargetGroupARN + "-" + ig.Name),
Lifecycle: b.Lifecycle,
TargetGroupARN: *x.TargetGroupARN,
AutoscalingGroup: b.LinkToAutoscalingGroup(ig),
})
}
}
return nil
}

View File

@ -21,7 +21,6 @@ import (
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/featureflag"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/cloudup/awstasks"
)
@ -263,25 +262,6 @@ func (b *BastionModelBuilder) Build(c *fi.ModelBuilderContext) error {
c.AddTask(elb)
}
// When Spotinst Elastigroups are used, there is no need to create
// a separate task for the attachment of the load balancer since this
// is already done as part of the Elastigroup's creation, if needed.
if !featureflag.Spotinst.Enabled() {
for _, ig := range bastionInstanceGroups {
// We build the ASG when we iterate over the instance groups
// Attach the ELB to the ASG
t := &awstasks.LoadBalancerAttachment{
Name: s("bastion-elb-attachment"),
Lifecycle: b.Lifecycle,
LoadBalancer: elb,
AutoscalingGroup: b.LinkToAutoscalingGroup(ig),
}
c.AddTask(t)
}
}
bastionPublicName := ""
if b.Cluster.Spec.Topology != nil && b.Cluster.Spec.Topology.Bastion != nil {
bastionPublicName = b.Cluster.Spec.Topology.Bastion.BastionPublicName

View File

@ -110,22 +110,13 @@ provider "aws" {
region = "us-test-1"
}
resource "aws_autoscaling_attachment" "bastion-bastionuserdata-example-com" {
autoscaling_group_name = aws_autoscaling_group.bastion-bastionuserdata-example-com.id
elb = aws_elb.bastion-bastionuserdata-example-com.id
}
resource "aws_autoscaling_attachment" "master-us-test-1a-masters-bastionuserdata-example-com" {
autoscaling_group_name = aws_autoscaling_group.master-us-test-1a-masters-bastionuserdata-example-com.id
elb = aws_elb.api-bastionuserdata-example-com.id
}
resource "aws_autoscaling_group" "bastion-bastionuserdata-example-com" {
enabled_metrics = ["GroupDesiredCapacity", "GroupInServiceInstances", "GroupMaxSize", "GroupMinSize", "GroupPendingInstances", "GroupStandbyInstances", "GroupTerminatingInstances", "GroupTotalInstances"]
launch_template {
id = aws_launch_template.bastion-bastionuserdata-example-com.id
version = aws_launch_template.bastion-bastionuserdata-example-com.latest_version
}
load_balancers = [aws_elb.bastion-bastionuserdata-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1
@ -174,6 +165,7 @@ resource "aws_autoscaling_group" "master-us-test-1a-masters-bastionuserdata-exam
id = aws_launch_template.master-us-test-1a-masters-bastionuserdata-example-com.id
version = aws_launch_template.master-us-test-1a-masters-bastionuserdata-example-com.latest_version
}
load_balancers = [aws_elb.api-bastionuserdata-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1

View File

@ -80,17 +80,13 @@ provider "aws" {
region = "us-test-1"
}
resource "aws_autoscaling_attachment" "master-us-test-1a-masters-complex-example-com" {
autoscaling_group_name = aws_autoscaling_group.master-us-test-1a-masters-complex-example-com.id
elb = aws_elb.api-complex-example-com.id
}
resource "aws_autoscaling_group" "master-us-test-1a-masters-complex-example-com" {
enabled_metrics = ["GroupDesiredCapacity", "GroupInServiceInstances", "GroupMaxSize", "GroupMinSize", "GroupPendingInstances", "GroupStandbyInstances", "GroupTerminatingInstances", "GroupTotalInstances"]
launch_template {
id = aws_launch_template.master-us-test-1a-masters-complex-example-com.id
version = aws_launch_template.master-us-test-1a-masters-complex-example-com.latest_version
}
load_balancers = [aws_elb.api-complex-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1

View File

@ -90,27 +90,13 @@ provider "aws" {
region = "us-test-1"
}
resource "aws_autoscaling_attachment" "master-us-test-1a-masters-existingsg-example-com" {
autoscaling_group_name = aws_autoscaling_group.master-us-test-1a-masters-existingsg-example-com.id
elb = aws_elb.api-existingsg-example-com.id
}
resource "aws_autoscaling_attachment" "master-us-test-1b-masters-existingsg-example-com" {
autoscaling_group_name = aws_autoscaling_group.master-us-test-1b-masters-existingsg-example-com.id
elb = aws_elb.api-existingsg-example-com.id
}
resource "aws_autoscaling_attachment" "master-us-test-1c-masters-existingsg-example-com" {
autoscaling_group_name = aws_autoscaling_group.master-us-test-1c-masters-existingsg-example-com.id
elb = aws_elb.api-existingsg-example-com.id
}
resource "aws_autoscaling_group" "master-us-test-1a-masters-existingsg-example-com" {
enabled_metrics = ["GroupDesiredCapacity", "GroupInServiceInstances", "GroupMaxSize", "GroupMinSize", "GroupPendingInstances", "GroupStandbyInstances", "GroupTerminatingInstances", "GroupTotalInstances"]
launch_template {
id = aws_launch_template.master-us-test-1a-masters-existingsg-example-com.id
version = aws_launch_template.master-us-test-1a-masters-existingsg-example-com.latest_version
}
load_balancers = [aws_elb.api-existingsg-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1
@ -159,6 +145,7 @@ resource "aws_autoscaling_group" "master-us-test-1b-masters-existingsg-example-c
id = aws_launch_template.master-us-test-1b-masters-existingsg-example-com.id
version = aws_launch_template.master-us-test-1b-masters-existingsg-example-com.latest_version
}
load_balancers = [aws_elb.api-existingsg-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1
@ -207,6 +194,7 @@ resource "aws_autoscaling_group" "master-us-test-1c-masters-existingsg-example-c
id = aws_launch_template.master-us-test-1c-masters-existingsg-example-com.id
version = aws_launch_template.master-us-test-1c-masters-existingsg-example-com.latest_version
}
load_balancers = [aws_elb.api-existingsg-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1

View File

@ -80,27 +80,13 @@ provider "aws" {
region = "us-test-1"
}
resource "aws_autoscaling_attachment" "extlb-my-elb-nodes" {
autoscaling_group_name = aws_autoscaling_group.nodes-externallb-example-com.id
elb = "my-elb"
}
resource "aws_autoscaling_attachment" "extlb-my-other-elb-master-us-test-1a" {
autoscaling_group_name = aws_autoscaling_group.master-us-test-1a-masters-externallb-example-com.id
elb = "my-other-elb"
}
resource "aws_autoscaling_attachment" "exttg-aws_my-tg--0123456789abcdef-master-us-test-1a" {
alb_target_group_arn = "aws:arn:elasticloadbalancing:us-test-1a:123456789012:targetgroup/my-tg/0123456789abcdef"
autoscaling_group_name = aws_autoscaling_group.master-us-test-1a-masters-externallb-example-com.id
}
resource "aws_autoscaling_group" "master-us-test-1a-masters-externallb-example-com" {
enabled_metrics = ["GroupDesiredCapacity", "GroupInServiceInstances", "GroupMaxSize", "GroupMinSize", "GroupPendingInstances", "GroupStandbyInstances", "GroupTerminatingInstances", "GroupTotalInstances"]
launch_template {
id = aws_launch_template.master-us-test-1a-masters-externallb-example-com.id
version = aws_launch_template.master-us-test-1a-masters-externallb-example-com.latest_version
}
load_balancers = ["my-other-elb"]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1
@ -140,6 +126,7 @@ resource "aws_autoscaling_group" "master-us-test-1a-masters-externallb-example-c
propagate_at_launch = true
value = "owned"
}
target_group_arns = ["aws:arn:elasticloadbalancing:us-test-1a:123456789012:targetgroup/my-tg/0123456789abcdef"]
vpc_zone_identifier = [aws_subnet.us-test-1a-externallb-example-com.id]
}
@ -149,6 +136,7 @@ resource "aws_autoscaling_group" "nodes-externallb-example-com" {
id = aws_launch_template.nodes-externallb-example-com.id
version = aws_launch_template.nodes-externallb-example-com.latest_version
}
load_balancers = ["my-elb"]
max_size = 2
metrics_granularity = "1Minute"
min_size = 2

View File

@ -80,17 +80,13 @@ provider "aws" {
region = "us-test-1"
}
resource "aws_autoscaling_attachment" "master-us-test-1a-masters-externalpolicies-example-com" {
autoscaling_group_name = aws_autoscaling_group.master-us-test-1a-masters-externalpolicies-example-com.id
elb = aws_elb.api-externalpolicies-example-com.id
}
resource "aws_autoscaling_group" "master-us-test-1a-masters-externalpolicies-example-com" {
enabled_metrics = ["GroupDesiredCapacity", "GroupInServiceInstances", "GroupMaxSize", "GroupMinSize", "GroupPendingInstances", "GroupStandbyInstances", "GroupTerminatingInstances", "GroupTotalInstances"]
launch_template {
id = aws_launch_template.master-us-test-1a-masters-externalpolicies-example-com.id
version = aws_launch_template.master-us-test-1a-masters-externalpolicies-example-com.latest_version
}
load_balancers = [aws_elb.api-externalpolicies-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1

View File

@ -100,22 +100,13 @@ provider "aws" {
region = "us-test-1"
}
resource "aws_autoscaling_attachment" "bastion-private-shared-subnet-example-com" {
autoscaling_group_name = aws_autoscaling_group.bastion-private-shared-subnet-example-com.id
elb = aws_elb.bastion-private-shared-subnet-example-com.id
}
resource "aws_autoscaling_attachment" "master-us-test-1a-masters-private-shared-subnet-example-com" {
autoscaling_group_name = aws_autoscaling_group.master-us-test-1a-masters-private-shared-subnet-example-com.id
elb = aws_elb.api-private-shared-subnet-example-com.id
}
resource "aws_autoscaling_group" "bastion-private-shared-subnet-example-com" {
enabled_metrics = ["GroupDesiredCapacity", "GroupInServiceInstances", "GroupMaxSize", "GroupMinSize", "GroupPendingInstances", "GroupStandbyInstances", "GroupTerminatingInstances", "GroupTotalInstances"]
launch_template {
id = aws_launch_template.bastion-private-shared-subnet-example-com.id
version = aws_launch_template.bastion-private-shared-subnet-example-com.latest_version
}
load_balancers = [aws_elb.bastion-private-shared-subnet-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1
@ -164,6 +155,7 @@ resource "aws_autoscaling_group" "master-us-test-1a-masters-private-shared-subne
id = aws_launch_template.master-us-test-1a-masters-private-shared-subnet-example-com.id
version = aws_launch_template.master-us-test-1a-masters-private-shared-subnet-example-com.latest_version
}
load_balancers = [aws_elb.api-private-shared-subnet-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1

View File

@ -110,22 +110,13 @@ provider "aws" {
region = "us-test-1"
}
resource "aws_autoscaling_attachment" "bastion-privatecalico-example-com" {
autoscaling_group_name = aws_autoscaling_group.bastion-privatecalico-example-com.id
elb = aws_elb.bastion-privatecalico-example-com.id
}
resource "aws_autoscaling_attachment" "master-us-test-1a-masters-privatecalico-example-com" {
autoscaling_group_name = aws_autoscaling_group.master-us-test-1a-masters-privatecalico-example-com.id
elb = aws_elb.api-privatecalico-example-com.id
}
resource "aws_autoscaling_group" "bastion-privatecalico-example-com" {
enabled_metrics = ["GroupDesiredCapacity", "GroupInServiceInstances", "GroupMaxSize", "GroupMinSize", "GroupPendingInstances", "GroupStandbyInstances", "GroupTerminatingInstances", "GroupTotalInstances"]
launch_template {
id = aws_launch_template.bastion-privatecalico-example-com.id
version = aws_launch_template.bastion-privatecalico-example-com.latest_version
}
load_balancers = [aws_elb.bastion-privatecalico-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1
@ -174,6 +165,7 @@ resource "aws_autoscaling_group" "master-us-test-1a-masters-privatecalico-exampl
id = aws_launch_template.master-us-test-1a-masters-privatecalico-example-com.id
version = aws_launch_template.master-us-test-1a-masters-privatecalico-example-com.latest_version
}
load_balancers = [aws_elb.api-privatecalico-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1

View File

@ -110,22 +110,13 @@ provider "aws" {
region = "us-test-1"
}
resource "aws_autoscaling_attachment" "bastion-privatecanal-example-com" {
autoscaling_group_name = aws_autoscaling_group.bastion-privatecanal-example-com.id
elb = aws_elb.bastion-privatecanal-example-com.id
}
resource "aws_autoscaling_attachment" "master-us-test-1a-masters-privatecanal-example-com" {
autoscaling_group_name = aws_autoscaling_group.master-us-test-1a-masters-privatecanal-example-com.id
elb = aws_elb.api-privatecanal-example-com.id
}
resource "aws_autoscaling_group" "bastion-privatecanal-example-com" {
enabled_metrics = ["GroupDesiredCapacity", "GroupInServiceInstances", "GroupMaxSize", "GroupMinSize", "GroupPendingInstances", "GroupStandbyInstances", "GroupTerminatingInstances", "GroupTotalInstances"]
launch_template {
id = aws_launch_template.bastion-privatecanal-example-com.id
version = aws_launch_template.bastion-privatecanal-example-com.latest_version
}
load_balancers = [aws_elb.bastion-privatecanal-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1
@ -174,6 +165,7 @@ resource "aws_autoscaling_group" "master-us-test-1a-masters-privatecanal-example
id = aws_launch_template.master-us-test-1a-masters-privatecanal-example-com.id
version = aws_launch_template.master-us-test-1a-masters-privatecanal-example-com.latest_version
}
load_balancers = [aws_elb.api-privatecanal-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1

View File

@ -110,22 +110,13 @@ provider "aws" {
region = "us-test-1"
}
resource "aws_autoscaling_attachment" "bastion-privatecilium-example-com" {
autoscaling_group_name = aws_autoscaling_group.bastion-privatecilium-example-com.id
elb = aws_elb.bastion-privatecilium-example-com.id
}
resource "aws_autoscaling_attachment" "master-us-test-1a-masters-privatecilium-example-com" {
autoscaling_group_name = aws_autoscaling_group.master-us-test-1a-masters-privatecilium-example-com.id
elb = aws_elb.api-privatecilium-example-com.id
}
resource "aws_autoscaling_group" "bastion-privatecilium-example-com" {
enabled_metrics = ["GroupDesiredCapacity", "GroupInServiceInstances", "GroupMaxSize", "GroupMinSize", "GroupPendingInstances", "GroupStandbyInstances", "GroupTerminatingInstances", "GroupTotalInstances"]
launch_template {
id = aws_launch_template.bastion-privatecilium-example-com.id
version = aws_launch_template.bastion-privatecilium-example-com.latest_version
}
load_balancers = [aws_elb.bastion-privatecilium-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1
@ -174,6 +165,7 @@ resource "aws_autoscaling_group" "master-us-test-1a-masters-privatecilium-exampl
id = aws_launch_template.master-us-test-1a-masters-privatecilium-example-com.id
version = aws_launch_template.master-us-test-1a-masters-privatecilium-example-com.latest_version
}
load_balancers = [aws_elb.api-privatecilium-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1

View File

@ -110,22 +110,13 @@ provider "aws" {
region = "us-test-1"
}
resource "aws_autoscaling_attachment" "bastion-privatecilium-example-com" {
autoscaling_group_name = aws_autoscaling_group.bastion-privatecilium-example-com.id
elb = aws_elb.bastion-privatecilium-example-com.id
}
resource "aws_autoscaling_attachment" "master-us-test-1a-masters-privatecilium-example-com" {
autoscaling_group_name = aws_autoscaling_group.master-us-test-1a-masters-privatecilium-example-com.id
elb = aws_elb.api-privatecilium-example-com.id
}
resource "aws_autoscaling_group" "bastion-privatecilium-example-com" {
enabled_metrics = ["GroupDesiredCapacity", "GroupInServiceInstances", "GroupMaxSize", "GroupMinSize", "GroupPendingInstances", "GroupStandbyInstances", "GroupTerminatingInstances", "GroupTotalInstances"]
launch_template {
id = aws_launch_template.bastion-privatecilium-example-com.id
version = aws_launch_template.bastion-privatecilium-example-com.latest_version
}
load_balancers = [aws_elb.bastion-privatecilium-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1
@ -174,6 +165,7 @@ resource "aws_autoscaling_group" "master-us-test-1a-masters-privatecilium-exampl
id = aws_launch_template.master-us-test-1a-masters-privatecilium-example-com.id
version = aws_launch_template.master-us-test-1a-masters-privatecilium-example-com.latest_version
}
load_balancers = [aws_elb.api-privatecilium-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1

View File

@ -110,22 +110,13 @@ provider "aws" {
region = "us-test-1"
}
resource "aws_autoscaling_attachment" "bastion-privateciliumadvanced-example-com" {
autoscaling_group_name = aws_autoscaling_group.bastion-privateciliumadvanced-example-com.id
elb = aws_elb.bastion-privateciliumadvanced-example-com.id
}
resource "aws_autoscaling_attachment" "master-us-test-1a-masters-privateciliumadvanced-example-com" {
autoscaling_group_name = aws_autoscaling_group.master-us-test-1a-masters-privateciliumadvanced-example-com.id
elb = aws_elb.api-privateciliumadvanced-example-com.id
}
resource "aws_autoscaling_group" "bastion-privateciliumadvanced-example-com" {
enabled_metrics = ["GroupDesiredCapacity", "GroupInServiceInstances", "GroupMaxSize", "GroupMinSize", "GroupPendingInstances", "GroupStandbyInstances", "GroupTerminatingInstances", "GroupTotalInstances"]
launch_template {
id = aws_launch_template.bastion-privateciliumadvanced-example-com.id
version = aws_launch_template.bastion-privateciliumadvanced-example-com.latest_version
}
load_balancers = [aws_elb.bastion-privateciliumadvanced-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1
@ -174,6 +165,7 @@ resource "aws_autoscaling_group" "master-us-test-1a-masters-privateciliumadvance
id = aws_launch_template.master-us-test-1a-masters-privateciliumadvanced-example-com.id
version = aws_launch_template.master-us-test-1a-masters-privateciliumadvanced-example-com.latest_version
}
load_balancers = [aws_elb.api-privateciliumadvanced-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1

View File

@ -110,22 +110,13 @@ provider "aws" {
region = "us-test-1"
}
resource "aws_autoscaling_attachment" "bastion-privatedns1-example-com" {
autoscaling_group_name = aws_autoscaling_group.bastion-privatedns1-example-com.id
elb = aws_elb.bastion-privatedns1-example-com.id
}
resource "aws_autoscaling_attachment" "master-us-test-1a-masters-privatedns1-example-com" {
autoscaling_group_name = aws_autoscaling_group.master-us-test-1a-masters-privatedns1-example-com.id
elb = aws_elb.api-privatedns1-example-com.id
}
resource "aws_autoscaling_group" "bastion-privatedns1-example-com" {
enabled_metrics = ["GroupDesiredCapacity", "GroupInServiceInstances", "GroupMaxSize", "GroupMinSize", "GroupPendingInstances", "GroupStandbyInstances", "GroupTerminatingInstances", "GroupTotalInstances"]
launch_template {
id = aws_launch_template.bastion-privatedns1-example-com.id
version = aws_launch_template.bastion-privatedns1-example-com.latest_version
}
load_balancers = [aws_elb.bastion-privatedns1-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1
@ -184,6 +175,7 @@ resource "aws_autoscaling_group" "master-us-test-1a-masters-privatedns1-example-
id = aws_launch_template.master-us-test-1a-masters-privatedns1-example-com.id
version = aws_launch_template.master-us-test-1a-masters-privatedns1-example-com.latest_version
}
load_balancers = [aws_elb.api-privatedns1-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1

View File

@ -105,22 +105,13 @@ provider "aws" {
region = "us-test-1"
}
resource "aws_autoscaling_attachment" "bastion-privatedns2-example-com" {
autoscaling_group_name = aws_autoscaling_group.bastion-privatedns2-example-com.id
elb = aws_elb.bastion-privatedns2-example-com.id
}
resource "aws_autoscaling_attachment" "master-us-test-1a-masters-privatedns2-example-com" {
autoscaling_group_name = aws_autoscaling_group.master-us-test-1a-masters-privatedns2-example-com.id
elb = aws_elb.api-privatedns2-example-com.id
}
resource "aws_autoscaling_group" "bastion-privatedns2-example-com" {
enabled_metrics = ["GroupDesiredCapacity", "GroupInServiceInstances", "GroupMaxSize", "GroupMinSize", "GroupPendingInstances", "GroupStandbyInstances", "GroupTerminatingInstances", "GroupTotalInstances"]
launch_template {
id = aws_launch_template.bastion-privatedns2-example-com.id
version = aws_launch_template.bastion-privatedns2-example-com.latest_version
}
load_balancers = [aws_elb.bastion-privatedns2-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1
@ -169,6 +160,7 @@ resource "aws_autoscaling_group" "master-us-test-1a-masters-privatedns2-example-
id = aws_launch_template.master-us-test-1a-masters-privatedns2-example-com.id
version = aws_launch_template.master-us-test-1a-masters-privatedns2-example-com.latest_version
}
load_balancers = [aws_elb.api-privatedns2-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1

View File

@ -110,22 +110,13 @@ provider "aws" {
region = "us-test-1"
}
resource "aws_autoscaling_attachment" "bastion-privateflannel-example-com" {
autoscaling_group_name = aws_autoscaling_group.bastion-privateflannel-example-com.id
elb = aws_elb.bastion-privateflannel-example-com.id
}
resource "aws_autoscaling_attachment" "master-us-test-1a-masters-privateflannel-example-com" {
autoscaling_group_name = aws_autoscaling_group.master-us-test-1a-masters-privateflannel-example-com.id
elb = aws_elb.api-privateflannel-example-com.id
}
resource "aws_autoscaling_group" "bastion-privateflannel-example-com" {
enabled_metrics = ["GroupDesiredCapacity", "GroupInServiceInstances", "GroupMaxSize", "GroupMinSize", "GroupPendingInstances", "GroupStandbyInstances", "GroupTerminatingInstances", "GroupTotalInstances"]
launch_template {
id = aws_launch_template.bastion-privateflannel-example-com.id
version = aws_launch_template.bastion-privateflannel-example-com.latest_version
}
load_balancers = [aws_elb.bastion-privateflannel-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1
@ -174,6 +165,7 @@ resource "aws_autoscaling_group" "master-us-test-1a-masters-privateflannel-examp
id = aws_launch_template.master-us-test-1a-masters-privateflannel-example-com.id
version = aws_launch_template.master-us-test-1a-masters-privateflannel-example-com.latest_version
}
load_balancers = [aws_elb.api-privateflannel-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1

View File

@ -125,22 +125,13 @@ provider "aws" {
region = "us-test-1"
}
resource "aws_autoscaling_attachment" "bastion-privatekopeio-example-com" {
autoscaling_group_name = aws_autoscaling_group.bastion-privatekopeio-example-com.id
elb = aws_elb.bastion-privatekopeio-example-com.id
}
resource "aws_autoscaling_attachment" "master-us-test-1a-masters-privatekopeio-example-com" {
autoscaling_group_name = aws_autoscaling_group.master-us-test-1a-masters-privatekopeio-example-com.id
elb = aws_elb.api-privatekopeio-example-com.id
}
resource "aws_autoscaling_group" "bastion-privatekopeio-example-com" {
enabled_metrics = ["GroupDesiredCapacity", "GroupInServiceInstances", "GroupMaxSize", "GroupMinSize", "GroupPendingInstances", "GroupStandbyInstances", "GroupTerminatingInstances", "GroupTotalInstances"]
launch_template {
id = aws_launch_template.bastion-privatekopeio-example-com.id
version = aws_launch_template.bastion-privatekopeio-example-com.latest_version
}
load_balancers = [aws_elb.bastion-privatekopeio-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1
@ -189,6 +180,7 @@ resource "aws_autoscaling_group" "master-us-test-1a-masters-privatekopeio-exampl
id = aws_launch_template.master-us-test-1a-masters-privatekopeio-example-com.id
version = aws_launch_template.master-us-test-1a-masters-privatekopeio-example-com.latest_version
}
load_balancers = [aws_elb.api-privatekopeio-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1

View File

@ -110,22 +110,13 @@ provider "aws" {
region = "us-test-1"
}
resource "aws_autoscaling_attachment" "bastion-privateweave-example-com" {
autoscaling_group_name = aws_autoscaling_group.bastion-privateweave-example-com.id
elb = aws_elb.bastion-privateweave-example-com.id
}
resource "aws_autoscaling_attachment" "master-us-test-1a-masters-privateweave-example-com" {
autoscaling_group_name = aws_autoscaling_group.master-us-test-1a-masters-privateweave-example-com.id
elb = aws_elb.api-privateweave-example-com.id
}
resource "aws_autoscaling_group" "bastion-privateweave-example-com" {
enabled_metrics = ["GroupDesiredCapacity", "GroupInServiceInstances", "GroupMaxSize", "GroupMinSize", "GroupPendingInstances", "GroupStandbyInstances", "GroupTerminatingInstances", "GroupTotalInstances"]
launch_template {
id = aws_launch_template.bastion-privateweave-example-com.id
version = aws_launch_template.bastion-privateweave-example-com.latest_version
}
load_balancers = [aws_elb.bastion-privateweave-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1
@ -174,6 +165,7 @@ resource "aws_autoscaling_group" "master-us-test-1a-masters-privateweave-example
id = aws_launch_template.master-us-test-1a-masters-privateweave-example-com.id
version = aws_launch_template.master-us-test-1a-masters-privateweave-example-com.latest_version
}
load_balancers = [aws_elb.api-privateweave-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1

View File

@ -105,22 +105,13 @@ provider "aws" {
region = "us-test-1"
}
resource "aws_autoscaling_attachment" "bastion-unmanaged-example-com" {
autoscaling_group_name = aws_autoscaling_group.bastion-unmanaged-example-com.id
elb = aws_elb.bastion-unmanaged-example-com.id
}
resource "aws_autoscaling_attachment" "master-us-test-1a-masters-unmanaged-example-com" {
autoscaling_group_name = aws_autoscaling_group.master-us-test-1a-masters-unmanaged-example-com.id
elb = aws_elb.api-unmanaged-example-com.id
}
resource "aws_autoscaling_group" "bastion-unmanaged-example-com" {
enabled_metrics = ["GroupDesiredCapacity", "GroupInServiceInstances", "GroupMaxSize", "GroupMinSize", "GroupPendingInstances", "GroupStandbyInstances", "GroupTerminatingInstances", "GroupTotalInstances"]
launch_template {
id = aws_launch_template.bastion-unmanaged-example-com.id
version = aws_launch_template.bastion-unmanaged-example-com.latest_version
}
load_balancers = [aws_elb.bastion-unmanaged-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1
@ -169,6 +160,7 @@ resource "aws_autoscaling_group" "master-us-test-1a-masters-unmanaged-example-co
id = aws_launch_template.master-us-test-1a-masters-unmanaged-example-com.id
version = aws_launch_template.master-us-test-1a-masters-unmanaged-example-com.latest_version
}
load_balancers = [aws_elb.api-unmanaged-example-com.id]
max_size = 1
metrics_granularity = "1Minute"
min_size = 1

View File

@ -18,10 +18,6 @@ go_library(
"ebsvolume_fitask.go",
"elastic_ip.go",
"elasticip_fitask.go",
"external_load_balancer_attachment.go",
"external_target_group_attachment.go",
"externalloadbalancerattachment_fitask.go",
"externaltargetgroupattachment_fitask.go",
"helper.go",
"iaminstanceprofile.go",
"iaminstanceprofile_fitask.go",
@ -47,11 +43,9 @@ go_library(
"launchtemplate_target_cloudformation.go",
"launchtemplate_target_terraform.go",
"load_balancer.go",
"load_balancer_attachment.go",
"loadbalancer_attributes.go",
"loadbalancer_fitask.go",
"loadbalancer_healthchecks.go",
"loadbalancerattachment_fitask.go",
"natgateway.go",
"natgateway_fitask.go",
"route.go",
@ -69,6 +63,8 @@ go_library(
"subnet.go",
"subnet_fitask.go",
"tags.go",
"targetgroup.go",
"targetgroup_fitask.go",
"vpc.go",
"vpc_dhcpoptions_association.go",
"vpc_fitask.go",

View File

@ -54,6 +54,8 @@ type AutoscalingGroup struct {
LaunchConfiguration *LaunchConfiguration
// LaunchTemplate is the launch template for the asg
LaunchTemplate *LaunchTemplate
// LoadBalancers is a list of elastic load balancer names to add to the autoscaling group
LoadBalancers []*LoadBalancer
// MaxSize is the max number of nodes in asg
MaxSize *int64
// Metrics is a collection of metrics to monitor
@ -85,6 +87,8 @@ type AutoscalingGroup struct {
SuspendProcesses *[]string
// Tags is a collection of keypairs to apply to the node on launch
Tags map[string]string
// TargetGroups is a list of ALB/NLB target group ARNs to add to the autoscaling group
TargetGroups []*TargetGroup
}
var _ fi.CompareWithID = &AutoscalingGroup{}
@ -112,6 +116,14 @@ func (e *AutoscalingGroup) Find(c *fi.Context) (*AutoscalingGroup, error) {
MinSize: g.MinSize,
}
for _, lb := range g.LoadBalancerNames {
actual.LoadBalancers = append(actual.LoadBalancers, &LoadBalancer{Name: aws.String(*lb)})
}
for _, tg := range g.TargetGroupARNs {
actual.TargetGroups = append(actual.TargetGroups, &TargetGroup{ARN: aws.String(*tg)})
}
if g.VPCZoneIdentifier != nil {
subnets := strings.Split(*g.VPCZoneIdentifier, ",")
for _, subnet := range subnets {
@ -264,6 +276,14 @@ func (v *AutoscalingGroup) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *Autos
VPCZoneIdentifier: fi.String(strings.Join(e.AutoscalingGroupSubnets(), ",")),
}
for _, k := range e.LoadBalancers {
request.LoadBalancerNames = append(request.LoadBalancerNames, k.GetName())
}
for _, tg := range e.TargetGroups {
request.TargetGroupARNs = append(request.TargetGroupARNs, tg.ARN)
}
// @check are we using a launch configuration, mixed instances policy, or launch template
if e.LaunchConfiguration != nil {
request.LaunchConfigurationName = e.LaunchConfiguration.ID
@ -444,6 +464,22 @@ func (v *AutoscalingGroup) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *Autos
changes.Tags = nil
}
var attachLBRequest *autoscaling.AttachLoadBalancersInput
var detachLBRequest *autoscaling.DetachLoadBalancersInput
if changes.LoadBalancers != nil {
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.Tags = nil
}
if changes.Metrics != nil || changes.Granularity != nil {
// TODO: Support disabling metrics?
if len(e.Metrics) != 0 {
@ -513,6 +549,17 @@ func (v *AutoscalingGroup) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *Autos
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)
}
}
}
return nil
@ -574,6 +621,17 @@ func (e *AutoscalingGroup) AutoscalingGroupSubnets() []string {
return list
}
// AutoscalingLoadBalancers returns a list of LBs attatched to the ASG
func (e *AutoscalingGroup) AutoscalingLoadBalancers() []*string {
var list []*string
for _, v := range e.LoadBalancers {
list = append(list, v.Name)
}
return list
}
// processCompare returns processes that exist in a but not in b
func processCompare(a *[]string, b *[]string) []*string {
notInB := []*string{}
@ -611,6 +669,24 @@ func (e *AutoscalingGroup) getASGTagsToDelete(currentTags map[string]string) []*
return tagsToDelete
}
// getLBsToDetach loops through the currently set LBs and builds a list of
// LBs to be detach from the Autoscaling Group
func (e *AutoscalingGroup) getLBsToDetach(currentLBs []*LoadBalancer) []*string {
lbsToDetach := []*string{}
desiredLBs := map[string]bool{}
for _, v := range e.LoadBalancers {
desiredLBs[*v.Name] = true
}
for _, v := range currentLBs {
if _, ok := desiredLBs[*v.Name]; !ok {
lbsToDetach = append(lbsToDetach, v.Name)
}
}
return lbsToDetach
}
type terraformASGTag struct {
Key *string `json:"key" cty:"key"`
Value *string `json:"value" cty:"value"`
@ -678,6 +754,8 @@ type terraformAutoscalingGroup struct {
EnabledMetrics []*string `json:"enabled_metrics,omitempty" cty:"enabled_metrics"`
SuspendedProcesses []*string `json:"suspended_processes,omitempty" cty:"suspended_processes"`
InstanceProtection *bool `json:"protect_from_scale_in,omitempty" cty:"protect_from_scale_in"`
LoadBalancers []*terraform.Literal `json:"load_balancers,omitempty" cty:"load_balancers"`
TargetGroupARNs []*terraform.Literal `json:"target_group_arns,omitempty" cty:"target_group_arns"`
}
// RenderTerraform is responsible for rendering the terraform codebase
@ -704,6 +782,16 @@ func (_ *AutoscalingGroup) RenderTerraform(t *terraform.TerraformTarget, a, e, c
})
}
for _, k := range e.LoadBalancers {
tf.LoadBalancers = append(tf.LoadBalancers, k.TerraformLink())
}
terraform.SortLiterals(tf.LoadBalancers)
for _, tg := range e.TargetGroups {
tf.TargetGroupARNs = append(tf.TargetGroupARNs, tg.TerraformLink())
}
terraform.SortLiterals(tf.TargetGroupARNs)
if e.LaunchConfiguration != nil {
tf.LaunchConfigurationName = e.LaunchConfiguration.TerraformLink()
} else if e.UseMixedInstancesPolicy() {
@ -931,6 +1019,14 @@ func (_ *AutoscalingGroup) RenderCloudformation(t *cloudformation.Cloudformation
})
}
for _, k := range e.LoadBalancers {
cf.LoadBalancerNames = append(cf.LoadBalancerNames, k.CloudformationLink())
}
for _, tg := range e.TargetGroups {
cf.TargetGroupARNs = append(cf.TargetGroupARNs, tg.CloudformationLink())
}
return t.RenderResource("AWS::AutoScaling::AutoScalingGroup", fi.StringValue(e.Name), cf)
}

View File

@ -1,140 +0,0 @@
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package awstasks
import (
"fmt"
"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"
)
// +kops:fitask
type ExternalLoadBalancerAttachment struct {
Name *string
Lifecycle *fi.Lifecycle
LoadBalancerName string
AutoscalingGroup *AutoscalingGroup
}
func (e *ExternalLoadBalancerAttachment) Find(c *fi.Context) (*ExternalLoadBalancerAttachment, error) {
cloud := c.Cloud.(awsup.AWSCloud)
if e.LoadBalancerName == "" {
return nil, fmt.Errorf("InstanceGroup did not have LoadBalancerNames set")
}
g, err := findAutoscalingGroup(cloud, *e.AutoscalingGroup.Name)
if err != nil {
return nil, err
}
if g == nil {
return nil, nil
}
for _, name := range g.LoadBalancerNames {
if aws.StringValue(name) != e.LoadBalancerName {
continue
}
actual := &ExternalLoadBalancerAttachment{}
actual.LoadBalancerName = e.LoadBalancerName
actual.AutoscalingGroup = e.AutoscalingGroup
// Prevent spurious changes
actual.Name = e.Name // ELB attachments don't have tags
actual.Lifecycle = e.Lifecycle
return actual, nil
}
return nil, nil
}
func (e *ExternalLoadBalancerAttachment) Run(c *fi.Context) error {
return fi.DefaultDeltaRunMethod(e, c)
}
func (s *ExternalLoadBalancerAttachment) CheckChanges(a, e, changes *ExternalLoadBalancerAttachment) error {
if a == nil {
if e.LoadBalancerName == "" {
return fi.RequiredField("LoadBalancerName")
}
if e.AutoscalingGroup == nil {
return fi.RequiredField("AutoscalingGroup")
}
}
return nil
}
func (_ *ExternalLoadBalancerAttachment) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *ExternalLoadBalancerAttachment) error {
if e.LoadBalancerName == "" {
return fi.RequiredField("LoadBalancerName")
}
request := &autoscaling.AttachLoadBalancersInput{}
request.AutoScalingGroupName = e.AutoscalingGroup.Name
request.LoadBalancerNames = aws.StringSlice([]string{e.LoadBalancerName})
klog.V(2).Infof("Attaching autoscaling group %q to ELB %q", fi.StringValue(e.AutoscalingGroup.Name), e.LoadBalancerName)
_, err := t.Cloud.Autoscaling().AttachLoadBalancers(request)
if err != nil {
return fmt.Errorf("error attaching autoscaling group to ELB: %v", err)
}
return nil
}
type terraformExternalLoadBalancerAttachment struct {
ELB *terraform.Literal `json:"elb" cty:"elb"`
AutoscalingGroup *terraform.Literal `json:"autoscaling_group_name,omitempty" cty:"autoscaling_group_name"`
}
func (_ *ExternalLoadBalancerAttachment) RenderTerraform(t *terraform.TerraformTarget, a, e, changes *ExternalLoadBalancerAttachment) error {
tf := &terraformExternalLoadBalancerAttachment{
ELB: terraform.LiteralFromStringValue(e.LoadBalancerName),
AutoscalingGroup: e.AutoscalingGroup.TerraformLink(),
}
return t.RenderResource("aws_autoscaling_attachment", *e.Name, tf)
}
func (e *ExternalLoadBalancerAttachment) TerraformLink() *terraform.Literal {
return terraform.LiteralProperty("aws_autoscaling_attachment", e.LoadBalancerName, "id")
}
func (_ *ExternalLoadBalancerAttachment) RenderCloudformation(t *cloudformation.CloudformationTarget, a, e, changes *ExternalLoadBalancerAttachment) error {
cfObj, ok := t.Find(e.AutoscalingGroup.CloudformationLink())
if !ok {
// topo-sort fail?
return fmt.Errorf("AutoScalingGroup not yet rendered")
}
cf, ok := cfObj.(*cloudformationAutoscalingGroup)
if !ok {
return fmt.Errorf("unexpected type for CF record: %T", cfObj)
}
cf.LoadBalancerNames = append(cf.LoadBalancerNames, cloudformation.LiteralString(e.LoadBalancerName))
return nil
}

View File

@ -1,146 +0,0 @@
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package awstasks
import (
"fmt"
"regexp"
"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"
)
// +kops:fitask
type ExternalTargetGroupAttachment struct {
Name *string
Lifecycle *fi.Lifecycle
TargetGroupARN string
AutoscalingGroup *AutoscalingGroup
}
func (e *ExternalTargetGroupAttachment) name() string {
re := regexp.MustCompile("arn:.*:targetgroup/")
return re.ReplaceAllString(*e.Name, "")
}
func (e *ExternalTargetGroupAttachment) Find(c *fi.Context) (*ExternalTargetGroupAttachment, error) {
cloud := c.Cloud.(awsup.AWSCloud)
if e.TargetGroupARN == "" {
return nil, fmt.Errorf("InstanceGroup did not have TargetGroupARNs set")
}
g, err := findAutoscalingGroup(cloud, *e.AutoscalingGroup.Name)
if err != nil {
return nil, err
}
if g == nil {
return nil, nil
}
for _, name := range g.TargetGroupARNs {
if aws.StringValue(name) != e.TargetGroupARN {
continue
}
actual := &ExternalTargetGroupAttachment{}
actual.TargetGroupARN = e.TargetGroupARN
actual.AutoscalingGroup = e.AutoscalingGroup
// Prevent spurious changes
actual.Name = e.Name // ELB attachments don't have tags
actual.Lifecycle = e.Lifecycle
return actual, nil
}
return nil, nil
}
func (e *ExternalTargetGroupAttachment) Run(c *fi.Context) error {
return fi.DefaultDeltaRunMethod(e, c)
}
func (s *ExternalTargetGroupAttachment) CheckChanges(a, e, changes *ExternalTargetGroupAttachment) error {
if a == nil {
if e.TargetGroupARN == "" {
return fi.RequiredField("TargetGroupARN")
}
if e.AutoscalingGroup == nil {
return fi.RequiredField("AutoscalingGroup")
}
}
return nil
}
func (_ *ExternalTargetGroupAttachment) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *ExternalTargetGroupAttachment) error {
if e.TargetGroupARN == "" {
return fi.RequiredField("TargetGroupARN")
}
request := &autoscaling.AttachLoadBalancerTargetGroupsInput{}
request.AutoScalingGroupName = e.AutoscalingGroup.Name
request.TargetGroupARNs = aws.StringSlice([]string{e.TargetGroupARN})
klog.V(2).Infof("Attaching autoscaling group %q to Target Group %q", fi.StringValue(e.AutoscalingGroup.Name), e.TargetGroupARN)
_, err := t.Cloud.Autoscaling().AttachLoadBalancerTargetGroups(request)
if err != nil {
return fmt.Errorf("error attaching autoscaling group to ELB: %v", err)
}
return nil
}
type terraformExternalTargetGroupAttachment struct {
TargetGroupARN *terraform.Literal `json:"alb_target_group_arn,omitempty" cty:"alb_target_group_arn"`
AutoscalingGroup *terraform.Literal `json:"autoscaling_group_name,omitempty" cty:"autoscaling_group_name"`
}
func (_ *ExternalTargetGroupAttachment) RenderTerraform(t *terraform.TerraformTarget, a, e, changes *ExternalTargetGroupAttachment) error {
tf := &terraformExternalTargetGroupAttachment{
TargetGroupARN: terraform.LiteralFromStringValue(e.TargetGroupARN),
AutoscalingGroup: e.AutoscalingGroup.TerraformLink(),
}
return t.RenderResource("aws_autoscaling_attachment", e.name(), tf)
}
func (e *ExternalTargetGroupAttachment) TerraformLink() *terraform.Literal {
return terraform.LiteralProperty("aws_autoscaling_attachment", e.name(), "id")
}
func (_ *ExternalTargetGroupAttachment) RenderCloudformation(t *cloudformation.CloudformationTarget, a, e, changes *ExternalTargetGroupAttachment) error {
cfObj, ok := t.Find(e.AutoscalingGroup.CloudformationLink())
if !ok {
// topo-sort fail?
return fmt.Errorf("AutoScalingGroup not yet rendered")
}
cf, ok := cfObj.(*cloudformationAutoscalingGroup)
if !ok {
return fmt.Errorf("unexpected type for CF record: %T", cfObj)
}
cf.TargetGroupARNs = append(cf.TargetGroupARNs, cloudformation.LiteralString(e.TargetGroupARN))
return nil
}

View File

@ -1,51 +0,0 @@
// +build !ignore_autogenerated
/*
Copyright 2020 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by fitask. DO NOT EDIT.
package awstasks
import (
"k8s.io/kops/upup/pkg/fi"
)
// ExternalLoadBalancerAttachment
var _ fi.HasLifecycle = &ExternalLoadBalancerAttachment{}
// GetLifecycle returns the Lifecycle of the object, implementing fi.HasLifecycle
func (o *ExternalLoadBalancerAttachment) GetLifecycle() *fi.Lifecycle {
return o.Lifecycle
}
// SetLifecycle sets the Lifecycle of the object, implementing fi.SetLifecycle
func (o *ExternalLoadBalancerAttachment) SetLifecycle(lifecycle fi.Lifecycle) {
o.Lifecycle = &lifecycle
}
var _ fi.HasName = &ExternalLoadBalancerAttachment{}
// GetName returns the Name of the object, implementing fi.HasName
func (o *ExternalLoadBalancerAttachment) GetName() *string {
return o.Name
}
// String is the stringer function for the task, producing readable output using fi.TaskAsString
func (o *ExternalLoadBalancerAttachment) String() string {
return fi.TaskAsString(o)
}

View File

@ -1,51 +0,0 @@
// +build !ignore_autogenerated
/*
Copyright 2020 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by fitask. DO NOT EDIT.
package awstasks
import (
"k8s.io/kops/upup/pkg/fi"
)
// ExternalTargetGroupAttachment
var _ fi.HasLifecycle = &ExternalTargetGroupAttachment{}
// GetLifecycle returns the Lifecycle of the object, implementing fi.HasLifecycle
func (o *ExternalTargetGroupAttachment) GetLifecycle() *fi.Lifecycle {
return o.Lifecycle
}
// SetLifecycle sets the Lifecycle of the object, implementing fi.SetLifecycle
func (o *ExternalTargetGroupAttachment) SetLifecycle(lifecycle fi.Lifecycle) {
o.Lifecycle = &lifecycle
}
var _ fi.HasName = &ExternalTargetGroupAttachment{}
// GetName returns the Name of the object, implementing fi.HasName
func (o *ExternalTargetGroupAttachment) GetName() *string {
return o.Name
}
// String is the stringer function for the task, producing readable output using fi.TaskAsString
func (o *ExternalTargetGroupAttachment) String() string {
return fi.TaskAsString(o)
}

View File

@ -67,6 +67,9 @@ type LoadBalancer struct {
Tags map[string]string
ForAPIServer bool
// Shared is set if this is an external LB (one we don't create or own)
Shared *bool
}
var _ fi.CompareWithID = &LoadBalancer{}
@ -438,6 +441,13 @@ func (e *LoadBalancer) Run(c *fi.Context) error {
return fi.DefaultDeltaRunMethod(e, c)
}
func (_ *LoadBalancer) ShouldCreate(a, e, changes *LoadBalancer) (bool, error) {
if fi.BoolValue(e.Shared) {
return false, nil
}
return true, nil
}
func (e *LoadBalancer) Normalize() {
// We need to sort our arrays consistently, so we don't get spurious changes
sort.Stable(OrderSubnetsById(e.Subnets))
@ -449,11 +459,15 @@ func (s *LoadBalancer) CheckChanges(a, e, changes *LoadBalancer) error {
if fi.StringValue(e.Name) == "" {
return fi.RequiredField("Name")
}
if len(e.SecurityGroups) == 0 {
return fi.RequiredField("SecurityGroups")
}
if len(e.Subnets) == 0 {
return fi.RequiredField("Subnets")
shared := fi.BoolValue(e.Shared)
if !shared {
if len(e.SecurityGroups) == 0 {
return fi.RequiredField("SecurityGroups")
}
if len(e.Subnets) == 0 {
return fi.RequiredField("Subnets")
}
}
if e.AccessLog != nil {
@ -483,6 +497,11 @@ func (s *LoadBalancer) CheckChanges(a, e, changes *LoadBalancer) error {
}
func (_ *LoadBalancer) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *LoadBalancer) error {
shared := fi.BoolValue(e.Shared)
if shared {
return nil
}
var loadBalancerName string
if a == nil {
if e.LoadBalancerName == nil {
@ -692,6 +711,11 @@ type terraformLoadBalancerHealthCheck struct {
}
func (_ *LoadBalancer) RenderTerraform(t *terraform.TerraformTarget, a, e, changes *LoadBalancer) error {
shared := fi.BoolValue(e.Shared)
if shared {
return nil
}
cloud := t.Cloud.(awsup.AWSCloud)
if e.LoadBalancerName == nil {
@ -782,6 +806,16 @@ func (_ *LoadBalancer) RenderTerraform(t *terraform.TerraformTarget, a, e, chang
}
func (e *LoadBalancer) TerraformLink(params ...string) *terraform.Literal {
shared := fi.BoolValue(e.Shared)
if shared {
if e.Name == nil {
klog.Fatalf("Name must be set, if LB is shared: %s", e)
}
klog.V(4).Infof("reusing existing LB with name %q", *e.Name)
return terraform.LiteralFromStringValue(*e.Name)
}
prop := "id"
if len(params) > 0 {
prop = params[0]
@ -836,6 +870,11 @@ func (_ *LoadBalancer) RenderCloudformation(t *cloudformation.CloudformationTarg
// If this resource has a public IP address and is also in a VPC that is defined in the same template,
// you must use the DependsOn attribute to declare a dependency on the VPC-gateway attachment.
shared := fi.BoolValue(e.Shared)
if shared {
return nil
}
cloud := t.Cloud.(awsup.AWSCloud)
if e.LoadBalancerName == nil {
@ -912,6 +951,16 @@ func (_ *LoadBalancer) RenderCloudformation(t *cloudformation.CloudformationTarg
}
func (e *LoadBalancer) CloudformationLink() *cloudformation.Literal {
shared := fi.BoolValue(e.Shared)
if shared {
if e.Name == nil {
klog.Fatalf("Name must be set, if LB is shared: %s", e)
}
klog.V(4).Infof("reusing existing LB with name %q", *e.Name)
return cloudformation.LiteralString(*e.Name)
}
return cloudformation.Ref("AWS::ElasticLoadBalancing::LoadBalancer", *e.Name)
}

View File

@ -1,196 +0,0 @@
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package awstasks
import (
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/autoscaling"
"github.com/aws/aws-sdk-go/service/elb"
"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"
)
// +kops:fitask
type LoadBalancerAttachment struct {
Name *string
Lifecycle *fi.Lifecycle
LoadBalancer *LoadBalancer
// LoadBalancerAttachments now support ASGs or direct instances
AutoscalingGroup *AutoscalingGroup
Subnet *Subnet
// Here be dragons..
// This will *NOT* unmarshal.. for some reason this pointer is initiated as nil
// instead of a pointer to Instance with nil members..
Instance *Instance
}
func (e *LoadBalancerAttachment) Find(c *fi.Context) (*LoadBalancerAttachment, error) {
cloud := c.Cloud.(awsup.AWSCloud)
// Instance only
if e.Instance != nil && e.AutoscalingGroup == nil {
i, err := e.Instance.Find(c)
if err != nil {
return nil, fmt.Errorf("unable to find instance: %v", err)
}
actual := &LoadBalancerAttachment{}
actual.LoadBalancer = e.LoadBalancer
actual.Instance = i
return actual, nil
// ASG only
} else if e.AutoscalingGroup != nil && e.Instance == nil {
if aws.StringValue(e.LoadBalancer.LoadBalancerName) == "" {
return nil, fmt.Errorf("LoadBalancer did not have LoadBalancerName set")
}
g, err := findAutoscalingGroup(cloud, *e.AutoscalingGroup.Name)
if err != nil {
return nil, err
}
if g == nil {
return nil, nil
}
for _, name := range g.LoadBalancerNames {
if aws.StringValue(name) != *e.LoadBalancer.LoadBalancerName {
continue
}
actual := &LoadBalancerAttachment{}
actual.LoadBalancer = e.LoadBalancer
actual.AutoscalingGroup = e.AutoscalingGroup
// Prevent spurious changes
actual.Name = e.Name // ELB attachments don't have tags
actual.Lifecycle = e.Lifecycle
return actual, nil
}
} else {
// Invalid request
return nil, fmt.Errorf("Must specify either an instance or an ASG")
}
return nil, nil
}
func (e *LoadBalancerAttachment) Run(c *fi.Context) error {
return fi.DefaultDeltaRunMethod(e, c)
}
func (s *LoadBalancerAttachment) CheckChanges(a, e, changes *LoadBalancerAttachment) error {
if a == nil {
if e.LoadBalancer == nil {
return fi.RequiredField("LoadBalancer")
}
if e.AutoscalingGroup == nil {
return fi.RequiredField("AutoscalingGroup")
}
}
return nil
}
func (_ *LoadBalancerAttachment) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *LoadBalancerAttachment) error {
if e.LoadBalancer == nil {
return fi.RequiredField("LoadBalancer")
}
loadBalancerName := fi.StringValue(e.LoadBalancer.LoadBalancerName)
if loadBalancerName == "" {
return fi.RequiredField("LoadBalancer.LoadBalancerName")
}
if e.AutoscalingGroup != nil && e.Instance == nil {
request := &autoscaling.AttachLoadBalancersInput{}
request.AutoScalingGroupName = e.AutoscalingGroup.Name
request.LoadBalancerNames = aws.StringSlice([]string{loadBalancerName})
klog.V(2).Infof("Attaching autoscaling group %q to ELB %q", fi.StringValue(e.AutoscalingGroup.Name), loadBalancerName)
_, err := t.Cloud.Autoscaling().AttachLoadBalancers(request)
if err != nil {
return fmt.Errorf("error attaching autoscaling group to ELB: %v", err)
}
} else if e.AutoscalingGroup == nil && e.Instance != nil {
request := &elb.RegisterInstancesWithLoadBalancerInput{}
request.Instances = append(request.Instances, &elb.Instance{InstanceId: e.Instance.ID})
request.LoadBalancerName = aws.String(loadBalancerName)
klog.V(2).Infof("Attaching instance %q to ELB %q", fi.StringValue(e.Instance.ID), loadBalancerName)
_, err := t.Cloud.ELB().RegisterInstancesWithLoadBalancer(request)
if err != nil {
return fmt.Errorf("error attaching instance to ELB: %v", err)
}
}
return nil
}
type terraformLoadBalancerAttachment struct {
ELB *terraform.Literal `json:"elb" cty:"elb"`
Instance *terraform.Literal `json:"instance,omitempty" cty:"instance"`
AutoscalingGroup *terraform.Literal `json:"autoscaling_group_name,omitempty" cty:"autoscaling_group_name"`
}
func (_ *LoadBalancerAttachment) RenderTerraform(t *terraform.TerraformTarget, a, e, changes *LoadBalancerAttachment) error {
tf := &terraformLoadBalancerAttachment{
ELB: e.LoadBalancer.TerraformLink(),
}
if e.AutoscalingGroup != nil && e.Instance == nil {
tf.AutoscalingGroup = e.AutoscalingGroup.TerraformLink()
return t.RenderResource("aws_autoscaling_attachment", *e.AutoscalingGroup.Name, tf)
} else if e.AutoscalingGroup == nil && e.Instance != nil {
tf.Instance = e.Instance.TerraformLink()
return t.RenderResource("aws_elb_attachment", *e.LoadBalancer.Name, tf)
}
return nil
}
func (e *LoadBalancerAttachment) TerraformLink() *terraform.Literal {
if e.AutoscalingGroup != nil && e.Instance == nil {
return terraform.LiteralProperty("aws_autoscaling_attachment", *e.AutoscalingGroup.Name, "id")
} else if e.AutoscalingGroup == nil && e.Instance != nil {
return terraform.LiteralProperty("aws_elb_attachment", *e.LoadBalancer.Name, "id")
}
return nil
}
func (_ *LoadBalancerAttachment) RenderCloudformation(t *cloudformation.CloudformationTarget, a, e, changes *LoadBalancerAttachment) error {
if e.AutoscalingGroup != nil {
cfObj, ok := t.Find(e.AutoscalingGroup.CloudformationLink())
if !ok {
// topo-sort fail?
return fmt.Errorf("AutoScalingGroup not yet rendered")
}
cf, ok := cfObj.(*cloudformationAutoscalingGroup)
if !ok {
return fmt.Errorf("unexpected type for CF record: %T", cfObj)
}
cf.LoadBalancerNames = append(cf.LoadBalancerNames, e.LoadBalancer.CloudformationLink())
}
if e.Instance != nil {
return fmt.Errorf("expected Instance to be nil")
}
return nil
}

View File

@ -0,0 +1,136 @@
/*
Copyright 2020 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package awstasks
import (
"fmt"
"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"
)
// TargetGroup manages an targetgroup used for an ALB/NLB.
// +kops:fitask
type TargetGroup struct {
Name *string
Lifecycle *fi.Lifecycle
// ARN is the Amazon Resource Name for the Target Group
ARN *string
// Shared is set if this is an external LB (one we don't create or own)
Shared *bool
}
var _ fi.CompareWithID = &TargetGroup{}
func (e *TargetGroup) CompareWithID() *string {
return e.ARN
}
func (e *TargetGroup) Find(c *fi.Context) (*TargetGroup, error) {
if e.ARN == nil {
return nil, fmt.Errorf("ARN must be set for TargetGroup")
}
actual := &TargetGroup{}
actual.ARN = e.ARN
// Prevent spurious changes
actual.Name = e.Name
actual.Lifecycle = e.Lifecycle
return actual, nil
}
func (e *TargetGroup) Run(c *fi.Context) error {
return fi.DefaultDeltaRunMethod(e, c)
}
func (_ *TargetGroup) ShouldCreate(a, e, changes *TargetGroup) (bool, error) {
if fi.BoolValue(e.Shared) {
return false, nil
}
return true, nil
}
func (s *TargetGroup) CheckChanges(a, e, changes *TargetGroup) error {
if a == nil {
if e.ARN == nil {
return fi.RequiredField("ARN")
}
}
return nil
}
func (_ *TargetGroup) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *TargetGroup) error {
shared := fi.BoolValue(e.Shared)
if shared {
return nil
}
return fmt.Errorf("non shared Target Groups is not yet supported")
}
func (_ *TargetGroup) RenderTerraform(t *terraform.TerraformTarget, a, e, changes *TargetGroup) error {
shared := fi.BoolValue(e.Shared)
if shared {
return nil
}
return fmt.Errorf("non shared Target Groups is not yet supported")
}
func (e *TargetGroup) TerraformLink(params ...string) *terraform.Literal {
shared := fi.BoolValue(e.Shared)
if shared {
if e.ARN == nil {
klog.Fatalf("ARN must be set for shared Target Group: %s", e)
}
klog.V(4).Infof("reusing existing Target Group with ARN %q", *e.ARN)
return terraform.LiteralFromStringValue(*e.ARN)
}
return nil
}
func (_ *TargetGroup) RenderCloudformation(t *cloudformation.CloudformationTarget, a, e, changes *TargetGroup) error {
shared := fi.BoolValue(e.Shared)
if shared {
return nil
}
return fmt.Errorf("non shared Target Groups is not yet supported")
}
func (e *TargetGroup) CloudformationLink() *cloudformation.Literal {
shared := fi.BoolValue(e.Shared)
if shared {
if e.ARN == nil {
klog.Fatalf("ARN must be set for shared Target Group: %s", e)
}
klog.V(4).Infof("reusing existing Target Group with ARN %q", *e.ARN)
return cloudformation.LiteralString(*e.ARN)
}
return nil
}

View File

@ -24,28 +24,28 @@ import (
"k8s.io/kops/upup/pkg/fi"
)
// LoadBalancerAttachment
// TargetGroup
var _ fi.HasLifecycle = &LoadBalancerAttachment{}
var _ fi.HasLifecycle = &TargetGroup{}
// GetLifecycle returns the Lifecycle of the object, implementing fi.HasLifecycle
func (o *LoadBalancerAttachment) GetLifecycle() *fi.Lifecycle {
func (o *TargetGroup) GetLifecycle() *fi.Lifecycle {
return o.Lifecycle
}
// SetLifecycle sets the Lifecycle of the object, implementing fi.SetLifecycle
func (o *LoadBalancerAttachment) SetLifecycle(lifecycle fi.Lifecycle) {
func (o *TargetGroup) SetLifecycle(lifecycle fi.Lifecycle) {
o.Lifecycle = &lifecycle
}
var _ fi.HasName = &LoadBalancerAttachment{}
var _ fi.HasName = &TargetGroup{}
// GetName returns the Name of the object, implementing fi.HasName
func (o *LoadBalancerAttachment) GetName() *string {
func (o *TargetGroup) GetName() *string {
return o.Name
}
// String is the stringer function for the task, producing readable output using fi.TaskAsString
func (o *LoadBalancerAttachment) String() string {
func (o *TargetGroup) String() string {
return fi.TaskAsString(o)
}