Skip to content

Commit

Permalink
refactor(kube-api-rewriter): add rewriter for Event resources (#496)
Browse files Browse the repository at this point in the history
* refactor(kube-api-rewriter): add rewriter for Event resources

- Stop confusing API consumers with non-renamed kind VirtualMachineInstance in Events.

---------

Signed-off-by: Ivan Mikheykin <[email protected]>
  • Loading branch information
diafour authored Nov 5, 2024
1 parent 44e2679 commit 191c214
Show file tree
Hide file tree
Showing 8 changed files with 252 additions and 77 deletions.
39 changes: 0 additions & 39 deletions images/kube-api-rewriter/pkg/rewriter/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package rewriter

import (
"github.com/tidwall/gjson"
"github.com/tidwall/sjson"
)

const (
Expand Down Expand Up @@ -86,41 +85,3 @@ func RenameServicePatch(rules *RewriteRules, obj []byte) ([]byte, error) {
return jsonPatch, nil
})
}

func RewriteAPIGroupAndKind(rules *RewriteRules, obj []byte, action Action) ([]byte, error) {
kind := gjson.GetBytes(obj, "kind").String()
apiGroup := gjson.GetBytes(obj, "apiGroup").String()

rwrApiVersion := ""
rwrKind := ""
if action == Rename {
_, resourceRule := rules.KindRules(apiGroup, kind)
if resourceRule != nil {
rwrApiVersion = rules.RenameApiVersion(apiGroup)
rwrKind = rules.RenameKind(kind)
}
}
if action == Restore {
if rules.IsRenamedGroup(apiGroup) {
rwrApiVersion = rules.RestoreApiVersion(apiGroup)
rwrKind = rules.RestoreKind(kind)
// Find resource rule by restored apiGroup and kind
_, resourceRule := rules.KindRules(rwrApiVersion, rwrKind)
if resourceRule == nil {
return obj, nil
}
}
}

if rwrApiVersion == "" || rwrKind == "" {
// No rewrite for OwnerReference without rules.
return obj, nil
}

obj, err := sjson.SetBytes(obj, "kind", rwrKind)
if err != nil {
return nil, err
}

return sjson.SetBytes(obj, "apiGroup", rwrApiVersion)
}
52 changes: 52 additions & 0 deletions images/kube-api-rewriter/pkg/rewriter/events.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
Copyright 2024 Flant JSC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package rewriter

const (
EventKind = "Event"
EventListKind = "EventList"
)

// RewriteEventOrList rewrites a single Event resource or a list of Events in EventList.
// The only field need to rewrite is involvedObject:
//
// {
// "metadata": { "name": "...", "namespace": "...", "managedFields": [...] },
// "involvedObject": {
// "kind": "SomeResource",
// "namespace": "name",
// "name": "ns",
// "uid": "a260fe4f-103a-41c6-996c-d29edb01fbbd",
// "apiVersion": "group.io/v1"
// },
// "type": "...",
// "reason": "...",
// "message": "...",
// "source": {
// "component": "...",
// "host": "..."
// },
// "reportingComponent": "...",
// "reportingInstance": "..."
// },
func RewriteEventOrList(rules *RewriteRules, obj []byte, action Action) ([]byte, error) {
return RewriteResourceOrList(obj, EventListKind, func(singleObj []byte) ([]byte, error) {
return TransformObject(singleObj, "involvedObject", func(involvedObj []byte) ([]byte, error) {
return RewriteAPIVersionAndKind(rules, involvedObj, action)
})
})
}
123 changes: 123 additions & 0 deletions images/kube-api-rewriter/pkg/rewriter/events_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
Copyright 2024 Flant JSC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package rewriter

import (
"bufio"
"bytes"
"net/http"
"testing"

"github.com/stretchr/testify/require"
"github.com/tidwall/gjson"
)

