mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
Add tests for managed fields tracking.
- Test that client-side apply users don't encounter a conflict with server-side apply for objects that previously didn't track managedFields - Test that we stop tracking managed fields with `managedFields: []` - Test that we stop tracking managed fields when the feature is disabled
This commit is contained in:
parent
382107e6c8
commit
f2deb2417a
@ -111,6 +111,7 @@ func NewTestFieldManager(gvk schema.GroupVersionKind, chainFieldManager func(fie
|
||||
f = fieldmanager.NewStripMetaManager(f)
|
||||
f = fieldmanager.NewManagedFieldsUpdater(f)
|
||||
f = fieldmanager.NewBuildManagerInfoManager(f, gvk.GroupVersion())
|
||||
f = fieldmanager.NewProbabilisticSkipNonAppliedManager(f, &fakeObjectCreater{gvk: gvk}, gvk, fieldmanager.DefaultTrackOnCreateProbability)
|
||||
f = fieldmanager.NewLastAppliedManager(f, typeConverter, objectConverter, gvk.GroupVersion())
|
||||
f = fieldmanager.NewLastAppliedUpdater(f)
|
||||
if chainFieldManager != nil {
|
||||
@ -1039,6 +1040,145 @@ spec:
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoTrackManagedFieldsForClientSideApply(t *testing.T) {
|
||||
f := NewDefaultTestFieldManager(schema.FromAPIVersionAndKind("apps/v1", "Deployment"))
|
||||
|
||||
// create object
|
||||
newObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
|
||||
deployment := []byte(`
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: my-deployment
|
||||
labels:
|
||||
app: my-app
|
||||
spec:
|
||||
replicas: 100
|
||||
`)
|
||||
if err := yaml.Unmarshal(deployment, &newObj.Object); err != nil {
|
||||
t.Errorf("error decoding YAML: %v", err)
|
||||
}
|
||||
if err := f.Update(newObj, "test_kubectl_create"); err != nil {
|
||||
t.Errorf("failed to update object: %v", err)
|
||||
}
|
||||
if m := f.ManagedFields(); len(m) == 0 {
|
||||
t.Errorf("expected to have managed fields, but got: %v", m)
|
||||
}
|
||||
|
||||
// stop tracking managed fields
|
||||
newObj = &unstructured.Unstructured{Object: map[string]interface{}{}}
|
||||
deployment = []byte(`
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: my-deployment
|
||||
managedFields: [] # stop tracking managed fields
|
||||
labels:
|
||||
app: my-app
|
||||
spec:
|
||||
replicas: 100
|
||||
`)
|
||||
if err := yaml.Unmarshal(deployment, &newObj.Object); err != nil {
|
||||
t.Errorf("error decoding YAML: %v", err)
|
||||
}
|
||||
newObj.SetUID("nonempty")
|
||||
if err := f.Update(newObj, "test_kubectl_replace"); err != nil {
|
||||
t.Errorf("failed to update object: %v", err)
|
||||
}
|
||||
if m := f.ManagedFields(); len(m) != 0 {
|
||||
t.Errorf("expected to have stop tracking managed fields, but got: %v", m)
|
||||
}
|
||||
|
||||
// check that we still don't track managed fields
|
||||
newObj = &unstructured.Unstructured{Object: map[string]interface{}{}}
|
||||
deployment = []byte(`
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: my-deployment
|
||||
labels:
|
||||
app: my-app
|
||||
spec:
|
||||
replicas: 100
|
||||
`)
|
||||
if err := yaml.Unmarshal(deployment, &newObj.Object); err != nil {
|
||||
t.Errorf("error decoding YAML: %v", err)
|
||||
}
|
||||
if err := setLastAppliedFromEncoded(newObj, deployment); err != nil {
|
||||
t.Errorf("failed to set last applied: %v", err)
|
||||
}
|
||||
if err := f.Update(newObj, "test_k_client_side_apply"); err != nil {
|
||||
t.Errorf("failed to update object: %v", err)
|
||||
}
|
||||
if m := f.ManagedFields(); len(m) != 0 {
|
||||
t.Errorf("expected to continue to not track managed fields, but got: %v", m)
|
||||
}
|
||||
lastApplied, err := getLastApplied(f.liveObj)
|
||||
if err != nil {
|
||||
t.Errorf("failed to get last applied: %v", err)
|
||||
}
|
||||
if !strings.Contains(lastApplied, "my-app") {
|
||||
t.Errorf("expected last applied annotation to be set properly, but got: %q", lastApplied)
|
||||
}
|
||||
|
||||
// start tracking managed fields
|
||||
newObj = &unstructured.Unstructured{Object: map[string]interface{}{}}
|
||||
deployment = []byte(`
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: my-deployment
|
||||
labels:
|
||||
app: my-app
|
||||
spec:
|
||||
replicas: 100
|
||||
`)
|
||||
if err := yaml.Unmarshal(deployment, &newObj.Object); err != nil {
|
||||
t.Errorf("error decoding YAML: %v", err)
|
||||
}
|
||||
if err := f.Apply(newObj, "test_server_side_apply_without_upgrade", false); err != nil {
|
||||
t.Errorf("error applying object: %v", err)
|
||||
}
|
||||
if m := f.ManagedFields(); len(m) < 2 {
|
||||
t.Errorf("expected to start tracking managed fields with at least 2 field managers, but got: %v", m)
|
||||
}
|
||||
if e, a := "test_server_side_apply_without_upgrade", f.ManagedFields()[0].Manager; e != a {
|
||||
t.Fatalf("exected first manager name to be %v, but got %v: %#v", e, a, f.ManagedFields())
|
||||
}
|
||||
if e, a := "before-first-apply", f.ManagedFields()[1].Manager; e != a {
|
||||
t.Fatalf("exected second manager name to be %v, but got %v: %#v", e, a, f.ManagedFields())
|
||||
}
|
||||
|
||||
// upgrade management of the object from client-side apply to server-side apply
|
||||
newObj = &unstructured.Unstructured{Object: map[string]interface{}{}}
|
||||
deployment = []byte(`
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: my-deployment
|
||||
labels:
|
||||
app: my-app-v2 # change
|
||||
spec:
|
||||
replicas: 8 # change
|
||||
`)
|
||||
if err := yaml.Unmarshal(deployment, &newObj.Object); err != nil {
|
||||
t.Errorf("error decoding YAML: %v", err)
|
||||
}
|
||||
if err := f.Apply(newObj, "kubectl", false); err != nil {
|
||||
t.Errorf("error applying object: %v", err)
|
||||
}
|
||||
if m := f.ManagedFields(); len(m) == 0 {
|
||||
t.Errorf("expected to track managed fields, but got: %v", m)
|
||||
}
|
||||
lastApplied, err = getLastApplied(f.liveObj)
|
||||
if err != nil {
|
||||
t.Errorf("failed to get last applied: %v", err)
|
||||
}
|
||||
if !strings.Contains(lastApplied, "my-app-v2") {
|
||||
t.Errorf("expected last applied annotation to be updated, but got: %q", lastApplied)
|
||||
}
|
||||
}
|
||||
|
||||
func yamlToJSON(y []byte) (string, error) {
|
||||
obj := &unstructured.Unstructured{Object: map[string]interface{}{}}
|
||||
if err := yaml.Unmarshal(y, &obj.Object); err != nil {
|
||||
|
@ -1635,6 +1635,16 @@ func TestClearManagedFieldsWithUpdateEmptyList(t *testing.T) {
|
||||
t.Fatalf("Failed to patch object: %v", err)
|
||||
}
|
||||
|
||||
_, err = client.CoreV1().RESTClient().Patch(types.MergePatchType).
|
||||
Namespace("default").
|
||||
Resource("configmaps").
|
||||
Name("test-cm").
|
||||
Body([]byte(`{"metadata":{"labels": { "test-label": "v1" }}}`)).Do(context.TODO()).Get()
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to patch object: %v", err)
|
||||
}
|
||||
|
||||
object, err := client.CoreV1().RESTClient().Get().Namespace("default").Resource("configmaps").Name("test-cm").Do(context.TODO()).Get()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to retrieve object: %v", err)
|
||||
@ -1646,7 +1656,7 @@ func TestClearManagedFieldsWithUpdateEmptyList(t *testing.T) {
|
||||
}
|
||||
|
||||
if managedFields := accessor.GetManagedFields(); len(managedFields) != 0 {
|
||||
t.Fatalf("Failed to clear managedFields, got: %v", managedFields)
|
||||
t.Fatalf("Failed to stop tracking managedFields, got: %v", managedFields)
|
||||
}
|
||||
|
||||
if labels := accessor.GetLabels(); len(labels) < 1 {
|
||||
@ -2595,3 +2605,103 @@ spec:
|
||||
t.Fatalf("expected to get obj with image %s, but got %s", "my-image-new", deploymentObj.Spec.Template.Spec.Containers[0].Image)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStopTrackingManagedFieldsOnFeatureDisabled(t *testing.T) {
|
||||
sharedEtcd := framework.DefaultEtcdOptions()
|
||||
masterConfig := framework.NewIntegrationTestMasterConfigWithOptions(&framework.MasterConfigOptions{
|
||||
EtcdOptions: sharedEtcd,
|
||||
})
|
||||
masterConfig.GenericConfig.OpenAPIConfig = framework.DefaultOpenAPIConfig()
|
||||
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, genericfeatures.ServerSideApply, true)()
|
||||
_, master, closeFn := framework.RunAMaster(masterConfig)
|
||||
client, err := clientset.NewForConfig(&restclient.Config{Host: master.URL, QPS: -1})
|
||||
if err != nil {
|
||||
t.Fatalf("Error in create clientset: %v", err)
|
||||
}
|
||||
|
||||
obj := []byte(`
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: my-deployment
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: my-app
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: my-app
|
||||
spec:
|
||||
containers:
|
||||
- name: my-c
|
||||
image: my-image
|
||||
`)
|
||||
|
||||
deployment, err := yamlutil.ToJSON(obj)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed marshal yaml: %v", err)
|
||||
}
|
||||
_, err = client.CoreV1().RESTClient().Patch(types.ApplyPatchType).
|
||||
AbsPath("/apis/apps/v1").
|
||||
Namespace("default").
|
||||
Resource("deployments").
|
||||
Name("my-deployment").
|
||||
Param("fieldManager", "kubectl").
|
||||
Body(deployment).
|
||||
Do(context.TODO()).
|
||||
Get()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to apply object: %v", err)
|
||||
}
|
||||
|
||||
deploymentObj, err := client.AppsV1().Deployments("default").Get(context.TODO(), "my-deployment", metav1.GetOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get object: %v", err)
|
||||
}
|
||||
if managed := deploymentObj.GetManagedFields(); managed == nil {
|
||||
t.Errorf("object doesn't have managedFields")
|
||||
}
|
||||
|
||||
// Restart server with server-side apply disabled
|
||||
closeFn()
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, genericfeatures.ServerSideApply, false)()
|
||||
_, master, closeFn = framework.RunAMaster(masterConfig)
|
||||
client, err = clientset.NewForConfig(&restclient.Config{Host: master.URL, QPS: -1})
|
||||
if err != nil {
|
||||
t.Fatalf("Error in create clientset: %v", err)
|
||||
}
|
||||
defer closeFn()
|
||||
|
||||
_, err = client.CoreV1().RESTClient().Patch(types.ApplyPatchType).
|
||||
AbsPath("/apis/apps/v1").
|
||||
Namespace("default").
|
||||
Resource("deployments").
|
||||
Name("my-deployment").
|
||||
Param("fieldManager", "kubectl").
|
||||
Body(deployment).
|
||||
Do(context.TODO()).
|
||||
Get()
|
||||
if err == nil {
|
||||
t.Errorf("expected to fail to apply object, but succeeded")
|
||||
}
|
||||
|
||||
_, err = client.CoreV1().RESTClient().Patch(types.MergePatchType).
|
||||
AbsPath("/apis/apps/v1").
|
||||
Namespace("default").
|
||||
Resource("deployments").
|
||||
Name("my-deployment").
|
||||
Body([]byte(`{"metadata":{"labels": { "app": "v1" }}}`)).Do(context.TODO()).Get()
|
||||
if err != nil {
|
||||
t.Errorf("failed to update object: %v", err)
|
||||
}
|
||||
|
||||
deploymentObj, err = client.AppsV1().Deployments("default").Get(context.TODO(), "my-deployment", metav1.GetOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get object: %v", err)
|
||||
}
|
||||
if managed := deploymentObj.GetManagedFields(); managed != nil {
|
||||
t.Errorf("object has unexpected managedFields: %v", managed)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user