-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add resource rewriter component
- Loading branch information
1 parent
735f851
commit 23051f0
Showing
10 changed files
with
313 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,21 @@ | ||
package importer | ||
|
||
import ( | ||
"time" | ||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" | ||
|
||
"k8s.io/apimachinery/pkg/api/meta" | ||
"github.com/mhrabovcin/troubleshoot-live/pkg/rewriter" | ||
) | ||
|
||
// prepareForImport modifies object loaded from support bundle file in a way | ||
// that can be imported. | ||
func prepareForImport(in any) error { | ||
obj, err := meta.Accessor(in) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
annotations := obj.GetAnnotations() | ||
if annotations == nil { | ||
annotations = map[string]string{} | ||
} | ||
// TODO(mh): inject | ||
rr := rewriter.GeneratedValues() | ||
|
||
if obj.GetResourceVersion() != "" { | ||
annotations[AnnotationForOriginalValue("resourceVersion")] = obj.GetResourceVersion() | ||
obj.SetResourceVersion("") | ||
u, ok := in.(*unstructured.Unstructured) | ||
if !ok { | ||
panic("non unstructured obj") | ||
} | ||
|
||
annotations[AnnotationForOriginalValue("creationTimestamp")] = obj.GetCreationTimestamp().Format(time.RFC3339) | ||
obj.SetAnnotations(annotations) | ||
|
||
return nil | ||
return rr.BeforeImport(u) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package rewriter | ||
|
||
// GeneratedValues removes generated values. | ||
// See: https://kubernetes.io/docs/reference/using-api/api-concepts/#generated-values | ||
func GeneratedValues() ResourceRewriter { | ||
return Multi( | ||
RemoveField("metadata", "generateName"), | ||
RemoveField("metadata", "creationTimestamp"), | ||
RemoveField("metadata", "deletionTimestamp"), | ||
RemoveField("metadata", "uid"), | ||
RemoveField("metadata", "resourceVersion"), | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package rewriter | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
"time" | ||
|
||
"github.com/stretchr/testify/assert" | ||
corev1 "k8s.io/api/core/v1" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/types" | ||
) | ||
|
||
func TestGeneratedValues(t *testing.T) { | ||
r := GeneratedValues() | ||
timestamp := metav1.NewTime(time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)) | ||
pod := &corev1.Pod{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
GenerateName: "generated-", | ||
CreationTimestamp: timestamp, | ||
DeletionTimestamp: ×tamp, | ||
UID: types.UID("1000"), | ||
ResourceVersion: "2000", | ||
}, | ||
} | ||
pod = testRewriterBeforeImport(t, r, pod) | ||
assert.Empty(t, pod.GetGenerateName()) | ||
assert.Empty(t, pod.GetCreationTimestamp()) | ||
assert.Empty(t, pod.GetDeletionTimestamp()) | ||
assert.Empty(t, pod.GetUID()) | ||
assert.Empty(t, pod.GetResourceVersion()) | ||
|
||
expectedFields := map[string]string{ | ||
"generateName": "generated-", | ||
"creationTimestamp": "2023-01-01T00:00:00Z", | ||
"deletionTimestamp": "2023-01-01T00:00:00Z", | ||
"uid": "1000", | ||
"resourceVersion": "2000", | ||
} | ||
for k, v := range expectedFields { | ||
fieldName := fmt.Sprintf("metadata.%s", k) | ||
annotation := annotationForOriginalValue(fieldName) | ||
assert.Contains(t, pod.GetAnnotations(), annotation, "annotation %q missing", fieldName) | ||
assert.Equal(t, v, pod.GetAnnotations()[annotation], "wrong value stored in %q", fieldName) | ||
} | ||
|
||
pod = testRewriterBeforeServing(t, r, pod) | ||
assert.Equal(t, "generated-", pod.GetGenerateName()) | ||
assert.Equal(t, timestamp.Format(time.RFC3339), pod.GetCreationTimestamp().In(time.UTC).Format(time.RFC3339)) | ||
assert.Equal(t, timestamp.Format(time.RFC3339), pod.GetDeletionTimestamp().In(time.UTC).Format(time.RFC3339)) | ||
assert.Equal(t, types.UID("1000"), pod.GetUID()) | ||
assert.Equal(t, "2000", pod.GetResourceVersion()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package rewriter | ||
|
||
import "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" | ||
|
||
type multiRewriter struct { | ||
rewriters []ResourceRewriter | ||
} | ||
|
||
var _ ResourceRewriter = (*multiRewriter)(nil) | ||
|
||
// Multi executes serially multiple rewriters. | ||
func Multi(rewriters ...ResourceRewriter) ResourceRewriter { | ||
return &multiRewriter{ | ||
rewriters: rewriters, | ||
} | ||
} | ||
|
||
func (r *multiRewriter) BeforeImport(u *unstructured.Unstructured) error { | ||
for _, rewriter := range r.rewriters { | ||
if err := rewriter.BeforeImport(u); err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (r *multiRewriter) BeforeServing(u *unstructured.Unstructured) error { | ||
for _, rewriter := range r.rewriters { | ||
if err := rewriter.BeforeServing(u); err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package rewriter | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" | ||
) | ||
|
||
// annotationForOriginalValue creates annotation key for given value. | ||
func annotationForOriginalValue(name string) string { | ||
return fmt.Sprintf("troubleshoot-live/%s", name) | ||
} | ||
|
||
// ResourceRewriter prepares object for saving on import and rewrites the object | ||
// before its returned back from proxy server. | ||
type ResourceRewriter interface { | ||
// BeforeImport is invoked when object is created in API server. | ||
BeforeImport(u *unstructured.Unstructured) error | ||
|
||
// BeforeServing is applied when object passes proxy (via List or Get request). | ||
BeforeServing(u *unstructured.Unstructured) error | ||
} | ||
|
||
var _ ResourceRewriter = (*removeField)(nil) | ||
|
||
// RemoveField removes a field from original object. This should be used for metadata | ||
// fields that are generated by API server on write. | ||
func RemoveField(path ...string) ResourceRewriter { | ||
return &removeField{ | ||
fieldPath: path, | ||
} | ||
} | ||
|
||
type removeField struct { | ||
fieldPath []string | ||
} | ||
|
||
func (r *removeField) annotationName() string { | ||
return annotationForOriginalValue(strings.Join(r.fieldPath, ".")) | ||
} | ||
|
||
func (r *removeField) BeforeImport(u *unstructured.Unstructured) error { | ||
s, ok, err := unstructured.NestedString(u.Object, r.fieldPath...) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if !ok { | ||
return nil | ||
} | ||
|
||
unstructured.RemoveNestedField(u.Object, r.fieldPath...) | ||
return addAnnotation(u, r.annotationName(), s) | ||
} | ||
|
||
func (r *removeField) BeforeServing(u *unstructured.Unstructured) error { | ||
value, ok, err := unstructured.NestedString(u.Object, "metadata", "annotations", r.annotationName()) | ||
if err != nil { | ||
return err | ||
} | ||
if !ok { | ||
return nil | ||
} | ||
|
||
if err := unstructured.SetNestedField(u.Object, value, r.fieldPath...); err != nil { | ||
return err | ||
} | ||
unstructured.RemoveNestedField(u.Object, "metadata", "annotations", r.annotationName()) | ||
return nil | ||
} | ||
|
||
func addAnnotation(u *unstructured.Unstructured, key, value string) error { | ||
annotations, ok, err := unstructured.NestedStringMap(u.Object, "metadata", "annotations") | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if !ok { | ||
annotations = map[string]string{} | ||
} | ||
|
||
annotations[key] = value | ||
return unstructured.SetNestedStringMap(u.Object, annotations, "metadata", "annotations") | ||
} |
Oops, something went wrong.