func TestRewriteEvent(t *testing.T) {
eventReq := `POST /api/v1/namespaces/vm/events HTTP/1.1
Host: 127.0.0.1
`
eventPayload := `{
"kind": "Event",
"apiVersion": "v1",
"metadata": {
"name": "some-event-name",
"namespace": "vm",
},
"involvedObject": {
"kind": "SomeResource",
"namespace": "vm",
"name": "some-vm-name",
"uid": "ad9f7357-f6b0-4679-8571-042c75ec53fb",
"apiVersion": "original.group.io/v1"
},
"reason": "EventReason",
"message": "Event message for some-vm-name",
"source": {
"component": "some-component",
"host": "some-node"
},
"count": 1000,
"type": "Warning",
"eventTime": null,
"reportingComponent": "some-component",
"reportingInstance": "some-node"
}`

req, err := http.ReadRequest(bufio.NewReader(bytes.NewBufferString(eventReq + eventPayload)))
require.NoError(t, err, "should parse hardcoded http request")
require.NotNil(t, req.URL, "should parse url in hardcoded http request")

rwr := createTestRewriterForCore()
targetReq := NewTargetRequest(rwr, req)
require.NotNil(t, targetReq, "should get TargetRequest")
require.True(t, targetReq.ShouldRewriteRequest(), "should rewrite request")
require.True(t, targetReq.ShouldRewriteResponse(), "should rewrite response")
// require.Equal(t, origGroup, targetReq.OrigGroup(), "should set proper orig group")

resultBytes, err := rwr.RewriteJSONPayload(targetReq, []byte(eventPayload), Rename)
if err != nil {
t.Fatalf("should rename Error without error: %v", err)
}
if resultBytes == nil {
t.Fatalf("should rename Error: %v", err)
}

tests := []struct {
path string
expected string
}{
{`involvedObject.kind`, "PrefixedSomeResource"},
{`involvedObject.apiVersion`, "prefixed.resources.group.io/v1"},
}

for _, tt := range tests {
t.Run(tt.path, func(t *testing.T) {
actual := gjson.GetBytes(resultBytes, tt.path).String()
if actual != tt.expected {
t.Fatalf("%s value should be %s, got %s", tt.path, tt.expected, actual)
}
})
}

// Restore.
resultBytes, err = rwr.RewriteJSONPayload(targetReq, []byte(eventPayload), Restore)
if err != nil {
t.Fatalf("should restore PVC without error: %v", err)
}
if resultBytes == nil {
t.Fatalf("should restore PVC: %v", err)
}

tests = []struct {
path string
expected string
}{
{`involvedObject.kind`, "SomeResource"},
{`involvedObject.apiVersion`, "original.group.io/v1"},
}

for _, tt := range tests {
t.Run(tt.path, func(t *testing.T) {
actual := gjson.GetBytes(resultBytes, tt.path).String()
if actual != tt.expected {
t.Fatalf("%s value should be %s, got %s", tt.path, tt.expected, actual)
}
})
}

}
69 changes: 69 additions & 0 deletions images/kube-api-rewriter/pkg/rewriter/gvk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
Copyright 2024 Flant JSC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package rewriter

import (
"github.com/tidwall/gjson"
"github.com/tidwall/sjson"
)

func RewriteAPIGroupAndKind(rules *RewriteRules, obj []byte, action Action) ([]byte, error) {
return RewriteGVK(rules, obj, action, "apiGroup")
}

func RewriteAPIVersionAndKind(rules *RewriteRules, obj []byte, action Action) ([]byte, error) {
return RewriteGVK(rules, obj, action, "apiVersion")
}

