Skip to content

Commit 916d5ff

Browse files
committed
fix: set correct namespace for recycled object
1 parent 0ea2b57 commit 916d5ff

File tree

7 files changed

+82
-37
lines changed

7 files changed

+82
-37
lines changed

cmd/krb-cli/cmd/get-recycle-items.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ func runGetRecycleItems(args []string) {
150150
t.SetOutputMirror(os.Stdout)
151151
t.AppendHeader(table.Row{"Name", "Object Key", "Object APIVersion", "Object Kind", "Age"})
152152
for _, obj := range result.Items {
153-
t.AppendRow(table.Row{obj.Name, obj.Object.Key().String(), obj.Object.GroupVersion().String(), obj.Object.Kind, duration.HumanDuration(time.Since(obj.CreationTimestamp.Time))}, table.RowConfig{
153+
t.AppendRow(table.Row{obj.Name, obj.Object.Key(), obj.Object.GroupVersion().String(), obj.Object.Kind, duration.HumanDuration(time.Since(obj.CreationTimestamp.Time))}, table.RowConfig{
154154
AutoMerge: true,
155155
})
156156
}

cmd/krb-cli/cmd/restore.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,9 @@ func runRestore(args []string) {
8686
}
8787

8888
if _, err := kube.DynamicClient().Resource(recycleItem.Object.GroupVersionResource()).Namespace(recycleItem.Object.Namespace).Create(context.Background(), unstructuredObj, metav1.CreateOptions{}); err != nil {
89-
tlog.Printf("✗ failed to restore recycled resource object [%s]: %v", recycleItem.Object.Key().String(), err)
89+
tlog.Printf("✗ failed to restore recycled resource object [%s]: %v", recycleItem.Object.Key(), err)
9090
} else {
91-
tlog.Printf("✓ restored recycled resource object [%s: %s] done.", recycleItem.Object.Resource, recycleItem.Object.Key().String())
91+
tlog.Printf("✓ restored recycled resource object [%s: %s] done.", recycleItem.Object.Resource, recycleItem.Object.Key())
9292
// delete the recycle item after successful restore
9393
if err := krbclient.RecycleItem().Delete(context.Background(), recycleItemName, client.DeleteOptions{}); err != nil {
9494
tlog.Printf("✗ failed to automatically delete RecycleItem [%s] after restore: %v", recycleItemName, err)

cmd/krb-cli/cmd/view.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,19 +90,19 @@ func runView(args []string) {
9090
case "json":
9191
objContent, err := recycleItem.Object.IndentedJSON()
9292
if err != nil {
93-
tlog.Printf("✗ failed to view recycled resource object [%s: %s] from RecycleItem [%s] in JSON format: %s, error: %v", recycleItem.Object.Kind, recycleItem.Object.Key().String(), recycleItem.Name, recycleItem.Name, err)
93+
tlog.Printf("✗ failed to view recycled resource object [%s: %s] from RecycleItem [%s] in JSON format: %s, error: %v", recycleItem.Object.Kind, recycleItem.Object.Key(), recycleItem.Name, recycleItem.Name, err)
9494
continue
9595
}
9696
objContents = append(objContents, objContent)
97-
// tlog.Printf("✓ recycled resource object [%s: %s] from RecycleItem [%s]: \n%s \n", recycleItem.Object.Kind, recycleItem.Object.Key().String(), recycleItem.Name, objContent)
97+
// tlog.Printf("✓ recycled resource object [%s: %s] from RecycleItem [%s]: \n%s \n", recycleItem.Object.Kind, recycleItem.Object.Key(), recycleItem.Name, objContent)
9898
default:
9999
objContent, err := recycleItem.Object.YAML()
100100
if err != nil {
101-
tlog.Printf("✗ failed to view recycled resource object [%s: %s] from RecycleItem [%s] in YAML format: %s, error: %v", recycleItem.Object.Kind, recycleItem.Object.Key().String(), recycleItem.Name, recycleItem.Name, err)
101+
tlog.Printf("✗ failed to view recycled resource object [%s: %s] from RecycleItem [%s] in YAML format: %s, error: %v", recycleItem.Object.Kind, recycleItem.Object.Key(), recycleItem.Name, recycleItem.Name, err)
102102
continue
103103
}
104104
objContents = append(objContents, objContent)
105-
// tlog.Printf("✓ recycled resource object [%s: %s] from RecycleItem [%s]: \n%s \n", recycleItem.Object.Kind, recycleItem.Object.Key().String(), recycleItem.Name, objContent)
105+
// tlog.Printf("✓ recycled resource object [%s: %s] from RecycleItem [%s]: \n%s \n", recycleItem.Object.Kind, recycleItem.Object.Key(), recycleItem.Name, objContent)
106106
}
107107
}
108108
tlog.Print(strings.Join(objContents, "\n---\n"))

internal/api/recycle_item_types.go

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import (
2424
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2525
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2626
"k8s.io/apimachinery/pkg/runtime/schema"
27-
"k8s.io/apimachinery/pkg/types"
2827
"k8s.io/apimachinery/pkg/util/rand"
2928
"sigs.k8s.io/yaml"
3029
)
@@ -53,13 +52,9 @@ type RecycleItemList struct {
5352
}
5453

5554
func NewRecycleItem(recycledObj *RecycledObject) *RecycleItem {
56-
gr := metav1.GroupResource{
57-
Group: recycledObj.Group,
58-
Resource: recycledObj.Resource,
59-
}
6055
labels := map[string]string{
6156
"krb.ketches.cn/object-name": recycledObj.Name,
62-
"krb.ketches.cn/object-gr": gr.String(),
57+
"krb.ketches.cn/object-gr": recycledObj.GroupResource().String(),
6358
"krb.ketches.cn/recycled-at": fmt.Sprintf("%d", metav1.Now().Unix()),
6459
}
6560
if recycledObj.Namespace != "" {
@@ -72,18 +67,18 @@ func NewRecycleItem(recycledObj *RecycledObject) *RecycleItem {
7267
Kind: RecycleItemKind,
7368
},
7469
ObjectMeta: metav1.ObjectMeta{
75-
Name: fmt.Sprintf("%s-%s", recycledObj.Name, rand.String(8)),
70+
Name: recycledObj.Name + "-" + rand.String(8),
7671
Labels: labels,
7772
},
7873
Object: *recycledObj,
7974
}
8075
}
8176

82-
func (obj *RecycledObject) Key() types.NamespacedName {
83-
return types.NamespacedName{
84-
Name: obj.Name,
85-
Namespace: obj.Namespace,
77+
func (obj *RecycledObject) Key() string {
78+
if obj.Namespace == "" {
79+
return obj.Name
8680
}
81+
return obj.Namespace + "/" + obj.Name
8782
}
8883

8984
func (obj *RecycledObject) GroupVersionKind() schema.GroupVersionKind {

internal/webhook/webhook.go

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@ import (
2727
"github.com/ketches/kube-recycle-bin/internal/api"
2828
krbclient "github.com/ketches/kube-recycle-bin/internal/client"
2929
"github.com/ketches/kube-recycle-bin/internal/consts"
30+
"github.com/ketches/kube-recycle-bin/pkg/kube"
3031
"github.com/ketches/kube-recycle-bin/pkg/tlog"
32+
"github.com/ketches/kube-recycle-bin/pkg/util"
3133
admissionv1 "k8s.io/api/admission/v1"
3234
k8serrors "k8s.io/apimachinery/pkg/api/errors"
33-
"k8s.io/apimachinery/pkg/types"
35+
"k8s.io/apimachinery/pkg/runtime/schema"
3436
"k8s.io/client-go/util/retry"
3537
"sigs.k8s.io/controller-runtime/pkg/client"
3638
"sigs.k8s.io/controller-runtime/pkg/log"
@@ -78,26 +80,23 @@ func recycleDeleteObjects(w http.ResponseWriter, r *http.Request) {
7880
}
7981

8082
request := review.Request
81-
tlog.Infof("» prepare to recycle deleted object: %s - %s", request.Kind.String(), types.NamespacedName{
82-
Name: request.Name,
83-
Namespace: request.Namespace,
84-
}.String())
8583

8684
// Create RecycleItem to recycle the deleted object.
87-
recycleItem := api.NewRecycleItem(buildRecycledObject(request))
88-
if err := retry.OnError(retry.DefaultRetry, k8serrors.IsAlreadyExists, func() error {
89-
if err := krbclient.RecycleItem().Create(context.Background(), recycleItem, client.CreateOptions{}); err != nil {
90-
return err
85+
recycledObj := buildRecycledObject(request)
86+
if recycledObj != nil {
87+
tlog.Infof("» prepare to recycle deleted object [%s: %s]", request.Kind.Kind, recycledObj.Key())
88+
recycleItem := api.NewRecycleItem(recycledObj)
89+
if err := retry.OnError(retry.DefaultRetry, k8serrors.IsAlreadyExists, func() error {
90+
if err := krbclient.RecycleItem().Create(context.Background(), recycleItem, client.CreateOptions{}); err != nil {
91+
return err
92+
}
93+
94+
tlog.Infof("✓ recycle deleted object [%s: %s] done.", recycledObj.Kind, recycledObj.Key())
95+
96+
return nil
97+
}); err != nil {
98+
tlog.Errorf("✗ failed to recycle deleted object [%s: %s]: %v", recycledObj.Kind, recycledObj.Key(), err)
9199
}
92-
93-
tlog.Infof("✓ recycle deleted object %s done", types.NamespacedName{
94-
Name: request.Name,
95-
Namespace: request.Namespace,
96-
}.String())
97-
98-
return nil
99-
}); err != nil {
100-
tlog.Errorf("✗ failed to recycle deleted object: %v", err)
101100
}
102101

103102
response(w, review)
@@ -119,12 +118,21 @@ func parseRequest(r *http.Request) (*admissionv1.AdmissionReview, error) {
119118

120119
// buildRecycledObject constructs api.RecycledObject from the request
121120
func buildRecycledObject(request *admissionv1.AdmissionRequest) *api.RecycledObject {
121+
namespaced, err := kube.IsResourceNamespaced(schema.GroupVersionResource{
122+
Group: request.Resource.Group,
123+
Version: request.Resource.Version,
124+
Resource: request.Resource.Resource,
125+
})
126+
if err != nil {
127+
tlog.Errorf("✗ failed to check if resource is namespaced: %v", err)
128+
return nil
129+
}
122130
return &api.RecycledObject{
123131
Group: request.Resource.Group,
124132
Version: request.Resource.Version,
125133
Resource: request.Resource.Resource,
126134
Kind: request.Kind.Kind,
127-
Namespace: request.Namespace,
135+
Namespace: util.If(namespaced, request.Namespace, ""),
128136
Name: request.Name,
129137
Raw: request.OldObject.Raw,
130138
}

pkg/kube/gvkr.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"k8s.io/client-go/restmapper"
2525
)
2626

27+
// GetAllGroupResources returns all group resources in the cluster.
2728
func GetAllGroupResources() ([]string, error) {
2829
discoveryClient := DiscoveryClient()
2930

@@ -146,3 +147,20 @@ func GetPreferredGroupVersionResourceFor(resource string) (*schema.GroupVersionR
146147
}
147148
return nil, fmt.Errorf("can not find preferred GroupVersionResource for resource %s", resource)
148149
}
150+
151+
// IsResourceNamespaced checks if the given GroupVersionResource is namespaced.
152+
func IsResourceNamespaced(gvr schema.GroupVersionResource) (bool, error) {
153+
discoveryClient := DiscoveryClient()
154+
155+
apiResourceList, err := discoveryClient.ServerResourcesForGroupVersion(gvr.GroupVersion().String())
156+
if err != nil {
157+
return false, err
158+
}
159+
160+
for _, apiResource := range apiResourceList.APIResources {
161+
if apiResource.Name == gvr.Resource {
162+
return apiResource.Namespaced, nil
163+
}
164+
}
165+
return false, fmt.Errorf("can not assert if resource %s is namespaced", gvr.GroupResource().String())
166+
}

pkg/util/cond.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
Copyright 2025 The Ketches 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 util
18+
19+
func If(cond bool, a, b string) string {
20+
if cond {
21+
return a
22+
}
23+
return b
24+
}

0 commit comments

Comments
 (0)