-
Notifications
You must be signed in to change notification settings - Fork 692
refactor: separate CAPA resources from cluster #706
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 20 commits
8dbc19c
f23359a
0575559
f632c07
fce0651
8bcb655
79a24fb
f4532f5
d7f3d48
23c58cf
46e103d
d21ae49
d4808f4
0a1739c
96c19b6
49b6b90
e28b52a
631ea66
8a68b1d
8ad92e9
c10318d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| load("@io_bazel_rules_go//go:def.bzl", "go_library") | ||
|
|
||
| go_library( | ||
| name = "go_default_library", | ||
| srcs = ["migrate.go"], | ||
| importpath = "sigs.k8s.io/cluster-api-provider-aws/cmd/clusterawsadm/cmd/alpha/migrate", | ||
| visibility = ["//visibility:public"], | ||
| deps = [ | ||
| "//pkg/cloud/aws/tags:go_default_library", | ||
| "//vendor/github.com/aws/aws-sdk-go/aws:go_default_library", | ||
| "//vendor/github.com/aws/aws-sdk-go/aws/session:go_default_library", | ||
| "//vendor/github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi:go_default_library", | ||
| "//vendor/github.com/spf13/cobra:go_default_library", | ||
| ], | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,208 @@ | ||
| /* | ||
| Copyright 2018 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 migrate | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "os" | ||
| "strings" | ||
|
|
||
| "github.com/aws/aws-sdk-go/aws" | ||
| "github.com/aws/aws-sdk-go/aws/session" | ||
| awstags "github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi" | ||
| "github.com/spf13/cobra" | ||
| "sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/aws/tags" | ||
| ) | ||
|
|
||
| var ( | ||
| // See: https://docs.aws.amazon.com/sdk-for-go/api/service/resourcegroupstaggingapi/#TagResourcesInput | ||
| maxARNs = 20 | ||
| supportedVersions = []string{"0.3.0"} | ||
|
|
||
| clusterName string | ||
| ) | ||
|
|
||
| // MigrateCmd is the command for migrating AWS resources to be compatible | ||
| // with specific CAPA versions | ||
| func MigrateCmd() *cobra.Command { // nolint | ||
| newCmd := &cobra.Command{ | ||
| Use: "migrate [target version]", | ||
| Short: "migrate between CAPA versions", | ||
| Long: fmt.Sprintf(`Migrate AWS resources between incompatible versions of Cluster API Provider AWS. | ||
| Supported versions: %v`, supportedVersions), | ||
| Args: func(cmd *cobra.Command, args []string) error { | ||
| if len(args) != 1 { | ||
| fmt.Printf("Error: requires target version as an argument. Supported versions: %v\n\n", supportedVersions) | ||
| if err := cmd.Help(); err != nil { | ||
| return err | ||
| } | ||
| os.Exit(200) | ||
| } | ||
| if !isValidVersion(args[0]) { | ||
| fmt.Printf("Error: unsupported migration target. Supported versions: %v\n\n", supportedVersions) | ||
| cmd.Help() | ||
| os.Exit(201) | ||
| } | ||
| return nil | ||
| }, | ||
| RunE: func(cmd *cobra.Command, args []string) error { | ||
| sess, err := session.NewSessionWithOptions(session.Options{ | ||
| SharedConfigState: session.SharedConfigEnable, | ||
| }) | ||
| if err != nil { | ||
| fmt.Printf("Error: %v", err) | ||
| return nil | ||
| } | ||
|
|
||
| tagsSvc := awstags.New(sess) | ||
|
|
||
| resources, err := getResourcesByCluster(tagsSvc, clusterName) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| fmt.Printf("Found %v resources owned by cluster %q.\n", len(resources), clusterName) | ||
| fmt.Printf("Applying new tags to cluster %q.\n", clusterName) | ||
|
|
||
| err = applyNewTags(tagsSvc, resources, clusterName) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| fmt.Printf("Removing legacy tags from cluster %q\n", clusterName) | ||
|
|
||
| return removeOldTags(tagsSvc, resources, clusterName) | ||
| }, | ||
| } | ||
|
|
||
| newCmd.Flags().StringVarP(&clusterName, "clusterName", "n", "", "name of existing Cluster object") | ||
| newCmd.MarkFlagRequired("clusterName") | ||
|
|
||
| return newCmd | ||
| } | ||
|
|
||
| func getResourcesByCluster(svc *awstags.ResourceGroupsTaggingAPI, name string) ([]*string, error) { | ||
| input := &awstags.GetResourcesInput{ | ||
| TagFilters: []*awstags.TagFilter{ | ||
| { | ||
| Key: aws.String(fmt.Sprintf("kubernetes.io/cluster/%s", name)), | ||
| Values: []*string{aws.String("owned")}, | ||
| }, | ||
| { | ||
| Key: aws.String("sigs.k8s.io/cluster-api-provider-aws/managed"), | ||
| Values: []*string{aws.String("true")}, | ||
| }, | ||
| }, | ||
| } | ||
|
|
||
| out, err := svc.GetResources(input) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| arns := make([]*string, 0, len(out.ResourceTagMappingList)) | ||
| for _, resource := range out.ResourceTagMappingList { | ||
| arns = append(arns, resource.ResourceARN) | ||
| } | ||
|
|
||
| return arns, nil | ||
| } | ||
|
|
||
| func applyNewTags(svc *awstags.ResourceGroupsTaggingAPI, arns []*string, name string) error { | ||
|
|
||
| for i := 0; i <= (len(arns) / maxARNs); i++ { | ||
| end := (i + 1) * maxARNs | ||
| if end > len(arns) { | ||
| end = len(arns) | ||
| } | ||
|
|
||
| input := &awstags.TagResourcesInput{ | ||
| ResourceARNList: arns[i*maxARNs : end], | ||
| Tags: map[string]*string{ | ||
| tags.ClusterKey(name): aws.String("owned"), | ||
| }, | ||
| } | ||
|
|
||
| _, err := svc.TagResources(input) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| func removeOldTags(svc *awstags.ResourceGroupsTaggingAPI, arns []*string, name string) error { | ||
| for i := 0; i <= (len(arns) / maxARNs); i++ { | ||
| end := (i + 1) * maxARNs | ||
| if end > len(arns) { | ||
| end = len(arns) | ||
| } | ||
|
|
||
| managedInput := &awstags.UntagResourcesInput{ | ||
| ResourceARNList: arns[i*maxARNs : end], | ||
| TagKeys: []*string{ | ||
| aws.String("sigs.k8s.io/cluster-api-provider-aws/managed"), | ||
| }, | ||
| } | ||
|
|
||
| _, err := svc.UntagResources(managedInput) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| } | ||
|
|
||
| var filteredARNs []*string | ||
|
|
||
| for _, v := range arns { | ||
| // instances should have both ownership tags, so filter those out | ||
| // TODO(rudoi): is there a better way to filter? | ||
| if !strings.Contains(aws.StringValue(v), "instance") { | ||
| filteredARNs = append(filteredARNs, v) | ||
| } | ||
| } | ||
|
|
||
| for i := 0; i <= (len(filteredARNs) / maxARNs); i++ { | ||
| end := (i + 1) * maxARNs | ||
| if i == (len(filteredARNs) / maxARNs) { | ||
| end = len(filteredARNs) | ||
| } | ||
|
|
||
| ownedInput := &awstags.UntagResourcesInput{ | ||
| ResourceARNList: filteredARNs[i*maxARNs : end], | ||
| TagKeys: []*string{ | ||
| aws.String(fmt.Sprintf("kubernetes.io/cluster/%s", name)), | ||
| }, | ||
| } | ||
|
|
||
| _, err := svc.UntagResources(ownedInput) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| func isValidVersion(s string) bool { | ||
| for _, v := range supportedVersions { | ||
| if s == v { | ||
| return true | ||
| } | ||
| } | ||
| return false | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| # Upgrading to 0.3.0 | ||
|
|
||
| In 0.3.0, the tagging scheme changed for identifying AWS resources. In order not to lose track, there is a partial migration tool included in 0.3.0's `clusterawsadm`. | ||
|
|
||
| The migration path is as follows: | ||
|
|
||
| 1. `kubectl scale statefulset -n aws-provider-system aws-provider-controller-manager --replicas=0` | ||
| 2. `clusterawsadm migrate -n CLUSTER_NAME 0.3.0` | ||
| 3. Update the image for the aws-provider-controller-manager | ||
| 4. `kubectl scale statefulset -n aws-provider-system aws-provider-controller-manager --replicas=1` | ||
| 5. Wait ~2 minutes for the security group changes to all settle | ||
| - All of the nodes and control plane machines should have exactly one security group tagged with `kubernetes.io/cluster/<CLUSTER_NAME>=owned`: the new `CLUSTER_NAME-lb` group. | ||
| 6. Find the names of your controller-manager pods, and run `kubectl exec -n kube-system -it CONTROLLER_MANAGER_POD_NAME -- sh -c 'kill 1' as a workaround for kubernetes/kubernetes#77019` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,6 +23,7 @@ import ( | |
|
|
||
| corev1 "k8s.io/api/core/v1" | ||
| metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
| "sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/aws/tags" | ||
| ) | ||
|
|
||
| // AWSResourceReference is a reference to a specific AWS resource by ID, ARN, or filters. | ||
|
|
@@ -237,6 +238,9 @@ var ( | |
|
|
||
| // SecurityGroupControlPlane defines a Kubernetes control plane node role | ||
| SecurityGroupControlPlane = SecurityGroupRole("controlplane") | ||
|
|
||
| // SecurityGroupLB defines a container for the cloud provider to inject its load balancer ingress rules | ||
| SecurityGroupLB = SecurityGroupRole("lb") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggest creating package constants for
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I started down this path, but I think it's large enough and self-contained enough to make more sense as a separate PR |
||
| ) | ||
|
|
||
| // SecurityGroup defines an AWS security group. | ||
|
|
@@ -251,7 +255,7 @@ type SecurityGroup struct { | |
| IngressRules IngressRules `json:"ingressRule"` | ||
|
|
||
| // Tags is a map of tags associated with the security group. | ||
| Tags map[string]string `json:"tags,omitempty"` | ||
| Tags tags.Map `json:"tags,omitempty"` | ||
| } | ||
|
|
||
| // String returns a string representation of the security group. | ||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Uh oh!
There was an error while loading. Please reload this page.