// RewriteGVK rewrites a "kind" field and a field with the group
// if there is the rule for these particular kind and group.
func RewriteGVK(rules *RewriteRules, obj []byte, action Action, gvFieldName string) ([]byte, error) {
kind := gjson.GetBytes(obj, "kind").String()
apiGroupVersion := gjson.GetBytes(obj, gvFieldName).String()

rwrApiVersion := ""
rwrKind := ""
if action == Rename {
// Rename if there is a rule for kind and group
_, resourceRule := rules.KindRules(apiGroupVersion, kind)
if resourceRule == nil {
return obj, nil
}
rwrApiVersion = rules.RenameApiVersion(apiGroupVersion)
rwrKind = rules.RenameKind(kind)
}
if action == Restore {
// Restore if group is renamed and a rule can be found
// for restored kind and group.
if !rules.IsRenamedGroup(apiGroupVersion) {
return obj, nil
}
rwrApiVersion = rules.RestoreApiVersion(apiGroupVersion)
rwrKind = rules.RestoreKind(kind)
_, resourceRule := rules.KindRules(rwrApiVersion, rwrKind)
if resourceRule == nil {
return obj, nil
}
}

obj, err := sjson.SetBytes(obj, "kind", rwrKind)
if err != nil {
return nil, err
}

return sjson.SetBytes(obj, gvFieldName, rwrApiVersion)
}
4 changes: 2 additions & 2 deletions images/kube-api-rewriter/pkg/rewriter/rbac_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func TestRenameRoleRule(t *testing.T) {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
resBytes, err := renameRoleRule(rwr.Rules, []byte(tt.rule))
resBytes, err := RenameResourceRule(rwr.Rules, []byte(tt.rule))
require.NoError(t, err, "should rename rule")

actual := string(resBytes)
Expand Down Expand Up @@ -174,7 +174,7 @@ func TestRestoreRoleRule(t *testing.T) {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
resBytes, err := restoreRoleRule(rwr.Rules, []byte(tt.rule))
resBytes, err := RestoreResourceRule(rwr.Rules, []byte(tt.rule))
require.NoError(t, err, "should rename rule")

actual := string(resBytes)
Expand Down
36 changes: 1 addition & 35 deletions images/kube-api-rewriter/pkg/rewriter/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,41 +118,7 @@ func RestoreAPIVersionAndKind(rules *RewriteRules, obj []byte) ([]byte, error) {

func RewriteOwnerReferences(rules *RewriteRules, obj []byte, path string, action Action) ([]byte, error) {
return RewriteArray(obj, path, func(ownerRefObj []byte) ([]byte, error) {
kind := gjson.GetBytes(ownerRefObj, "kind").String()
apiVersion := gjson.GetBytes(ownerRefObj, "apiVersion").String()

rwrApiVersion := ""
rwrKind := ""
if action == Rename {
_, resourceRule := rules.KindRules(apiVersion, kind)
if resourceRule != nil {
rwrApiVersion = rules.RenameApiVersion(apiVersion)
rwrKind = rules.RenameKind(kind)
}
}
if action == Restore {
if rules.IsRenamedGroup(apiVersion) {
rwrApiVersion = rules.RestoreApiVersion(apiVersion)
rwrKind = rules.RestoreKind(kind)
// Find resource rule by restored apiGroup and kind
_, resourceRule := rules.KindRules(rwrApiVersion, rwrKind)
if resourceRule == nil {
return ownerRefObj, nil
}
}
}

if rwrApiVersion == "" || rwrKind == "" {
// No rewrite for OwnerReference without rules.
return ownerRefObj, nil
}

ownerRefObj, err := sjson.SetBytes(ownerRefObj, "kind", rwrKind)
if err != nil {
return nil, err
}

return sjson.SetBytes(ownerRefObj, "apiVersion", rwrApiVersion)
return RewriteAPIVersionAndKind(rules, ownerRefObj, action)
})
}

Expand Down
3 changes: 3 additions & 0 deletions images/kube-api-rewriter/pkg/rewriter/rule_rewriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,9 @@ func (rw *RuleBasedRewriter) RewriteJSONPayload(_ *TargetRequest, obj []byte, ac
ValidatingWebhookConfigurationListKind:
rwrBytes, err = RewriteValidatingOrList(rw.Rules, obj, action)

case EventKind, EventListKind:
rwrBytes, err = RewriteEventOrList(rw.Rules, obj, action)

case ClusterRoleKind, ClusterRoleListKind:
rwrBytes, err = RewriteClusterRoleOrList(rw.Rules, obj, action)

Expand Down
3 changes: 2 additions & 1 deletion images/kube-api-rewriter/pkg/rewriter/target_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,8 @@ func shouldRewriteResource(resourceType string) bool {
"controllerrevisions",
"apiservices",
"validatingadmissionpolicybindings",
"validatingadmissionpolicies":
"validatingadmissionpolicies",
"events":
return true
}

Expand Down

0 comments on commit 191c214

Please sign in to comment.