mirror of
https://github.com/kubernetes/client-go.git
synced 2025-06-20 04:13:19 +00:00
The canonical import for json-patch v4 is gopkg.in/evanphx/json-patch.v4 (see https://github.com/evanphx/json-patch/blob/master/README.md#get-it for reference). Using the v4-specific path should also reduce the risk of unwanted v5 upgrade attempts, because they won't be offered as automated upgrades by dependency upgrade management tools, and they won't happen through indirect dependencies (see https://github.com/kubernetes/kubernetes/pull/120327 for context). Signed-off-by: Stephen Kitt <skitt@redhat.com> Kubernetes-commit: 5300466a5c8988b479a151ceb77f49dd00065c83
1312 lines
36 KiB
Go
1312 lines
36 KiB
Go
/*
|
|
Copyright 2022 The Kubernetes Authors.
|
|
|
|
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 csaupgrade_test
|
|
|
|
import (
|
|
"encoding/json"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/stretchr/testify/require"
|
|
jsonpatch "gopkg.in/evanphx/json-patch.v4"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
"k8s.io/apimachinery/pkg/util/sets"
|
|
"k8s.io/apimachinery/pkg/util/yaml"
|
|
"k8s.io/client-go/util/csaupgrade"
|
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
|
)
|
|
|
|
func TestFindOwners(t *testing.T) {
|
|
testCases := []struct {
|
|
Name string
|
|
ManagedFieldsYAML string
|
|
Operation metav1.ManagedFieldsOperationType
|
|
Fields *fieldpath.Set
|
|
Expectation []string
|
|
}{
|
|
{
|
|
// Field a root field path owner
|
|
Name: "Basic",
|
|
ManagedFieldsYAML: `
|
|
managedFields:
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:data:
|
|
.: {}
|
|
f:key: {}
|
|
f:legacy: {}
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
manager: kubectl-client-side-apply
|
|
operation: Update
|
|
time: "2022-08-22T23:08:23Z"
|
|
`,
|
|
Operation: metav1.ManagedFieldsOperationUpdate,
|
|
Fields: fieldpath.NewSet(fieldpath.MakePathOrDie("data")),
|
|
Expectation: []string{"kubectl-client-side-apply"},
|
|
},
|
|
{
|
|
// Find a fieldpath nested inside another field
|
|
Name: "Nested",
|
|
ManagedFieldsYAML: `
|
|
managedFields:
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:data:
|
|
.: {}
|
|
f:key: {}
|
|
f:legacy: {}
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
manager: kubectl-client-side-apply
|
|
operation: Update
|
|
time: "2022-08-22T23:08:23Z"
|
|
`,
|
|
Operation: metav1.ManagedFieldsOperationUpdate,
|
|
Fields: fieldpath.NewSet(fieldpath.MakePathOrDie("metadata", "annotations", "kubectl.kubernetes.io/last-applied-configuration")),
|
|
Expectation: []string{"kubectl-client-side-apply"},
|
|
},
|
|
{
|
|
// Search for an operaiton/fieldpath combination that is not found on both
|
|
// axes
|
|
Name: "NotFound",
|
|
ManagedFieldsYAML: `
|
|
managedFields:
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:data:
|
|
.: {}
|
|
f:key: {}
|
|
f:legacy: {}
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
manager: kubectl
|
|
operation: Apply
|
|
time: "2022-08-23T23:08:23Z"
|
|
`,
|
|
Operation: metav1.ManagedFieldsOperationUpdate,
|
|
Fields: fieldpath.NewSet(fieldpath.MakePathOrDie("metadata", "annotations", "kubectl.kubernetes.io/last-applied-configuration")),
|
|
Expectation: []string{},
|
|
},
|
|
{
|
|
// Test using apply operation
|
|
Name: "ApplyOperation",
|
|
ManagedFieldsYAML: `
|
|
managedFields:
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:data:
|
|
.: {}
|
|
f:key: {}
|
|
f:legacy: {}
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
manager: kubectl
|
|
operation: Apply
|
|
time: "2022-08-23T23:08:23Z"
|
|
`,
|
|
Operation: metav1.ManagedFieldsOperationApply,
|
|
Fields: fieldpath.NewSet(fieldpath.MakePathOrDie("metadata", "annotations", "kubectl.kubernetes.io/last-applied-configuration")),
|
|
Expectation: []string{"kubectl"},
|
|
},
|
|
{
|
|
// Of multiple field managers, match a single one
|
|
Name: "OneOfMultiple",
|
|
ManagedFieldsYAML: `
|
|
managedFields:
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
manager: kubectl-client-side-apply
|
|
operation: Update
|
|
time: "2022-08-23T23:08:23Z"
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:data:
|
|
.: {}
|
|
f:key: {}
|
|
f:legacy: {}
|
|
manager: kubectl
|
|
operation: Apply
|
|
time: "2022-08-23T23:08:23Z"
|
|
`,
|
|
Operation: metav1.ManagedFieldsOperationUpdate,
|
|
Fields: fieldpath.NewSet(fieldpath.MakePathOrDie("metadata", "annotations", "kubectl.kubernetes.io/last-applied-configuration")),
|
|
Expectation: []string{"kubectl-client-side-apply"},
|
|
},
|
|
{
|
|
// have multiple field managers, and match more than one but not all of them
|
|
Name: "ManyOfMultiple",
|
|
ManagedFieldsYAML: `
|
|
managedFields:
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
manager: kubectl-client-side-apply
|
|
operation: Update
|
|
time: "2022-08-23T23:08:23Z"
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
f:data:
|
|
.: {}
|
|
f:key: {}
|
|
f:legacy: {}
|
|
manager: kubectl
|
|
operation: Apply
|
|
time: "2022-08-23T23:08:23Z"
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
manager: kubectl-client-side-apply2
|
|
operation: Update
|
|
time: "2022-08-23T23:08:23Z"
|
|
`,
|
|
Operation: metav1.ManagedFieldsOperationUpdate,
|
|
Fields: fieldpath.NewSet(fieldpath.MakePathOrDie("metadata", "annotations", "kubectl.kubernetes.io/last-applied-configuration")),
|
|
Expectation: []string{"kubectl-client-side-apply", "kubectl-client-side-apply2"},
|
|
},
|
|
{
|
|
// Test with multiple fields to match against
|
|
Name: "BasicMultipleFields",
|
|
ManagedFieldsYAML: `
|
|
managedFields:
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
f:data:
|
|
.: {}
|
|
f:key: {}
|
|
f:legacy: {}
|
|
manager: kubectl-client-side-apply
|
|
operation: Update
|
|
time: "2022-08-23T23:08:23Z"
|
|
`,
|
|
Operation: metav1.ManagedFieldsOperationUpdate,
|
|
Fields: fieldpath.NewSet(
|
|
fieldpath.MakePathOrDie("data", "key"),
|
|
fieldpath.MakePathOrDie("metadata", "annotations", "kubectl.kubernetes.io/last-applied-configuration"),
|
|
),
|
|
Expectation: []string{"kubectl-client-side-apply"},
|
|
},
|
|
{
|
|
// Test with multiplle fields but the manager is missing one of the fields
|
|
// requested so it does not match
|
|
Name: "MissingOneField",
|
|
ManagedFieldsYAML: `
|
|
managedFields:
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
f:data:
|
|
.: {}
|
|
f:legacy: {}
|
|
manager: kubectl-client-side-apply
|
|
operation: Update
|
|
time: "2022-08-23T23:08:23Z"
|
|
`,
|
|
Operation: metav1.ManagedFieldsOperationUpdate,
|
|
Fields: fieldpath.NewSet(
|
|
fieldpath.MakePathOrDie("data", "key"),
|
|
fieldpath.MakePathOrDie("metadata", "annotations", "kubectl.kubernetes.io/last-applied-configuration"),
|
|
),
|
|
Expectation: []string{},
|
|
},
|
|
}
|
|
for _, tcase := range testCases {
|
|
t.Run(tcase.Name, func(t *testing.T) {
|
|
var entries struct {
|
|
ManagedFields []metav1.ManagedFieldsEntry `json:"managedFields"`
|
|
}
|
|
err := yaml.Unmarshal([]byte(tcase.ManagedFieldsYAML), &entries)
|
|
require.NoError(t, err)
|
|
|
|
result := csaupgrade.FindFieldsOwners(entries.ManagedFields, tcase.Operation, tcase.Fields)
|
|
|
|
// Compare owner names since they uniquely identify the selected entries
|
|
// (given that the operation is provided)
|
|
ownerNames := []string{}
|
|
for _, entry := range result {
|
|
ownerNames = append(ownerNames, entry.Manager)
|
|
require.Equal(t, tcase.Operation, entry.Operation)
|
|
}
|
|
require.ElementsMatch(t, tcase.Expectation, ownerNames)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUpgradeCSA(t *testing.T) {
|
|
|
|
cases := []struct {
|
|
Name string
|
|
CSAManagers []string
|
|
SSAManager string
|
|
Options []csaupgrade.Option
|
|
OriginalObject []byte
|
|
ExpectedObject []byte
|
|
}{
|
|
{
|
|
// Case where there is a CSA entry with the given name, but no SSA entry
|
|
// is found. Expect that the CSA entry is converted to an SSA entry
|
|
// and renamed.
|
|
Name: "csa-basic-direct-conversion",
|
|
CSAManagers: []string{"kubectl-client-side-apply"},
|
|
SSAManager: "kubectl",
|
|
OriginalObject: []byte(`
|
|
apiVersion: v1
|
|
data: {}
|
|
kind: ConfigMap
|
|
metadata:
|
|
resourceVersion: "1"
|
|
annotations:
|
|
kubectl.kubernetes.io/last-applied-configuration: |
|
|
{"apiVersion":"v1","data":{"key":"value","legacy":"unused"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"test","namespace":"default"}}
|
|
creationTimestamp: "2022-08-22T23:08:23Z"
|
|
managedFields:
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:data:
|
|
.: {}
|
|
f:key: {}
|
|
f:legacy: {}
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
manager: kubectl-client-side-apply
|
|
operation: Update
|
|
time: "2022-08-22T23:08:23Z"
|
|
name: test
|
|
namespace: default
|
|
`),
|
|
ExpectedObject: []byte(`
|
|
apiVersion: v1
|
|
data: {}
|
|
kind: ConfigMap
|
|
metadata:
|
|
resourceVersion: "1"
|
|
annotations:
|
|
kubectl.kubernetes.io/last-applied-configuration: |
|
|
{"apiVersion":"v1","data":{"key":"value","legacy":"unused"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"test","namespace":"default"}}
|
|
creationTimestamp: "2022-08-22T23:08:23Z"
|
|
managedFields:
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:data:
|
|
.: {}
|
|
f:key: {}
|
|
f:legacy: {}
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
manager: kubectl
|
|
operation: Apply
|
|
time: "2022-08-22T23:08:23Z"
|
|
name: test
|
|
namespace: default
|
|
`),
|
|
},
|
|
{
|
|
// This is the case when kubectl --server-side is used for the first time
|
|
// Server creates duplicate managed fields entry - one for Update and another
|
|
// for Apply. Expect entries to be merged into one entry, which is unchanged
|
|
// from initial SSA.
|
|
Name: "csa-combine-with-ssa-duplicate-keys",
|
|
CSAManagers: []string{"kubectl-client-side-apply"},
|
|
SSAManager: "kubectl",
|
|
OriginalObject: []byte(`
|
|
apiVersion: v1
|
|
data: {}
|
|
kind: ConfigMap
|
|
metadata:
|
|
resourceVersion: "1"
|
|
annotations:
|
|
kubectl.kubernetes.io/last-applied-configuration: |
|
|
{"apiVersion":"v1","data":{"key":"value","legacy":"unused"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"test","namespace":"default"}}
|
|
creationTimestamp: "2022-08-22T23:08:23Z"
|
|
managedFields:
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:data:
|
|
.: {}
|
|
f:key: {}
|
|
f:legacy: {}
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
manager: kubectl
|
|
operation: Apply
|
|
time: "2022-08-23T23:08:23Z"
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:data:
|
|
.: {}
|
|
f:key: {}
|
|
f:legacy: {}
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
manager: kubectl-client-side-apply
|
|
operation: Update
|
|
time: "2022-08-22T23:08:23Z"
|
|
name: test
|
|
namespace: default
|
|
`),
|
|
ExpectedObject: []byte(`
|
|
apiVersion: v1
|
|
data: {}
|
|
kind: ConfigMap
|
|
metadata:
|
|
resourceVersion: "1"
|
|
annotations:
|
|
kubectl.kubernetes.io/last-applied-configuration: |
|
|
{"apiVersion":"v1","data":{"key":"value","legacy":"unused"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"test","namespace":"default"}}
|
|
creationTimestamp: "2022-08-22T23:08:23Z"
|
|
managedFields:
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:data:
|
|
.: {}
|
|
f:key: {}
|
|
f:legacy: {}
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
manager: kubectl
|
|
operation: Apply
|
|
time: "2022-08-23T23:08:23Z"
|
|
name: test
|
|
namespace: default
|
|
`),
|
|
},
|
|
{
|
|
// This is the case when kubectl --server-side is used for the first time,
|
|
// but then a key is removed. A bug would take place where key is left in
|
|
// CSA entry but no longer present in SSA entry, so it would not be pruned.
|
|
// This shows that upgrading such an object results in correct behavior next
|
|
// time SSA applier
|
|
// Expect final object to have unioned keys from both entries
|
|
Name: "csa-combine-with-ssa-additional-keys",
|
|
CSAManagers: []string{"kubectl-client-side-apply"},
|
|
SSAManager: "kubectl",
|
|
OriginalObject: []byte(`
|
|
apiVersion: v1
|
|
data: {}
|
|
kind: ConfigMap
|
|
metadata:
|
|
resourceVersion: "1"
|
|
annotations:
|
|
kubectl.kubernetes.io/last-applied-configuration: |
|
|
{"apiVersion":"v1","data":{"key":"value","legacy":"unused"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"test","namespace":"default"}}
|
|
creationTimestamp: "2022-08-22T23:08:23Z"
|
|
managedFields:
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:data:
|
|
.: {}
|
|
f:key: {}
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
manager: kubectl
|
|
operation: Apply
|
|
time: "2022-08-23T23:08:23Z"
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:data:
|
|
.: {}
|
|
f:key: {}
|
|
f:legacy: {}
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
manager: kubectl-client-side-apply
|
|
operation: Update
|
|
time: "2022-08-22T23:08:23Z"
|
|
name: test
|
|
namespace: default
|
|
`),
|
|
ExpectedObject: []byte(`
|
|
apiVersion: v1
|
|
data: {}
|
|
kind: ConfigMap
|
|
metadata:
|
|
resourceVersion: "1"
|
|
annotations:
|
|
kubectl.kubernetes.io/last-applied-configuration: |
|
|
{"apiVersion":"v1","data":{"key":"value","legacy":"unused"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"test","namespace":"default"}}
|
|
creationTimestamp: "2022-08-22T23:08:23Z"
|
|
managedFields:
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:data:
|
|
.: {}
|
|
f:key: {}
|
|
f:legacy: {}
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
manager: kubectl
|
|
operation: Apply
|
|
time: "2022-08-23T23:08:23Z"
|
|
name: test
|
|
namespace: default
|
|
`),
|
|
},
|
|
{
|
|
// Case when there are multiple CSA versions on the object which do not
|
|
// match the version from the apply entry. Shows they are tossed away
|
|
// without being merged.
|
|
Name: "csa-no-applicable-version",
|
|
CSAManagers: []string{"kubectl-client-side-apply"},
|
|
SSAManager: "kubectl",
|
|
OriginalObject: []byte(`
|
|
apiVersion: v1
|
|
data: {}
|
|
kind: ConfigMap
|
|
metadata:
|
|
resourceVersion: "1"
|
|
annotations:
|
|
kubectl.kubernetes.io/last-applied-configuration: |
|
|
{"apiVersion":"v1","data":{"key":"value","legacy":"unused"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"test","namespace":"default"}}
|
|
creationTimestamp: "2022-08-22T23:08:23Z"
|
|
managedFields:
|
|
- apiVersion: v5
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:data:
|
|
.: {}
|
|
f:key: {}
|
|
f:legacy: {}
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
manager: kubectl
|
|
operation: Apply
|
|
time: "2022-08-23T23:08:23Z"
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:data:
|
|
f:key2: {}
|
|
f:metadata:
|
|
f:annotations:
|
|
f:hello2: {}
|
|
manager: kubectl-client-side-apply
|
|
operation: Update
|
|
time: "2022-08-22T23:08:23Z"
|
|
- apiVersion: v2
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:data:
|
|
f:key3: {}
|
|
f:metadata:
|
|
f:annotations:
|
|
f:hello3: {}
|
|
manager: kubectl-client-side-apply
|
|
operation: Update
|
|
time: "2022-08-22T23:08:23Z"
|
|
- apiVersion: v3
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:data:
|
|
f:key4: {}
|
|
f:metadata:
|
|
f:annotations:
|
|
f:hello3: {}
|
|
manager: kubectl-client-side-apply
|
|
operation: Update
|
|
time: "2022-08-22T23:08:23Z"
|
|
- apiVersion: v4
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:data:
|
|
f:key5: {}
|
|
f:metadata:
|
|
f:annotations:
|
|
f:hello4: {}
|
|
manager: kubectl-client-side-apply
|
|
operation: Update
|
|
time: "2022-08-22T23:08:23Z"
|
|
name: test
|
|
namespace: default
|
|
`),
|
|
ExpectedObject: []byte(`
|
|
apiVersion: v1
|
|
data: {}
|
|
kind: ConfigMap
|
|
metadata:
|
|
resourceVersion: "1"
|
|
annotations:
|
|
kubectl.kubernetes.io/last-applied-configuration: |
|
|
{"apiVersion":"v1","data":{"key":"value","legacy":"unused"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"test","namespace":"default"}}
|
|
creationTimestamp: "2022-08-22T23:08:23Z"
|
|
managedFields:
|
|
- apiVersion: v5
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:data:
|
|
.: {}
|
|
f:key: {}
|
|
f:legacy: {}
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
manager: kubectl
|
|
operation: Apply
|
|
time: "2022-08-23T23:08:23Z"
|
|
name: test
|
|
namespace: default
|
|
`),
|
|
},
|
|
{
|
|
// Case when there are multiple CSA versions on the object which do not
|
|
// match the version from the apply entry, and one which does.
|
|
// Shows that CSA entry with matching version is unioned into the SSA entry.
|
|
Name: "csa-single-applicable-version",
|
|
CSAManagers: []string{"kubectl-client-side-apply"},
|
|
SSAManager: "kubectl",
|
|
OriginalObject: []byte(`
|
|
apiVersion: v1
|
|
data: {}
|
|
kind: ConfigMap
|
|
metadata:
|
|
resourceVersion: "1"
|
|
annotations:
|
|
kubectl.kubernetes.io/last-applied-configuration: |
|
|
{"apiVersion":"v1","data":{"key":"value","legacy":"unused"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"test","namespace":"default"}}
|
|
creationTimestamp: "2022-08-22T23:08:23Z"
|
|
managedFields:
|
|
- apiVersion: v5
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:data:
|
|
.: {}
|
|
f:key: {}
|
|
f:legacy: {}
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
manager: kubectl
|
|
operation: Apply
|
|
time: "2022-08-23T23:08:23Z"
|
|
- apiVersion: v5
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:data:
|
|
f:key2: {}
|
|
f:metadata:
|
|
f:annotations:
|
|
f:hello2: {}
|
|
manager: kubectl-client-side-apply
|
|
operation: Update
|
|
time: "2022-08-22T23:08:23Z"
|
|
- apiVersion: v2
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:data:
|
|
f:key3: {}
|
|
f:metadata:
|
|
f:annotations:
|
|
f:hello3: {}
|
|
manager: kubectl-client-side-apply
|
|
operation: Update
|
|
time: "2022-08-22T23:08:23Z"
|
|
- apiVersion: v3
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:data:
|
|
f:key4: {}
|
|
f:metadata:
|
|
f:annotations:
|
|
f:hello4: {}
|
|
manager: kubectl-client-side-apply
|
|
operation: Update
|
|
time: "2022-08-22T23:08:23Z"
|
|
- apiVersion: v4
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:data:
|
|
f:key5: {}
|
|
f:metadata:
|
|
f:annotations:
|
|
f:hello5: {}
|
|
manager: kubectl-client-side-apply
|
|
operation: Update
|
|
time: "2022-08-22T23:08:23Z"
|
|
name: test
|
|
namespace: default
|
|
`),
|
|
ExpectedObject: []byte(`
|
|
apiVersion: v1
|
|
data: {}
|
|
kind: ConfigMap
|
|
metadata:
|
|
resourceVersion: "1"
|
|
annotations:
|
|
kubectl.kubernetes.io/last-applied-configuration: |
|
|
{"apiVersion":"v1","data":{"key":"value","legacy":"unused"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"test","namespace":"default"}}
|
|
creationTimestamp: "2022-08-22T23:08:23Z"
|
|
managedFields:
|
|
- apiVersion: v5
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:data:
|
|
.: {}
|
|
f:key: {}
|
|
f:key2: {}
|
|
f:legacy: {}
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:hello2: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
manager: kubectl
|
|
operation: Apply
|
|
time: "2022-08-23T23:08:23Z"
|
|
name: test
|
|
namespace: default
|
|
`),
|
|
},
|
|
{
|
|
// Do nothing to object with nothing to migrate and no existing SSA manager
|
|
Name: "noop",
|
|
CSAManagers: []string{"kubectl-client-side-apply"},
|
|
SSAManager: "not-already-in-object",
|
|
OriginalObject: []byte(`
|
|
apiVersion: v1
|
|
data: {}
|
|
kind: ConfigMap
|
|
metadata:
|
|
resourceVersion: "1"
|
|
annotations:
|
|
kubectl.kubernetes.io/last-applied-configuration: |
|
|
{"apiVersion":"v1","data":{"key":"value","legacy":"unused"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"test","namespace":"default"}}
|
|
creationTimestamp: "2022-08-22T23:08:23Z"
|
|
managedFields:
|
|
- apiVersion: v5
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:data:
|
|
.: {}
|
|
f:key: {}
|
|
f:legacy: {}
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
manager: kubectl
|
|
operation: Apply
|
|
time: "2022-08-23T23:08:23Z"
|
|
name: test
|
|
namespace: default
|
|
`),
|
|
ExpectedObject: []byte(`
|
|
apiVersion: v1
|
|
data: {}
|
|
kind: ConfigMap
|
|
metadata:
|
|
resourceVersion: "1"
|
|
annotations:
|
|
kubectl.kubernetes.io/last-applied-configuration: |
|
|
{"apiVersion":"v1","data":{"key":"value","legacy":"unused"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"test","namespace":"default"}}
|
|
creationTimestamp: "2022-08-22T23:08:23Z"
|
|
managedFields:
|
|
- apiVersion: v5
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:data:
|
|
.: {}
|
|
f:key: {}
|
|
f:legacy: {}
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
manager: kubectl
|
|
operation: Apply
|
|
time: "2022-08-23T23:08:23Z"
|
|
name: test
|
|
namespace: default
|
|
`),
|
|
},
|
|
{
|
|
// Expect multiple targets to be merged into existing ssa manager
|
|
Name: "multipleTargetsExisting",
|
|
CSAManagers: []string{"kube-scheduler", "kubectl-client-side-apply"},
|
|
SSAManager: "kubectl",
|
|
OriginalObject: []byte(`
|
|
apiVersion: v1
|
|
data: {}
|
|
kind: ConfigMap
|
|
metadata:
|
|
resourceVersion: "1"
|
|
annotations:
|
|
kubectl.kubernetes.io/last-applied-configuration: |
|
|
{"apiVersion":"v1","data":{"key":"value","legacy":"unused"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"test","namespace":"default"}}
|
|
creationTimestamp: "2022-08-22T23:08:23Z"
|
|
managedFields:
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:metadata:
|
|
f:labels:
|
|
f:name: {}
|
|
f:spec:
|
|
f:containers:
|
|
k:{"name":"kubernetes-pause"}:
|
|
.: {}
|
|
f:image: {}
|
|
f:name: {}
|
|
manager: kubectl
|
|
operation: Apply
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:status:
|
|
f:conditions:
|
|
.: {}
|
|
k:{"type":"PodScheduled"}:
|
|
.: {}
|
|
f:lastProbeTime: {}
|
|
f:lastTransitionTime: {}
|
|
f:message: {}
|
|
f:reason: {}
|
|
f:status: {}
|
|
f:type: {}
|
|
manager: kube-scheduler
|
|
operation: Update
|
|
time: "2022-11-03T23:22:40Z"
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
f:labels:
|
|
.: {}
|
|
f:name: {}
|
|
f:spec:
|
|
f:containers:
|
|
k:{"name":"kubernetes-pause"}:
|
|
.: {}
|
|
f:image: {}
|
|
f:imagePullPolicy: {}
|
|
f:name: {}
|
|
f:resources: {}
|
|
f:terminationMessagePath: {}
|
|
f:terminationMessagePolicy: {}
|
|
f:dnsPolicy: {}
|
|
f:enableServiceLinks: {}
|
|
f:restartPolicy: {}
|
|
f:schedulerName: {}
|
|
f:securityContext: {}
|
|
f:terminationGracePeriodSeconds: {}
|
|
manager: kubectl-client-side-apply
|
|
operation: Update
|
|
time: "2022-11-03T23:22:40Z"
|
|
name: test
|
|
namespace: default
|
|
`),
|
|
ExpectedObject: []byte(`
|
|
apiVersion: v1
|
|
data: {}
|
|
kind: ConfigMap
|
|
metadata:
|
|
resourceVersion: "1"
|
|
annotations:
|
|
kubectl.kubernetes.io/last-applied-configuration: |
|
|
{"apiVersion":"v1","data":{"key":"value","legacy":"unused"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"test","namespace":"default"}}
|
|
creationTimestamp: "2022-08-22T23:08:23Z"
|
|
managedFields:
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:status:
|
|
f:conditions:
|
|
.: {}
|
|
k:{"type":"PodScheduled"}:
|
|
.: {}
|
|
f:lastProbeTime: {}
|
|
f:lastTransitionTime: {}
|
|
f:message: {}
|
|
f:reason: {}
|
|
f:status: {}
|
|
f:type: {}
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
f:labels:
|
|
.: {}
|
|
f:name: {}
|
|
f:spec:
|
|
f:containers:
|
|
k:{"name":"kubernetes-pause"}:
|
|
.: {}
|
|
f:image: {}
|
|
f:imagePullPolicy: {}
|
|
f:name: {}
|
|
f:resources: {}
|
|
f:terminationMessagePath: {}
|
|
f:terminationMessagePolicy: {}
|
|
f:dnsPolicy: {}
|
|
f:enableServiceLinks: {}
|
|
f:restartPolicy: {}
|
|
f:schedulerName: {}
|
|
f:securityContext: {}
|
|
f:terminationGracePeriodSeconds: {}
|
|
manager: kubectl
|
|
operation: Apply
|
|
name: test
|
|
namespace: default
|
|
`),
|
|
},
|
|
{
|
|
// Expect multiple targets to be merged into a new ssa manager
|
|
Name: "multipleTargetsNewInsertion",
|
|
CSAManagers: []string{"kubectl-client-side-apply", "kube-scheduler"},
|
|
SSAManager: "newly-inserted-manager",
|
|
OriginalObject: []byte(`
|
|
apiVersion: v1
|
|
data: {}
|
|
kind: ConfigMap
|
|
metadata:
|
|
resourceVersion: "1"
|
|
annotations:
|
|
kubectl.kubernetes.io/last-applied-configuration: |
|
|
{"apiVersion":"v1","data":{"key":"value","legacy":"unused"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"test","namespace":"default"}}
|
|
creationTimestamp: "2022-08-22T23:08:23Z"
|
|
managedFields:
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:metadata:
|
|
f:labels:
|
|
f:name: {}
|
|
f:spec:
|
|
f:containers:
|
|
k:{"name":"kubernetes-pause"}:
|
|
.: {}
|
|
f:image: {}
|
|
f:name: {}
|
|
manager: kubectl
|
|
operation: Apply
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:status:
|
|
f:conditions:
|
|
.: {}
|
|
k:{"type":"PodScheduled"}:
|
|
.: {}
|
|
f:lastProbeTime: {}
|
|
f:lastTransitionTime: {}
|
|
f:message: {}
|
|
f:reason: {}
|
|
f:status: {}
|
|
f:type: {}
|
|
manager: kube-scheduler
|
|
operation: Update
|
|
time: "2022-11-03T23:22:40Z"
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
f:labels:
|
|
.: {}
|
|
f:name: {}
|
|
f:spec:
|
|
f:containers:
|
|
k:{"name":"kubernetes-pause"}:
|
|
.: {}
|
|
f:image: {}
|
|
f:imagePullPolicy: {}
|
|
f:name: {}
|
|
f:resources: {}
|
|
f:terminationMessagePath: {}
|
|
f:terminationMessagePolicy: {}
|
|
f:dnsPolicy: {}
|
|
f:enableServiceLinks: {}
|
|
f:restartPolicy: {}
|
|
f:schedulerName: {}
|
|
f:securityContext: {}
|
|
f:terminationGracePeriodSeconds: {}
|
|
manager: kubectl-client-side-apply
|
|
operation: Update
|
|
time: "2022-11-03T23:22:40Z"
|
|
name: test
|
|
namespace: default
|
|
`),
|
|
ExpectedObject: []byte(`
|
|
apiVersion: v1
|
|
data: {}
|
|
kind: ConfigMap
|
|
metadata:
|
|
resourceVersion: "1"
|
|
annotations:
|
|
kubectl.kubernetes.io/last-applied-configuration: |
|
|
{"apiVersion":"v1","data":{"key":"value","legacy":"unused"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"test","namespace":"default"}}
|
|
creationTimestamp: "2022-08-22T23:08:23Z"
|
|
managedFields:
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:metadata:
|
|
f:labels:
|
|
f:name: {}
|
|
f:spec:
|
|
f:containers:
|
|
k:{"name":"kubernetes-pause"}:
|
|
.: {}
|
|
f:image: {}
|
|
f:name: {}
|
|
manager: kubectl
|
|
operation: Apply
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:kubectl.kubernetes.io/last-applied-configuration: {}
|
|
f:labels:
|
|
.: {}
|
|
f:name: {}
|
|
f:spec:
|
|
f:containers:
|
|
k:{"name":"kubernetes-pause"}:
|
|
.: {}
|
|
f:image: {}
|
|
f:imagePullPolicy: {}
|
|
f:name: {}
|
|
f:resources: {}
|
|
f:terminationMessagePath: {}
|
|
f:terminationMessagePolicy: {}
|
|
f:dnsPolicy: {}
|
|
f:enableServiceLinks: {}
|
|
f:restartPolicy: {}
|
|
f:schedulerName: {}
|
|
f:securityContext: {}
|
|
f:terminationGracePeriodSeconds: {}
|
|
f:status:
|
|
f:conditions:
|
|
.: {}
|
|
k:{"type":"PodScheduled"}:
|
|
.: {}
|
|
f:lastProbeTime: {}
|
|
f:lastTransitionTime: {}
|
|
f:message: {}
|
|
f:reason: {}
|
|
f:status: {}
|
|
f:type: {}
|
|
manager: newly-inserted-manager
|
|
operation: Apply
|
|
time: "2022-11-03T23:22:40Z"
|
|
name: test
|
|
namespace: default
|
|
`),
|
|
},
|
|
{
|
|
// Expect multiple targets to be merged into a new ssa manager
|
|
Name: "subresource",
|
|
CSAManagers: []string{"kube-controller-manager"},
|
|
SSAManager: "kube-controller-manager",
|
|
Options: []csaupgrade.Option{csaupgrade.Subresource("status")},
|
|
OriginalObject: []byte(`
|
|
apiVersion: v1
|
|
kind: PersistentVolumeClaim
|
|
metadata:
|
|
annotations:
|
|
pv.kubernetes.io/bind-completed: "yes"
|
|
pv.kubernetes.io/bound-by-controller: "yes"
|
|
volume.beta.kubernetes.io/storage-provisioner: openshift-storage.cephfs.csi.ceph.com
|
|
volume.kubernetes.io/storage-provisioner: openshift-storage.cephfs.csi.ceph.com
|
|
creationTimestamp: "2024-02-24T15:24:31Z"
|
|
finalizers:
|
|
- kubernetes.io/pvc-protection
|
|
managedFields:
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:spec:
|
|
f:accessModes: {}
|
|
f:resources:
|
|
f:requests:
|
|
.: {}
|
|
f:storage: {}
|
|
f:storageClassName: {}
|
|
f:volumeMode: {}
|
|
manager: Mozilla
|
|
operation: Update
|
|
time: "2024-02-24T15:24:31Z"
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:pv.kubernetes.io/bind-completed: {}
|
|
f:pv.kubernetes.io/bound-by-controller: {}
|
|
f:volume.beta.kubernetes.io/storage-provisioner: {}
|
|
f:volume.kubernetes.io/storage-provisioner: {}
|
|
f:spec:
|
|
f:volumeName: {}
|
|
manager: kube-controller-manager
|
|
operation: Update
|
|
time: "2024-02-24T15:24:32Z"
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:status:
|
|
f:accessModes: {}
|
|
f:capacity:
|
|
.: {}
|
|
f:storage: {}
|
|
f:phase: {}
|
|
manager: kube-controller-manager
|
|
operation: Update
|
|
subresource: status
|
|
time: "2024-02-24T15:24:32Z"
|
|
name: test
|
|
namespace: default
|
|
resourceVersion: "948647140"
|
|
uid: f0692a61-0ffe-4fd5-b00f-0b95f3654fb9
|
|
spec:
|
|
accessModes:
|
|
- ReadWriteOnce
|
|
resources:
|
|
requests:
|
|
storage: 1Gi
|
|
storageClassName: ocs-storagecluster-cephfs
|
|
volumeMode: Filesystem
|
|
volumeName: pvc-f0692a61-0ffe-4fd5-b00f-0b95f3654fb9
|
|
status:
|
|
accessModes:
|
|
- ReadWriteOnce
|
|
capacity:
|
|
storage: 1Gi
|
|
phase: Bound
|
|
`),
|
|
ExpectedObject: []byte(`
|
|
apiVersion: v1
|
|
kind: PersistentVolumeClaim
|
|
metadata:
|
|
annotations:
|
|
pv.kubernetes.io/bind-completed: "yes"
|
|
pv.kubernetes.io/bound-by-controller: "yes"
|
|
volume.beta.kubernetes.io/storage-provisioner: openshift-storage.cephfs.csi.ceph.com
|
|
volume.kubernetes.io/storage-provisioner: openshift-storage.cephfs.csi.ceph.com
|
|
creationTimestamp: "2024-02-24T15:24:31Z"
|
|
finalizers:
|
|
- kubernetes.io/pvc-protection
|
|
managedFields:
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:spec:
|
|
f:accessModes: {}
|
|
f:resources:
|
|
f:requests:
|
|
.: {}
|
|
f:storage: {}
|
|
f:storageClassName: {}
|
|
f:volumeMode: {}
|
|
manager: Mozilla
|
|
operation: Update
|
|
time: "2024-02-24T15:24:31Z"
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:metadata:
|
|
f:annotations:
|
|
.: {}
|
|
f:pv.kubernetes.io/bind-completed: {}
|
|
f:pv.kubernetes.io/bound-by-controller: {}
|
|
f:volume.beta.kubernetes.io/storage-provisioner: {}
|
|
f:volume.kubernetes.io/storage-provisioner: {}
|
|
f:spec:
|
|
f:volumeName: {}
|
|
manager: kube-controller-manager
|
|
operation: Update
|
|
time: "2024-02-24T15:24:32Z"
|
|
- apiVersion: v1
|
|
fieldsType: FieldsV1
|
|
fieldsV1:
|
|
f:status:
|
|
f:accessModes: {}
|
|
f:capacity:
|
|
.: {}
|
|
f:storage: {}
|
|
f:phase: {}
|
|
manager: kube-controller-manager
|
|
operation: Apply
|
|
subresource: status
|
|
time: "2024-02-24T15:24:32Z"
|
|
name: test
|
|
namespace: default
|
|
resourceVersion: "948647140"
|
|
uid: f0692a61-0ffe-4fd5-b00f-0b95f3654fb9
|
|
spec:
|
|
accessModes:
|
|
- ReadWriteOnce
|
|
resources:
|
|
requests:
|
|
storage: 1Gi
|
|
storageClassName: ocs-storagecluster-cephfs
|
|
volumeMode: Filesystem
|
|
volumeName: pvc-f0692a61-0ffe-4fd5-b00f-0b95f3654fb9
|
|
status:
|
|
accessModes:
|
|
- ReadWriteOnce
|
|
capacity:
|
|
storage: 1Gi
|
|
phase: Bound
|
|
`),
|
|
},
|
|
}
|
|
|
|
for _, testCase := range cases {
|
|
t.Run(testCase.Name, func(t *testing.T) {
|
|
initialObject := unstructured.Unstructured{}
|
|
err := yaml.Unmarshal(testCase.OriginalObject, &initialObject.Object)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
upgraded := initialObject.DeepCopy()
|
|
err = csaupgrade.UpgradeManagedFields(
|
|
upgraded,
|
|
sets.New(testCase.CSAManagers...),
|
|
testCase.SSAManager,
|
|
testCase.Options...,
|
|
)
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expectedObject := unstructured.Unstructured{}
|
|
err = yaml.Unmarshal(testCase.ExpectedObject, &expectedObject.Object)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !reflect.DeepEqual(&expectedObject, upgraded) {
|
|
t.Fatal(cmp.Diff(&expectedObject, upgraded))
|
|
}
|
|
|
|
// Show that the UpgradeManagedFieldsPatch yields a patch that does
|
|
// nothing more and nothing less than make the object equal to output
|
|
// of UpgradeManagedFields
|
|
|
|
initialCopy := initialObject.DeepCopyObject()
|
|
patchBytes, err := csaupgrade.UpgradeManagedFieldsPatch(
|
|
initialCopy, sets.New(testCase.CSAManagers...), testCase.SSAManager, testCase.Options...)
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
} else if patchBytes != nil {
|
|
patch, err := jsonpatch.DecodePatch(patchBytes)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
initialJSON, err := json.Marshal(initialObject.Object)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
patchedBytes, err := patch.Apply(initialJSON)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var patched unstructured.Unstructured
|
|
if err := json.Unmarshal(patchedBytes, &patched.Object); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !reflect.DeepEqual(&patched, upgraded) {
|
|
t.Fatalf("expected patch to produce an upgraded object: %v", cmp.Diff(patched, upgraded))
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|