diff --git a/docs/releases/1.19-NOTES.md b/docs/releases/1.19-NOTES.md index a69e972c2c03d..d16151254bb3a 100644 --- a/docs/releases/1.19-NOTES.md +++ b/docs/releases/1.19-NOTES.md @@ -4,6 +4,8 @@ # Significant changes +**Terraform users on AWS should read the [_Required Actions_](#required-actions) section below to avoid potential etcd data loss.** + ## Changes to kubernetes config export kOps will no longer automatically export the kubernetes config on `kops update cluster`. In order to export the config on cluster update, you need to either add the `--user ` to reference an existing user, or `--admin` to export the cluster admin user. If neither flag is passed, the kubernetes config will not be modified. This makes it easier to reuse user definitions across clusters should you, for example, use OIDC for authentication. @@ -101,6 +103,19 @@ has been updated by a newer version of kOps unless it is given the `--allow-kops terraform apply ``` +* Terraform users on AWS may need to rename their EBS Volume resources to match 0.12's stricter naming requirements. Volumes whose Terraform resource name begin with a digit are now prefixed with `ebs-`. This change will be made regardless of `Terraform-0.12` feature flag value. More information is available in [#9982](https://github.com/kubernetes/kops/issues/9982). + When upgrading to kOps 1.19, follow these steps to determine if a rename is necessary: + ```bash + kops update cluster --target terraform ... + terraform plan + # Look for any EBS volumes being recreated + # Adjust these arguments as necessary + terraform state mv aws_ebs_volume.1a-etcd-events-foo-k8s-local aws_ebs_volume.ebs-1a-etcd-events-foo-k8s-local + terraform plan + # Confirm no EBS volumes being changed + 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). * AWS clusters using an ACM Certificate on the API ELB (`.spec.api.loadBalancer.sslCertificateID`) will need to migrate from Classic LoadBalancer (CLB) to Network LoadBalancer (NLB) prior to upgrading to Kubernetes 1.19 by setting `.spec.api.loadBalancer.class: Network`. diff --git a/tests/integration/update_cluster/complex/cloudformation.json b/tests/integration/update_cluster/complex/cloudformation.json index 1401f6b4b364d..9eb440084a947 100644 --- a/tests/integration/update_cluster/complex/cloudformation.json +++ b/tests/integration/update_cluster/complex/cloudformation.json @@ -1105,7 +1105,7 @@ ] } }, - "AWSEC2Volumeustest1aetcdeventscomplexexamplecom": { + "AWSEC2Volume1aetcdeventscomplexexamplecom": { "Type": "AWS::EC2::Volume", "Properties": { "AvailabilityZone": "us-test-1a", @@ -1119,7 +1119,7 @@ }, { "Key": "Name", - "Value": "us-test-1a.etcd-events.complex.example.com" + "Value": "1a.etcd-events.complex.example.com" }, { "Key": "Owner", @@ -1131,7 +1131,7 @@ }, { "Key": "k8s.io/etcd/events", - "Value": "us-test-1a/us-test-1a" + "Value": "1a/1a" }, { "Key": "k8s.io/role/master", @@ -1144,7 +1144,7 @@ ] } }, - "AWSEC2Volumeustest1aetcdmaincomplexexamplecom": { + "AWSEC2Volume1aetcdmaincomplexexamplecom": { "Type": "AWS::EC2::Volume", "Properties": { "AvailabilityZone": "us-test-1a", @@ -1158,7 +1158,7 @@ }, { "Key": "Name", - "Value": "us-test-1a.etcd-main.complex.example.com" + "Value": "1a.etcd-main.complex.example.com" }, { "Key": "Owner", @@ -1170,7 +1170,7 @@ }, { "Key": "k8s.io/etcd/main", - "Value": "us-test-1a/us-test-1a" + "Value": "1a/1a" }, { "Key": "k8s.io/role/master", diff --git a/tests/integration/update_cluster/complex/in-legacy-v1alpha2.yaml b/tests/integration/update_cluster/complex/in-legacy-v1alpha2.yaml index b8e55435f774c..e38b42dc243d6 100644 --- a/tests/integration/update_cluster/complex/in-legacy-v1alpha2.yaml +++ b/tests/integration/update_cluster/complex/in-legacy-v1alpha2.yaml @@ -26,11 +26,11 @@ spec: etcdClusters: - etcdMembers: - instanceGroup: master-us-test-1a - name: us-test-1a + name: 1a name: main - etcdMembers: - instanceGroup: master-us-test-1a - name: us-test-1a + name: 1a name: events iam: permissionsBoundary: arn:aws:iam:00000000000:policy/boundaries diff --git a/tests/integration/update_cluster/complex/in-v1alpha2.yaml b/tests/integration/update_cluster/complex/in-v1alpha2.yaml index e974f16b7d9b1..daa6fe6bbb5dc 100644 --- a/tests/integration/update_cluster/complex/in-v1alpha2.yaml +++ b/tests/integration/update_cluster/complex/in-v1alpha2.yaml @@ -26,11 +26,11 @@ spec: etcdClusters: - etcdMembers: - instanceGroup: master-us-test-1a - name: us-test-1a + name: 1a name: main - etcdMembers: - instanceGroup: master-us-test-1a - name: us-test-1a + name: 1a name: events iam: permissionsBoundary: arn:aws:iam:00000000000:policy/boundaries diff --git a/tests/integration/update_cluster/complex/kubernetes.tf b/tests/integration/update_cluster/complex/kubernetes.tf index b4aa505339284..1645ff50b9447 100644 --- a/tests/integration/update_cluster/complex/kubernetes.tf +++ b/tests/integration/update_cluster/complex/kubernetes.tf @@ -198,32 +198,32 @@ resource "aws_autoscaling_group" "nodes-complex-example-com" { vpc_zone_identifier = [aws_subnet.us-test-1a-complex-example-com.id] } -resource "aws_ebs_volume" "us-test-1a-etcd-events-complex-example-com" { +resource "aws_ebs_volume" "ebs-1a-etcd-events-complex-example-com" { availability_zone = "us-test-1a" encrypted = false size = 20 tags = { "KubernetesCluster" = "complex.example.com" - "Name" = "us-test-1a.etcd-events.complex.example.com" + "Name" = "1a.etcd-events.complex.example.com" "Owner" = "John Doe" "foo/bar" = "fib+baz" - "k8s.io/etcd/events" = "us-test-1a/us-test-1a" + "k8s.io/etcd/events" = "1a/1a" "k8s.io/role/master" = "1" "kubernetes.io/cluster/complex.example.com" = "owned" } type = "gp2" } -resource "aws_ebs_volume" "us-test-1a-etcd-main-complex-example-com" { +resource "aws_ebs_volume" "ebs-1a-etcd-main-complex-example-com" { availability_zone = "us-test-1a" encrypted = false size = 20 tags = { "KubernetesCluster" = "complex.example.com" - "Name" = "us-test-1a.etcd-main.complex.example.com" + "Name" = "1a.etcd-main.complex.example.com" "Owner" = "John Doe" "foo/bar" = "fib+baz" - "k8s.io/etcd/main" = "us-test-1a/us-test-1a" + "k8s.io/etcd/main" = "1a/1a" "k8s.io/role/master" = "1" "kubernetes.io/cluster/complex.example.com" = "owned" } diff --git a/upup/pkg/fi/cloudup/awstasks/ebsvolume.go b/upup/pkg/fi/cloudup/awstasks/ebsvolume.go index bddcd6bc5313e..d24e503e5f6d4 100644 --- a/upup/pkg/fi/cloudup/awstasks/ebsvolume.go +++ b/upup/pkg/fi/cloudup/awstasks/ebsvolume.go @@ -204,11 +204,18 @@ func (_ *EBSVolume) RenderTerraform(t *terraform.TerraformTarget, a, e, changes Tags: e.Tags, } - return t.RenderResource("aws_ebs_volume", *e.Name, tf) + return t.RenderResource("aws_ebs_volume", e.TerraformName(), tf) } func (e *EBSVolume) TerraformLink() *terraform.Literal { - return terraform.LiteralSelfLink("aws_ebs_volume", *e.Name) + return terraform.LiteralSelfLink("aws_ebs_volume", e.TerraformName()) +} + +func (e *EBSVolume) TerraformName() string { + if (*e.Name)[0] >= '0' && (*e.Name)[0] <= '9' { + return fmt.Sprintf("ebs-%v", *e.Name) + } + return *e.Name } type cloudformationVolume struct {