sigs.k8s.io/cluster-api-provider-aws@v1.5.5/cmd/clusterawsadm/gc/gc.go (about) 1 /* 2 Copyright 2022 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package gc 18 19 import ( 20 "context" 21 "fmt" 22 23 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 24 "k8s.io/apimachinery/pkg/runtime" 25 _ "k8s.io/client-go/plugin/pkg/client/auth/exec" 26 _ "k8s.io/client-go/plugin/pkg/client/auth/oidc" 27 "k8s.io/client-go/tools/clientcmd" 28 "sigs.k8s.io/controller-runtime/pkg/client" 29 30 infrav1 "sigs.k8s.io/cluster-api-provider-aws/api/v1beta1" 31 ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/controlplane/eks/api/v1beta1" 32 expinfrav1 "sigs.k8s.io/cluster-api-provider-aws/exp/api/v1beta1" 33 "sigs.k8s.io/cluster-api-provider-aws/pkg/annotations" 34 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 35 "sigs.k8s.io/cluster-api/controllers/external" 36 "sigs.k8s.io/cluster-api/util/patch" 37 ) 38 39 var ( 40 scheme = runtime.NewScheme() 41 ) 42 43 func init() { 44 _ = clusterv1.AddToScheme(scheme) 45 _ = infrav1.AddToScheme(scheme) 46 _ = ekscontrolplanev1.AddToScheme(scheme) 47 } 48 49 // CmdProcessor handles the garbage collection commands. 50 type CmdProcessor struct { 51 client client.Client 52 53 clusterName string 54 namespace string 55 } 56 57 // GCInput holds the configuration for the command processor. 58 type GCInput struct { 59 ClusterName string 60 Namespace string 61 KubeconfigPath string 62 } 63 64 // CmdProcessorOption is a function type to supply options when creating the command processor. 65 type CmdProcessorOption func(proc *CmdProcessor) error 66 67 // WithClient is an option that enable you to explicitly supply a client. 68 func WithClient(client client.Client) CmdProcessorOption { 69 return func(proc *CmdProcessor) error { 70 proc.client = client 71 72 return nil 73 } 74 } 75 76 // New creates a new instance of the command processor. 77 func New(input GCInput, opts ...CmdProcessorOption) (*CmdProcessor, error) { 78 cmd := &CmdProcessor{ 79 clusterName: input.ClusterName, 80 namespace: input.Namespace, 81 } 82 83 for _, opt := range opts { 84 if err := opt(cmd); err != nil { 85 return nil, fmt.Errorf("applying option: %w", err) 86 } 87 } 88 89 if cmd.client == nil { 90 config, err := clientcmd.BuildConfigFromFlags("", input.KubeconfigPath) 91 if err != nil { 92 return nil, fmt.Errorf("building client config: %w", err) 93 } 94 95 cl, err := client.New(config, client.Options{Scheme: scheme}) 96 if err != nil { 97 return nil, fmt.Errorf("creating new client: %w", err) 98 } 99 100 cmd.client = cl 101 } 102 103 return cmd, nil 104 } 105 106 // Enable is used to enable external resource garbage collection for a cluster. 107 func (c *CmdProcessor) Enable(ctx context.Context) error { 108 if err := c.setAnnotationAndPatch(ctx, "true"); err != nil { 109 return fmt.Errorf("setting gc annotation to true: %w", err) 110 } 111 112 return nil 113 } 114 115 // Disable is used to disable external resource garbage collection for a cluster. 116 func (c *CmdProcessor) Disable(ctx context.Context) error { 117 if err := c.setAnnotationAndPatch(ctx, "false"); err != nil { 118 return fmt.Errorf("setting gc annotation to false: %w", err) 119 } 120 121 return nil 122 } 123 124 func (c *CmdProcessor) setAnnotationAndPatch(ctx context.Context, annotationValue string) error { 125 infraObj, err := c.getInfraCluster(ctx) 126 if err != nil { 127 return err 128 } 129 130 patchHelper, err := patch.NewHelper(infraObj, c.client) 131 if err != nil { 132 return fmt.Errorf("creating patch helper: %w", err) 133 } 134 135 annotations.Set(infraObj, expinfrav1.ExternalResourceGCAnnotation, annotationValue) 136 137 if err := patchHelper.Patch(ctx, infraObj); err != nil { 138 return fmt.Errorf("patching infra cluster with gc annotation: %w", err) 139 } 140 141 return nil 142 } 143 144 func (c *CmdProcessor) getInfraCluster(ctx context.Context) (*unstructured.Unstructured, error) { 145 cluster := &clusterv1.Cluster{} 146 147 key := client.ObjectKey{ 148 Name: c.clusterName, 149 Namespace: c.namespace, 150 } 151 152 if err := c.client.Get(ctx, key, cluster); err != nil { 153 return nil, fmt.Errorf("getting capi cluster %s/%s: %w", c.namespace, c.clusterName, err) 154 } 155 156 ref := cluster.Spec.InfrastructureRef 157 obj, err := external.Get(ctx, c.client, ref, cluster.Namespace) 158 if err != nil { 159 return nil, fmt.Errorf("getting infra cluster %s/%s: %w", ref.Namespace, ref.Name, err) 160 } 161 162 return obj, nil 163 }