Skip to content

Commit

Permalink
refactor(kube-api-rewriter): rewrite ownerReferences for Lists (#148)
Browse files Browse the repository at this point in the history
* refactor(kube-api-rewriter): rewrite ownerReferences for Lists

- Fix KubeVirt error: "Failure while starting VMI: controllerrevisions.apps "revision-start-vm-NNNN-N" already exists'" when restarting VM.
- Add test restoring labels, annotations, and ownerReferences for List kind.

Signed-off-by: Ivan Mikheykin <[email protected]>
  • Loading branch information
diafour committed Jun 22, 2024
1 parent 6f72abf commit 8f67db7
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 20 deletions.
28 changes: 10 additions & 18 deletions images/kube-api-proxy/pkg/rewriter/rule_rewriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,32 +270,24 @@ func (rw *RuleBasedRewriter) RewriteJSONPayload(targetReq *TargetRequest, obj []
rwrBytes, err = RewriteServiceMonitorOrList(rw.Rules, obj, action)

default:
if targetReq.IsCore() {
rwrBytes, err = RewriteOwnerReferences(rw.Rules, obj, action)
} else {
rwrBytes, err = RewriteCustomResourceOrList(rw.Rules, obj, action)
}
// TODO Add rw.Rules.IsKnownKind() to rewrite only known kinds.
rwrBytes, err = RewriteCustomResourceOrList(rw.Rules, obj, action)
}
// Return obj bytes as-is in case of the error.
if err != nil {
return obj, err
}

rwrBytes, err = RewriteResourceOrList2(rwrBytes, func(singleObj []byte) ([]byte, error) {
return RewriteMetadata(rw.Rules, singleObj, action)
})
if err != nil {
return obj, err
}

if shouldRewriteOwnerReferences(kind) {
rwrBytes, err = RewriteOwnerReferences(rw.Rules, rwrBytes, action)
// Always rewrite metadata: labels, annotations, finalizers, ownerReferences.
// TODO: add rewriter for managedFields.
return RewriteResourceOrList2(rwrBytes, func(singleObj []byte) ([]byte, error) {
var err error
singleObj, err = RewriteMetadata(rw.Rules, singleObj, action)
if err != nil {
return obj, err
return nil, err
}
}

return rwrBytes, nil
return RewriteOwnerReferences(rw.Rules, singleObj, action)
})
}

// RewritePatch rewrites patches for some known objects.
Expand Down
86 changes: 84 additions & 2 deletions images/kube-api-proxy/pkg/rewriter/rule_rewriter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@ limitations under the License.
package rewriter

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

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

func createTestRewriter() *RuleBasedRewriter {
Expand Down Expand Up @@ -74,8 +78,8 @@ func createTestRewriter() *RuleBasedRewriter {
}

rules := &RewriteRules{
KindPrefix: "Prefixed", // KV
ResourceTypePrefix: "prefixed", // kv
KindPrefix: "Prefixed",
ResourceTypePrefix: "prefixed",
ShortNamePrefix: "p",
Categories: []string{"prefixed"},
RenamedGroup: "prefixed.resources.group.io",
Expand Down Expand Up @@ -197,3 +201,81 @@ func TestRewriteAPIEndpoint(t *testing.T) {
}

}

func TestRestoreControllerRevisionList(t *testing.T) {
getControllerRevisions := `GET /apis/apps/v1/controllerrevisions HTTP/1.1
Host: 127.0.0.1
`
responseBody := `{
"kind":"ControllerRevisionList",
"apiVersion":"apps/v1",
"metadata":{"resourceVersion":"412742959"},
"items":[
{
"metadata": {
"name": "resource-name",
"namespace": "ns-name",
"labels": {
"component.replacedlabelgroup.io/labelName": "labelValue"
},
"annotations":{
"replacedanno.io": "annoValue"
},
"ownerReferences": [
{
"apiVersion": "prefixed.resources.group.io/v1",
"kind": "PrefixedSomeResource",
"name": "owner-name",
"uid": "30b43f23-0c36-442f-897f-fececdf54620",
"controller": true,
"blockOwnerDeletion": true
}
]
},
"data": {"somekey":"somevalue"}
}
]}`

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

rwr := createTestRewriter()
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(responseBody), Restore)
if err != nil {
t.Fatalf("should restore RevisionControllerList without error: %v", err)
}
if resultBytes == nil {
t.Fatalf("should restore RevisionControllerList: %v", err)
}

tests := []struct {
path string
expected string
}{
{`kind`, "ControllerRevisionList"},
{`items.0.metadata.labels.component\.replacedlabelgroup\.io/labelName`, ""},
{`items.0.metadata.labels.component\.labelgroup\.io/labelName`, "labelValue"},
{`items.0.metadata.annotations.replacedanno\.io`, ""},
{`items.0.metadata.annotations.annogroup\.io`, "annoValue"},
{`items.0.metadata.ownerReferences.0.kind`, "SomeResource"},
{`items.0.metadata.ownerReferences.0.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.Log(string(resultBytes))
t.Fatalf("%s value should be %s, got %s", tt.path, tt.expected, actual)
}
})
}
}

0 comments on commit 8f67db7

Please sign in to comment.