...

Source file src/k8s.io/apimachinery/pkg/util/managedfields/internal/managedfieldsupdater_test.go

Documentation: k8s.io/apimachinery/pkg/util/managedfields/internal

     1  /*
     2  Copyright 2020 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package internal_test
    18  
    19  import (
    20  	"fmt"
    21  	"reflect"
    22  	"testing"
    23  	"time"
    24  
    25  	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/util/managedfields/managedfieldstest"
    27  
    28  	"k8s.io/apimachinery/pkg/api/meta"
    29  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    30  	"k8s.io/apimachinery/pkg/runtime"
    31  	"k8s.io/apimachinery/pkg/runtime/schema"
    32  	"k8s.io/apimachinery/pkg/util/managedfields/internal"
    33  	"sigs.k8s.io/yaml"
    34  )
    35  
    36  func TestManagedFieldsUpdateDoesModifyTime(t *testing.T) {
    37  	var err error
    38  	f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("v1", "ConfigMap"))
    39  
    40  	err = updateObject(f, "fieldmanager_test", []byte(`{
    41  		"apiVersion": "v1",
    42  		"kind": "ConfigMap",
    43  		"metadata": {
    44  			"name": "configmap"
    45  		},
    46  		"data": {
    47  			"key": "value"
    48  		}
    49  	}`))
    50  	if err != nil {
    51  		t.Fatal(err)
    52  	}
    53  	previousManagedFields := f.ManagedFields()
    54  
    55  	time.Sleep(time.Second)
    56  
    57  	err = updateObject(f, "fieldmanager_test", []byte(`{
    58  		"apiVersion": "v1",
    59  		"kind": "ConfigMap",
    60  		"metadata": {
    61  			"name": "configmap"
    62  		},
    63  		"data": {
    64  			"key": "new-value"
    65  		}
    66  	}`))
    67  	if err != nil {
    68  		t.Fatal(err)
    69  	}
    70  	newManagedFields := f.ManagedFields()
    71  
    72  	if previousManagedFields[0].Time.Equal(newManagedFields[0].Time) {
    73  		t.Errorf("ManagedFields time has not been updated:\n%v", newManagedFields)
    74  	}
    75  }
    76  
    77  func TestManagedFieldsApplyDoesModifyTime(t *testing.T) {
    78  	var err error
    79  	f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("v1", "ConfigMap"))
    80  
    81  	err = applyObject(f, "fieldmanager_test", []byte(`{
    82  		"apiVersion": "v1",
    83  		"kind": "ConfigMap",
    84  		"metadata": {
    85  			"name": "configmap"
    86  		},
    87  		"data": {
    88  			"key": "value"
    89  		}
    90  	}`))
    91  	if err != nil {
    92  		t.Fatal(err)
    93  	}
    94  	previousManagedFields := f.ManagedFields()
    95  
    96  	time.Sleep(time.Second)
    97  
    98  	err = applyObject(f, "fieldmanager_test", []byte(`{
    99  		"apiVersion": "v1",
   100  		"kind": "ConfigMap",
   101  		"metadata": {
   102  			"name": "configmap"
   103  		},
   104  		"data": {
   105  			"key": "new-value"
   106  		}
   107  	}`))
   108  	if err != nil {
   109  		t.Fatal(err)
   110  	}
   111  	newManagedFields := f.ManagedFields()
   112  
   113  	if previousManagedFields[0].Time.Equal(newManagedFields[0].Time) {
   114  		t.Errorf("ManagedFields time has not been updated:\n%v", newManagedFields)
   115  	}
   116  }
   117  
   118  func TestManagedFieldsUpdateWithoutChangesDoesNotModifyTime(t *testing.T) {
   119  	var err error
   120  	f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("v1", "ConfigMap"))
   121  
   122  	err = updateObject(f, "fieldmanager_test", []byte(`{
   123  		"apiVersion": "v1",
   124  		"kind": "ConfigMap",
   125  		"metadata": {
   126  			"name": "configmap"
   127  		},
   128  		"data": {
   129  			"key": "value"
   130  		}
   131  	}`))
   132  	if err != nil {
   133  		t.Fatal(err)
   134  	}
   135  	previousManagedFields := f.ManagedFields()
   136  
   137  	time.Sleep(time.Second)
   138  
   139  	err = updateObject(f, "fieldmanager_test", []byte(`{
   140  		"apiVersion": "v1",
   141  		"kind": "ConfigMap",
   142  		"metadata": {
   143  			"name": "configmap"
   144  		},
   145  		"data": {
   146  			"key": "value"
   147  		}
   148  	}`))
   149  	if err != nil {
   150  		t.Fatal(err)
   151  	}
   152  	newManagedFields := f.ManagedFields()
   153  
   154  	if !previousManagedFields[0].Time.Equal(newManagedFields[0].Time) {
   155  		t.Errorf("ManagedFields time has changed:\nBefore:\n%v\nAfter:\n%v", previousManagedFields, newManagedFields)
   156  	}
   157  }
   158  
   159  func TestManagedFieldsApplyWithoutChangesDoesNotModifyTime(t *testing.T) {
   160  	var err error
   161  	f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("v1", "ConfigMap"))
   162  
   163  	err = applyObject(f, "fieldmanager_test", []byte(`{
   164  		"apiVersion": "v1",
   165  		"kind": "ConfigMap",
   166  		"metadata": {
   167  			"name": "configmap"
   168  		},
   169  		"data": {
   170  			"key": "value"
   171  		}
   172  	}`))
   173  	if err != nil {
   174  		t.Fatal(err)
   175  	}
   176  	previousManagedFields := f.ManagedFields()
   177  
   178  	time.Sleep(time.Second)
   179  
   180  	err = applyObject(f, "fieldmanager_test", []byte(`{
   181  		"apiVersion": "v1",
   182  		"kind": "ConfigMap",
   183  		"metadata": {
   184  			"name": "configmap"
   185  		},
   186  		"data": {
   187  			"key": "value"
   188  		}
   189  	}`))
   190  	if err != nil {
   191  		t.Fatal(err)
   192  	}
   193  	newManagedFields := f.ManagedFields()
   194  
   195  	if !previousManagedFields[0].Time.Equal(newManagedFields[0].Time) {
   196  		t.Errorf("ManagedFields time has changed:\nBefore:\n%v\nAfter:\n%v", previousManagedFields, newManagedFields)
   197  	}
   198  }
   199  
   200  func TestNonManagedFieldsUpdateDoesNotModifyTime(t *testing.T) {
   201  	var err error
   202  	f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("v1", "ConfigMap"))
   203  
   204  	err = updateObject(f, "fieldmanager_a_test", []byte(`{
   205  		"apiVersion": "v1",
   206  		"kind": "ConfigMap",
   207  		"metadata": {
   208  			"name": "configmap"
   209  		},
   210  		"data": {
   211  			"key_a": "value"
   212  		}
   213  	}`))
   214  	if err != nil {
   215  		t.Fatal(err)
   216  	}
   217  	err = updateObject(f, "fieldmanager_b_test", []byte(`{
   218  		"apiVersion": "v1",
   219  		"kind": "ConfigMap",
   220  		"metadata": {
   221  			"name": "configmap"
   222  		},
   223  		"data": {
   224  			"key_b": "value"
   225  		}
   226  	}`))
   227  	if err != nil {
   228  		t.Fatal(err)
   229  	}
   230  	previousManagedFields := f.ManagedFields()
   231  	previousEntries := map[string]v1.ManagedFieldsEntry{}
   232  	for _, entry := range previousManagedFields {
   233  		previousEntries[entry.Manager] = entry
   234  	}
   235  
   236  	time.Sleep(time.Second)
   237  
   238  	err = updateObject(f, "fieldmanager_a_test", []byte(`{
   239  		"apiVersion": "v1",
   240  		"kind": "ConfigMap",
   241  		"metadata": {
   242  			"name": "configmap"
   243  		},
   244  		"data": {
   245  			"key_a": "value",
   246  			"key_b": "new-value"
   247  		}
   248  	}`))
   249  	if err != nil {
   250  		t.Fatal(err)
   251  	}
   252  	newManagedFields := f.ManagedFields()
   253  	newEntries := map[string]v1.ManagedFieldsEntry{}
   254  	for _, entry := range newManagedFields {
   255  		newEntries[entry.Manager] = entry
   256  	}
   257  
   258  	if _, ok := newEntries["fieldmanager_b_test"]; ok {
   259  		t.Errorf("FieldManager B ManagedFields has changed:\n%v", newEntries["fieldmanager_b_test"])
   260  	}
   261  }
   262  
   263  func TestNonManagedFieldsApplyDoesNotModifyTime(t *testing.T) {
   264  	var err error
   265  	f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("v1", "ConfigMap"))
   266  
   267  	err = applyObject(f, "fieldmanager_a_test", []byte(`{
   268  		"apiVersion": "v1",
   269  		"kind": "ConfigMap",
   270  		"metadata": {
   271  			"name": "configmap"
   272  		},
   273  		"data": {
   274  			"key_a": "value"
   275  		}
   276  	}`))
   277  	if err != nil {
   278  		t.Fatal(err)
   279  	}
   280  	err = applyObject(f, "fieldmanager_b_test", []byte(`{
   281  		"apiVersion": "v1",
   282  		"kind": "ConfigMap",
   283  		"metadata": {
   284  			"name": "configmap"
   285  		},
   286  		"data": {
   287  			"key_b": "value"
   288  		}
   289  	}`))
   290  	if err != nil {
   291  		t.Fatal(err)
   292  	}
   293  	previousManagedFields := f.ManagedFields()
   294  	previousEntries := map[string]v1.ManagedFieldsEntry{}
   295  	for _, entry := range previousManagedFields {
   296  		previousEntries[entry.Manager] = entry
   297  	}
   298  
   299  	time.Sleep(time.Second)
   300  
   301  	err = applyObject(f, "fieldmanager_a_test", []byte(`{
   302  		"apiVersion": "v1",
   303  		"kind": "ConfigMap",
   304  		"metadata": {
   305  			"name": "configmap"
   306  		},
   307  		"data": {
   308  			"key_a": "new-value"
   309  		}
   310  	}`))
   311  	if err != nil {
   312  		t.Fatal(err)
   313  	}
   314  	newManagedFields := f.ManagedFields()
   315  	newEntries := map[string]v1.ManagedFieldsEntry{}
   316  	for _, entry := range newManagedFields {
   317  		newEntries[entry.Manager] = entry
   318  	}
   319  
   320  	if !previousEntries["fieldmanager_b_test"].Time.Equal(newEntries["fieldmanager_b_test"].Time) {
   321  		t.Errorf("FieldManager B ManagedFields time changed:\nBefore:\n%v\nAfter:\n%v",
   322  			previousEntries["fieldmanager_b_test"], newEntries["fieldmanager_b_test"])
   323  	}
   324  }
   325  
   326  func TestTakingOverManagedFieldsDuringUpdateDoesNotModifyPreviousManagerTime(t *testing.T) {
   327  	var err error
   328  	f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("v1", "ConfigMap"))
   329  
   330  	err = updateObject(f, "fieldmanager_a_test", []byte(`{
   331  		"apiVersion": "v1",
   332  		"kind": "ConfigMap",
   333  		"metadata": {
   334  			"name": "configmap"
   335  		},
   336  		"data": {
   337  			"key_a": "value",
   338  			"key_b": value"
   339  		}
   340  	}`))
   341  	if err != nil {
   342  		t.Fatal(err)
   343  	}
   344  	previousManagedFields := f.ManagedFields()
   345  	previousEntries := map[string]v1.ManagedFieldsEntry{}
   346  	for _, entry := range previousManagedFields {
   347  		previousEntries[entry.Manager] = entry
   348  	}
   349  
   350  	time.Sleep(time.Second)
   351  
   352  	err = updateObject(f, "fieldmanager_b_test", []byte(`{
   353  		"apiVersion": "v1",
   354  		"kind": "ConfigMap",
   355  		"metadata": {
   356  			"name": "configmap"
   357  		},
   358  		"data": {
   359  			"key_b": "new-value"
   360  		}
   361  	}`))
   362  	if err != nil {
   363  		t.Fatal(err)
   364  	}
   365  	newManagedFields := f.ManagedFields()
   366  	newEntries := map[string]v1.ManagedFieldsEntry{}
   367  	for _, entry := range newManagedFields {
   368  		newEntries[entry.Manager] = entry
   369  	}
   370  
   371  	if !previousEntries["fieldmanager_a_test"].Time.Equal(newEntries["fieldmanager_a_test"].Time) {
   372  		t.Errorf("FieldManager A ManagedFields time has been updated:\nBefore:\n%v\nAfter:\n%v",
   373  			previousEntries["fieldmanager_a_test"], newEntries["fieldmanager_a_test"])
   374  	}
   375  }
   376  
   377  func TestTakingOverManagedFieldsDuringApplyDoesNotModifyPreviousManagerTime(t *testing.T) {
   378  	var err error
   379  	f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("v1", "ConfigMap"))
   380  
   381  	err = applyObject(f, "fieldmanager_a_test", []byte(`{
   382  		"apiVersion": "v1",
   383  		"kind": "ConfigMap",
   384  		"metadata": {
   385  			"name": "configmap"
   386  		},
   387  		"data": {
   388  			"key_a": "value",
   389  			"key_b": value"
   390  		}
   391  	}`))
   392  	if err != nil {
   393  		t.Fatal(err)
   394  	}
   395  	previousManagedFields := f.ManagedFields()
   396  	previousEntries := map[string]v1.ManagedFieldsEntry{}
   397  	for _, entry := range previousManagedFields {
   398  		previousEntries[entry.Manager] = entry
   399  	}
   400  
   401  	time.Sleep(time.Second)
   402  
   403  	err = applyObject(f, "fieldmanager_b_test", []byte(`{
   404  		"apiVersion": "v1",
   405  		"kind": "ConfigMap",
   406  		"metadata": {
   407  			"name": "configmap"
   408  		},
   409  		"data": {
   410  			"key_b": "new-value"
   411  		}
   412  	}`))
   413  	if err != nil {
   414  		t.Fatal(err)
   415  	}
   416  	newManagedFields := f.ManagedFields()
   417  	newEntries := map[string]v1.ManagedFieldsEntry{}
   418  	for _, entry := range newManagedFields {
   419  		newEntries[entry.Manager] = entry
   420  	}
   421  
   422  	if !previousEntries["fieldmanager_a_test"].Time.Equal(newEntries["fieldmanager_a_test"].Time) {
   423  		t.Errorf("FieldManager A ManagedFields time has been updated:\nBefore:\n%v\nAfter:\n%v",
   424  			previousEntries["fieldmanager_a_test"], newEntries["fieldmanager_a_test"])
   425  	}
   426  }
   427  
   428  type NoopManager struct{}
   429  
   430  func (NoopManager) Apply(liveObj, appliedObj runtime.Object, managed internal.Managed, fieldManager string, force bool) (runtime.Object, internal.Managed, error) {
   431  	return nil, managed, nil
   432  }
   433  
   434  func (NoopManager) Update(liveObj, newObj runtime.Object, managed internal.Managed, manager string) (runtime.Object, internal.Managed, error) {
   435  	return nil, nil, nil
   436  }
   437  
   438  func updateObject(f managedfieldstest.TestFieldManager, fieldManagerName string, object []byte) error {
   439  	obj := &unstructured.Unstructured{Object: map[string]interface{}{}}
   440  	if err := yaml.Unmarshal(object, &obj.Object); err != nil {
   441  		return fmt.Errorf("error decoding YAML: %v", err)
   442  	}
   443  	if err := f.Update(obj, fieldManagerName); err != nil {
   444  		return fmt.Errorf("failed to update object: %v", err)
   445  	}
   446  	return nil
   447  }
   448  
   449  func applyObject(f managedfieldstest.TestFieldManager, fieldManagerName string, object []byte) error {
   450  	obj := &unstructured.Unstructured{Object: map[string]interface{}{}}
   451  	if err := yaml.Unmarshal(object, &obj.Object); err != nil {
   452  		return fmt.Errorf("error decoding YAML: %v", err)
   453  	}
   454  	if err := f.Apply(obj, fieldManagerName, true); err != nil {
   455  		return fmt.Errorf("failed to apply object: %v", err)
   456  	}
   457  	return nil
   458  }
   459  
   460  // Ensures that if ManagedFieldsUpdater gets a nil value from its nested manager
   461  // chain (meaning the operation was a no-op), then the ManagedFieldsUpdater
   462  // itself will return a copy of the input live object, with its managed fields
   463  // removed
   464  func TestNilNewObjectReplacedWithDeepCopyExcludingManagedFields(t *testing.T) {
   465  	// Initialize our "live object" with some managed fields
   466  	obj := &unstructured.Unstructured{Object: map[string]interface{}{}}
   467  	if err := yaml.Unmarshal([]byte(`{
   468  		"apiVersion": "v1",
   469  		"kind": "Pod",
   470  		"metadata": {
   471  			"name": "pod",
   472  			"labels": {"app": "nginx"},
   473  			"managedFields": [
   474  				{
   475  					"apiVersion": "v1",
   476  					"fieldsType": "FieldsV1",
   477  					"fieldsV1": {
   478  						"f:metadata": {
   479  							"f:labels": {
   480  								"f:app": {}
   481  							}
   482  						}
   483  					},
   484  					"manager": "fieldmanager_test",
   485  					"operation": "Apply",
   486  					"time": "2021-11-11T18:41:17Z"
   487  				}
   488  			]
   489  		}
   490  	}`), &obj.Object); err != nil {
   491  		t.Fatalf("error decoding YAML: %v", err)
   492  	}
   493  
   494  	accessor, err := meta.Accessor(obj)
   495  	if err != nil {
   496  		t.Fatalf("couldn't get accessor: %v", err)
   497  	}
   498  
   499  	// Decode the managed fields in the live object, since it isn't allowed in the patch.
   500  	managed, err := internal.DecodeManagedFields(accessor.GetManagedFields())
   501  	if err != nil {
   502  		t.Fatalf("failed to decode managed fields: %v", err)
   503  	}
   504  
   505  	updater := internal.NewManagedFieldsUpdater(NoopManager{})
   506  
   507  	newObject, _, err := updater.Apply(obj, obj.DeepCopyObject(), managed, "some_manager", false)
   508  	if err != nil {
   509  		t.Fatalf("failed to apply configuration %v", err)
   510  	}
   511  
   512  	if newObject == obj {
   513  		t.Fatalf("returned newObject must not be the same instance as the passed in liveObj")
   514  	}
   515  
   516  	// Rip off managed fields of live, and check that it is deeply
   517  	// equal to newObject
   518  	liveWithoutManaged := obj.DeepCopyObject()
   519  	internal.RemoveObjectManagedFields(liveWithoutManaged)
   520  
   521  	if !reflect.DeepEqual(liveWithoutManaged, newObject) {
   522  		t.Fatalf("returned newObject must be deeply equal to the input live object, without managed fields")
   523  	}
   524  }
   525  

View as plain text