@@ -19,7 +19,6 @@ const (
19
19
vClusterMetadataPrefix = "vcluster.loft.sh/"
20
20
)
21
21
22
- // NamespaceCleanupHandler defines the function signature for namespace cleanup operations.
23
22
type NamespaceCleanupHandler func (
24
23
ctx context.Context ,
25
24
mainPhysicalNamespace string ,
@@ -29,7 +28,6 @@ type NamespaceCleanupHandler func(
29
28
logger log.Logger ,
30
29
) error
31
30
32
- // GetNamespaceCleanupHandler returns a NamespaceCleanupHandler function based on the provided policy.
33
31
func GetNamespaceCleanupHandler (policy config.HostDeletionPolicy ) (NamespaceCleanupHandler , error ) {
34
32
switch policy {
35
33
case config .HostDeletionPolicyAll :
@@ -43,14 +41,33 @@ func GetNamespaceCleanupHandler(policy config.HostDeletionPolicy) (NamespaceClea
43
41
}
44
42
}
45
43
46
- // cleanupNoneNamespaces is a no-op handler for the 'none' policy.
44
+ // cleanupNoneNamespaces is a no-op handler for the 'none' policy. It only removes namespace metadata added by vCluster.
47
45
func cleanupNoneNamespaces (
48
- _ context.Context ,
49
- _ string , _ string ,
46
+ ctx context.Context ,
47
+ mainPhysicalNamespace string ,
48
+ vClusterName string ,
50
49
_ config.SyncToHostNamespaces ,
51
- _ * kubernetes.Clientset ,
52
- _ log.Logger ,
50
+ k8sClient * kubernetes.Clientset ,
51
+ logger log.Logger ,
53
52
) error {
53
+ logger .Infof ("Starting metadata cleanup for vCluster '%s' namespaces." , vClusterName )
54
+ managedNamespaces , err := getManagedNamespaces (ctx , k8sClient , mainPhysicalNamespace , vClusterName , logger )
55
+ if err != nil {
56
+ return err
57
+ }
58
+
59
+ var errs []error
60
+ for _ , ns := range managedNamespaces {
61
+ if err := cleanupNamespaceMetadata (ctx , k8sClient , & ns ); err != nil {
62
+ errs = append (errs , err )
63
+ }
64
+ }
65
+
66
+ if len (errs ) > 0 {
67
+ return fmt .Errorf ("metadata cleanup for vCluster '%s' namespaces finished with errors: %w" , vClusterName , errors .Join (errs ... ))
68
+ }
69
+
70
+ logger .Infof ("Metadata cleanup for vCluster '%s' namespaces finished." , vClusterName )
54
71
return nil
55
72
}
56
73
@@ -66,38 +83,24 @@ func cleanupSyncedNamespaces(
66
83
) error {
67
84
logger .Infof ("Starting cleanup of vCluster '%s' namespaces." , vClusterName )
68
85
69
- if mainPhysicalNamespace == "" || vClusterName == "" {
70
- return fmt .Errorf ("main physical namespace or vCluster name is empty" )
71
- }
72
-
73
- labelSelector := translate .MarkerLabel + "=" + translate .SafeConcatName (mainPhysicalNamespace , "x" , vClusterName )
74
- nsList , err := k8sClient .CoreV1 ().Namespaces ().List (ctx , metav1.ListOptions {LabelSelector : labelSelector })
86
+ managedNamespaces , err := getManagedNamespaces (ctx , k8sClient , mainPhysicalNamespace , vClusterName , logger )
75
87
if err != nil {
76
- return fmt .Errorf ("list namespaces: %w" , err )
77
- }
78
-
79
- if nsList == nil || len (nsList .Items ) == 0 {
80
- logger .Infof ("No additional managed namespaces found with label selector '%s'." , labelSelector )
81
- return nil
88
+ return err
82
89
}
83
90
84
91
var errs []error
85
- for _ , ns := range nsList .Items {
86
- // Check if namespace was imported, if yes we skip deletion for 'synced' policy.
87
- if ns .Annotations != nil && ns .Annotations [translate .ImportedMarkerAnnotation ] == "true" {
92
+ for _ , ns := range managedNamespaces {
93
+ if isImportedNamespace (& ns ) {
88
94
logger .Infof ("Namespace %s was imported, cleaning up import." , ns .Name )
89
95
if err := cleanupNamespaceMetadata (ctx , k8sClient , & ns ); err != nil {
90
96
errs = append (errs , err )
91
97
}
92
98
continue
93
99
}
94
100
95
- logger .Infof ("Attempting to delete virtual cluster namespace %s." , ns .Name )
96
- err := k8sClient .CoreV1 ().Namespaces ().Delete (ctx , ns .Name , metav1.DeleteOptions {})
101
+ err := deleteAndLogNamespace (ctx , k8sClient , ns .Name , logger )
97
102
if err != nil {
98
- errs = append (errs , fmt .Errorf ("namespace %s: %w" , ns .Name , err ))
99
- } else {
100
- logger .Donef ("Successfully deleted virtual cluster namespace %s." , ns .Name )
103
+ errs = append (errs , err )
101
104
}
102
105
}
103
106
@@ -120,16 +123,16 @@ func cleanupAllNamespaces(
120
123
logger log.Logger ,
121
124
) error {
122
125
logger .Infof ("Starting cleanup of vCluster '%s' namespaces." , vClusterName )
123
- mappingsConfig := nsSyncConfig .Mappings
124
126
127
+ mappingsConfig := nsSyncConfig .Mappings
125
128
if len (mappingsConfig .ByName ) == 0 {
126
129
logger .Infof ("No namespace mappings defined." )
127
130
logger .Infof ("Cleanup of vCluster '%s' namespaces finished." , vClusterName )
128
131
return nil
129
132
}
130
133
logger .Debugf ("Processing %d namespace mappings for potential deletion." , len (mappingsConfig .ByName ))
131
134
132
- hostNamespaces , err := k8sClient . CoreV1 (). Namespaces (). List ( ctx , metav1.ListOptions {})
135
+ hostNamespaces , err := getNamespaces ( ctx , k8sClient , metav1.ListOptions {})
133
136
if err != nil {
134
137
return fmt .Errorf ("list all host namespaces for mapping check: %w" , err )
135
138
}
@@ -154,14 +157,17 @@ func cleanupAllNamespaces(
154
157
}
155
158
156
159
if currentRuleMatches {
157
- logger . Infof ( "Attempting to delete virtual cluster namespace %s." , hostNs . Name )
158
- err := k8sClient . CoreV1 (). Namespaces (). Delete ( ctx , hostNs .Name , metav1. DeleteOptions {})
159
- if err != nil {
160
- errs = append ( errs , fmt . Errorf ( "delete virtual cluster namespace %s: %w" , hostNs . Name , err ) )
160
+ var err error
161
+ if isProtectedNamespace ( hostNs .Name ) {
162
+ logger . Infof ( "Namespace %s is protected, cleaning up its metadata." , hostNs . Name )
163
+ err = cleanupNamespaceMetadata ( ctx , k8sClient , & hostNs )
161
164
} else {
162
- logger .Donef ("Successfully deleted virtual cluster namespace %s." , hostNs .Name )
165
+ err = deleteAndLogNamespace (ctx , k8sClient , hostNs .Name , logger )
166
+ }
167
+
168
+ if err != nil {
169
+ errs = append (errs , err )
163
170
}
164
- // This namespace has been handled. Skip other mappings and move to the next one.
165
171
break
166
172
}
167
173
}
@@ -175,6 +181,45 @@ func cleanupAllNamespaces(
175
181
return nil
176
182
}
177
183
184
+ func getNamespaces (ctx context.Context , k8sClient * kubernetes.Clientset , listOptions metav1.ListOptions ) (* corev1.NamespaceList , error ) {
185
+ nsList , err := k8sClient .CoreV1 ().Namespaces ().List (ctx , listOptions )
186
+ if err != nil {
187
+ return nil , fmt .Errorf ("listing namespaces with options %+v: %w" , listOptions , err )
188
+ }
189
+ return nsList , nil
190
+ }
191
+
192
+ func getManagedNamespaces (ctx context.Context , k8sClient * kubernetes.Clientset , mainPhysicalNamespace , vClusterName string , logger log.Logger ) ([]corev1.Namespace , error ) {
193
+ if mainPhysicalNamespace == "" || vClusterName == "" {
194
+ return nil , fmt .Errorf ("main physical namespace or vCluster name is empty" )
195
+ }
196
+
197
+ labelSelector := translate .MarkerLabel + "=" + translate .SafeConcatName (mainPhysicalNamespace , "x" , vClusterName )
198
+ listOptions := metav1.ListOptions {LabelSelector : labelSelector }
199
+
200
+ nsList , err := getNamespaces (ctx , k8sClient , listOptions )
201
+ if err != nil {
202
+ return nil , err
203
+ }
204
+
205
+ if nsList == nil || len (nsList .Items ) == 0 {
206
+ logger .Infof ("No additional managed namespaces found with label selector '%s'." , labelSelector )
207
+ return nil , nil
208
+ }
209
+
210
+ return nsList .Items , nil
211
+ }
212
+
213
+ func deleteAndLogNamespace (ctx context.Context , k8sClient * kubernetes.Clientset , nsName string , logger log.Logger ) error {
214
+ logger .Infof ("Attempting to delete virtual cluster namespace %s." , nsName )
215
+ err := k8sClient .CoreV1 ().Namespaces ().Delete (ctx , nsName , metav1.DeleteOptions {})
216
+ if err != nil {
217
+ return fmt .Errorf ("namespace %s: %w" , nsName , err )
218
+ }
219
+ logger .Donef ("Successfully deleted virtual cluster namespace %s." , nsName )
220
+ return nil
221
+ }
222
+
178
223
func cleanupNamespaceMetadata (
179
224
ctx context.Context ,
180
225
k8sClient * kubernetes.Clientset ,
@@ -199,3 +244,14 @@ func cleanupNamespaceMetadata(
199
244
200
245
return nil
201
246
}
247
+
248
+ // isProtectedNamespace checks if a namespace should be protected from deletion.
249
+ // Protected namespaces include 'default' and any namespace prefixed with 'kube-'.
250
+ func isProtectedNamespace (name string ) bool {
251
+ return name == "default" || strings .HasPrefix (name , "kube-" )
252
+ }
253
+
254
+ // isImportedNamespace checks if a namespace was imported
255
+ func isImportedNamespace (ns * corev1.Namespace ) bool {
256
+ return ns .Annotations != nil && ns .Annotations [translate .ImportedMarkerAnnotation ] == "true"
257
+ }
0 commit comments