Skip to content

Commit ca9dcd1

Browse files
authored
update: delete cluster cleans up Karpenter NodePools and EC2NodeClasses (#154)
1 parent 7d57128 commit ca9dcd1

File tree

4 files changed

+124
-6
lines changed

4 files changed

+124
-6
lines changed

go.mod

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ require (
4747
k8s.io/apimachinery v0.29.3
4848
k8s.io/cli-runtime v0.29.3
4949
k8s.io/client-go v0.29.3
50+
k8s.io/kubectl v0.29.3
5051
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3
5152
sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3
5253
sigs.k8s.io/yaml v1.3.0
@@ -97,6 +98,7 @@ require (
9798
github.com/fatih/color v1.13.0 // indirect
9899
github.com/felixge/httpsnoop v1.0.3 // indirect
99100
github.com/fsnotify/fsnotify v1.7.0 // indirect
101+
github.com/fvbommel/sortorder v1.1.0 // indirect
100102
github.com/go-errors/errors v1.4.2 // indirect
101103
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
102104
github.com/go-logr/logr v1.3.0 // indirect
@@ -197,10 +199,9 @@ require (
197199
gopkg.in/yaml.v3 v3.0.1 // indirect
198200
k8s.io/apiextensions-apiserver v0.29.0 // indirect
199201
k8s.io/apiserver v0.29.0 // indirect
200-
k8s.io/component-base v0.29.0 // indirect
202+
k8s.io/component-base v0.29.3 // indirect
201203
k8s.io/klog/v2 v2.110.1 // indirect
202204
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect
203-
k8s.io/kubectl v0.29.0 // indirect
204205
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
205206
oras.land/oras-go v1.2.4 // indirect
206207
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect

go.sum

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,8 @@ github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6
224224
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
225225
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
226226
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
227+
github.com/fvbommel/sortorder v1.1.0 h1:fUmoe+HLsBTctBDoaBwpQo5N+nrCp8g/BjKb/6ZQmYw=
228+
github.com/fvbommel/sortorder v1.1.0/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
227229
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
228230
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
229231
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
@@ -953,14 +955,14 @@ k8s.io/cli-runtime v0.29.3 h1:r68rephmmytoywkw2MyJ+CxjpasJDQY7AGc3XY2iv1k=
953955
k8s.io/cli-runtime v0.29.3/go.mod h1:aqVUsk86/RhaGJwDhHXH0jcdqBrgdF3bZWk4Z9D4mkM=
954956
k8s.io/client-go v0.29.3 h1:R/zaZbEAxqComZ9FHeQwOh3Y1ZUs7FaHKZdQtIc2WZg=
955957
k8s.io/client-go v0.29.3/go.mod h1:tkDisCvgPfiRpxGnOORfkljmS+UrW+WtXAy2fTvXJB0=
956-
k8s.io/component-base v0.29.0 h1:T7rjd5wvLnPBV1vC4zWd/iWRbV8Mdxs+nGaoaFzGw3s=
957-
k8s.io/component-base v0.29.0/go.mod h1:sADonFTQ9Zc9yFLghpDpmNXEdHyQmFIGbiuZbqAXQ1M=
958+
k8s.io/component-base v0.29.3 h1:Oq9/nddUxlnrCuuR2K/jp6aflVvc0uDvxMzAWxnGzAo=
959+
k8s.io/component-base v0.29.3/go.mod h1:Yuj33XXjuOk2BAaHsIGHhCKZQAgYKhqIxIjIr2UXYio=
958960
k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0=
959961
k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo=
960962
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780=
961963
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA=
962-
k8s.io/kubectl v0.29.0 h1:Oqi48gXjikDhrBF67AYuZRTcJV4lg2l42GmvsP7FmYI=
963-
k8s.io/kubectl v0.29.0/go.mod h1:0jMjGWIcMIQzmUaMgAzhSELv5WtHo2a8pq67DtviAJs=
964+
k8s.io/kubectl v0.29.3 h1:RuwyyIU42MAISRIePaa8Q7A3U74Q9P4MoJbDFz9o3us=
965+
k8s.io/kubectl v0.29.3/go.mod h1:yCxfY1dbwgVdEt2zkJ6d5NNLOhhWgTyrqACIoFhpdd4=
964966
k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI=
965967
k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
966968
oras.land/oras-go v1.2.4 h1:djpBY2/2Cs1PV87GSJlxv4voajVOMZxqqtq9AB8YNvY=
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
package karpenter
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os"
7+
"time"
8+
9+
"github.com/awslabs/eksdemo/pkg/kubernetes"
10+
api_errors "k8s.io/apimachinery/pkg/api/errors"
11+
"k8s.io/apimachinery/pkg/api/meta"
12+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13+
"k8s.io/apimachinery/pkg/runtime/schema"
14+
"k8s.io/cli-runtime/pkg/genericclioptions"
15+
"k8s.io/cli-runtime/pkg/genericiooptions"
16+
"k8s.io/cli-runtime/pkg/printers"
17+
"k8s.io/cli-runtime/pkg/resource"
18+
"k8s.io/client-go/dynamic"
19+
cmdwait "k8s.io/kubectl/pkg/cmd/wait"
20+
)
21+
22+
func DeleteCustomResources(kubeContext string) error {
23+
client, err := kubernetes.DynamicClient(kubeContext)
24+
if err != nil {
25+
return fmt.Errorf("failed creating kubernetes dynamic client: %w", err)
26+
}
27+
28+
if err := DeleteNodePool(client); err != nil {
29+
return err
30+
}
31+
32+
return DeleteEC2NodeClass(client, kubeContext)
33+
}
34+
35+
// This uses cli-runtime's Resource Builder and kubectl's waiter to simplify the delete and wait
36+
// Ideally this should use the Dynamic Client and a custom waiter
37+
func DeleteEC2NodeClass(client dynamic.Interface, kubeContext string) error {
38+
getter := genericclioptions.NewConfigFlags(true)
39+
getter.Context = &kubeContext
40+
41+
restMapper, err := getter.ToRESTMapper()
42+
if err != nil {
43+
return fmt.Errorf("failed creating restMapper: %w", err)
44+
}
45+
46+
gvk := "EC2NodeClass.v1beta1.karpenter.k8s.aws"
47+
fullySpecifiedGVK, _ := schema.ParseKindArg(gvk)
48+
49+
_, err = restMapper.RESTMapping(fullySpecifiedGVK.GroupKind(), fullySpecifiedGVK.Version)
50+
if err != nil {
51+
if meta.IsNoMatchError(err) {
52+
// EC2NodeClass kind doesn't exist, skip deletion
53+
return nil
54+
}
55+
return err
56+
}
57+
58+
infos, err := resource.NewBuilder(getter).Unstructured().ResourceTypes(gvk).SelectAllParam(true).Flatten().Do().Infos()
59+
if err != nil {
60+
return err
61+
}
62+
63+
for _, info := range infos {
64+
fmt.Printf("Deleting Karpenter EC2NodeClass %q\n", info.Name)
65+
66+
_, err := resource.NewHelper(info.Client, info.Mapping).Delete(info.Namespace, info.Name)
67+
if err != nil {
68+
return fmt.Errorf("failed to delete EC2NodeClass %q: %w", info.Name, err)
69+
}
70+
}
71+
72+
fmt.Println("Waiting up to 30 seconds for EC2NodeClasses to be deleted...")
73+
waitOptions := cmdwait.WaitOptions{
74+
ResourceFinder: genericclioptions.ResourceFinderForResult(resource.InfoListVisitor(infos)),
75+
DynamicClient: client,
76+
Timeout: 30 * time.Second,
77+
78+
Printer: &printers.NamePrinter{ShortOutput: false, Operation: "deleted"},
79+
ConditionFn: cmdwait.IsDeleted,
80+
IOStreams: genericiooptions.IOStreams{Out: os.Stdout, ErrOut: os.Stderr},
81+
}
82+
83+
return waitOptions.RunWait()
84+
}
85+
86+
func DeleteNodePool(client dynamic.Interface) error {
87+
nodePools := schema.GroupVersionResource{
88+
Group: "karpenter.sh",
89+
Version: "v1beta1",
90+
Resource: "nodepools",
91+
}
92+
93+
list, err := client.Resource(nodePools).List(context.Background(), metav1.ListOptions{})
94+
if err != nil {
95+
if api_errors.IsNotFound(err) {
96+
// nodepools resource doesn't exist, skip deletion
97+
return nil
98+
}
99+
return err
100+
}
101+
102+
for _, item := range list.Items {
103+
nodePoolName := item.GetName()
104+
105+
fmt.Printf("Deleting Karpenter NodePool %q\n", nodePoolName)
106+
if err := client.Resource(nodePools).Delete(context.Background(), nodePoolName, metav1.DeleteOptions{}); err != nil {
107+
fmt.Printf("failed to delete NodePool %q: %s\n", nodePoolName, err)
108+
}
109+
}
110+
return nil
111+
}

pkg/resource/cluster/options.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,10 @@ func (o *ClusterOptions) PreCreate() error {
207207
func (o *ClusterOptions) PreDelete() error {
208208
o.Region = aws.Region()
209209

210+
if err := karpenter.DeleteCustomResources(o.Common().KubeContext); err != nil {
211+
return err
212+
}
213+
210214
cloudformationClient := aws.NewCloudformationClient()
211215
stacks, err := cloudformation_stack.NewGetter(cloudformationClient).GetStacksByCluster(o.ClusterName, "")
212216
if err != nil {

0 commit comments

Comments
 (0)