@@ -296,28 +296,28 @@ func TestApplyUpdateApplyConflictForced(t *testing.T) {
296
296
"kind": "Deployment",
297
297
"metadata": {
298
298
"name": "deployment",
299
- "labels": {"app": "nginx"}
299
+ "labels": {"app": "nginx"}
300
300
},
301
301
"spec": {
302
- "replicas": 3,
303
- "selector": {
304
- "matchLabels": {
305
- "app": "nginx"
306
- }
307
- },
308
- "template": {
309
- "metadata": {
310
- "labels": {
311
- "app": "nginx"
312
- }
313
- },
314
- "spec": {
315
- "containers": [{
316
- "name": "nginx",
317
- "image": "nginx:latest"
318
- }]
319
- }
320
- }
302
+ "replicas": 3,
303
+ "selector": {
304
+ "matchLabels": {
305
+ "app": "nginx"
306
+ }
307
+ },
308
+ "template": {
309
+ "metadata": {
310
+ "labels": {
311
+ "app": "nginx"
312
+ }
313
+ },
314
+ "spec": {
315
+ "containers": [{
316
+ "name": "nginx",
317
+ "image": "nginx:latest"
318
+ }]
319
+ }
320
+ }
321
321
}
322
322
}` )
323
323
@@ -1873,6 +1873,125 @@ func TestApplyUnsetSharedFields(t *testing.T) {
1873
1873
}
1874
1874
}
1875
1875
1876
+ // TestApplyCanTransferFieldOwnershipToController verifies that when an applier creates an
1877
+ // object, a controller takes ownership of a field, and the applier
1878
+ // then omits the field from its applied configuration, that the field value persists.
1879
+ func TestApplyCanTransferFieldOwnershipToController (t * testing.T ) {
1880
+ defer featuregatetesting .SetFeatureGateDuringTest (t , utilfeature .DefaultFeatureGate , genericfeatures .ServerSideApply , true )()
1881
+
1882
+ _ , client , closeFn := setup (t )
1883
+ defer closeFn ()
1884
+
1885
+ // Applier creates a deployment with replicas set to 3
1886
+ apply := []byte (`{
1887
+ "apiVersion": "apps/v1",
1888
+ "kind": "Deployment",
1889
+ "metadata": {
1890
+ "name": "deployment-shared-map-item-removal",
1891
+ "labels": {"app": "nginx"}
1892
+ },
1893
+ "spec": {
1894
+ "replicas": 3,
1895
+ "selector": {
1896
+ "matchLabels": {
1897
+ "app": "nginx"
1898
+ }
1899
+ },
1900
+ "template": {
1901
+ "metadata": {
1902
+ "labels": {
1903
+ "app": "nginx"
1904
+ }
1905
+ },
1906
+ "spec": {
1907
+ "containers": [{
1908
+ "name": "nginx",
1909
+ "image": "nginx:latest",
1910
+ }]
1911
+ }
1912
+ }
1913
+ }
1914
+ }` )
1915
+
1916
+ appliedObj , err := client .CoreV1 ().RESTClient ().Patch (types .ApplyPatchType ).
1917
+ AbsPath ("/apis/apps/v1" ).
1918
+ Namespace ("default" ).
1919
+ Resource ("deployments" ).
1920
+ Name ("deployment-shared-map-item-removal" ).
1921
+ Param ("fieldManager" , "test_applier" ).
1922
+ Body (apply ).
1923
+ Do (context .TODO ()).
1924
+ Get ()
1925
+ if err != nil {
1926
+ t .Fatalf ("Failed to create object using Apply patch: %v" , err )
1927
+ }
1928
+
1929
+ // a controller takes over the replicas field
1930
+ applied , ok := appliedObj .(* appsv1.Deployment )
1931
+ if ! ok {
1932
+ t .Fatalf ("Failed to convert response object to Deployment" )
1933
+ }
1934
+ replicas := int32 (4 )
1935
+ applied .Spec .Replicas = & replicas
1936
+ _ , err = client .AppsV1 ().Deployments ("default" ).
1937
+ Update (context .TODO (), applied , metav1.UpdateOptions {FieldManager : "test_updater" })
1938
+ if err != nil {
1939
+ t .Fatalf ("Failed to create object using Apply patch: %v" , err )
1940
+ }
1941
+
1942
+ // applier omits replicas
1943
+ apply = []byte (`{
1944
+ "apiVersion": "apps/v1",
1945
+ "kind": "Deployment",
1946
+ "metadata": {
1947
+ "name": "deployment-shared-map-item-removal",
1948
+ "labels": {"app": "nginx"}
1949
+ },
1950
+ "spec": {
1951
+ "selector": {
1952
+ "matchLabels": {
1953
+ "app": "nginx"
1954
+ }
1955
+ },
1956
+ "template": {
1957
+ "metadata": {
1958
+ "labels": {
1959
+ "app": "nginx"
1960
+ }
1961
+ },
1962
+ "spec": {
1963
+ "containers": [{
1964
+ "name": "nginx",
1965
+ "image": "nginx:latest",
1966
+ }]
1967
+ }
1968
+ }
1969
+ }
1970
+ }` )
1971
+
1972
+ patched , err := client .CoreV1 ().RESTClient ().Patch (types .ApplyPatchType ).
1973
+ AbsPath ("/apis/apps/v1" ).
1974
+ Namespace ("default" ).
1975
+ Resource ("deployments" ).
1976
+ Name ("deployment-shared-map-item-removal" ).
1977
+ Param ("fieldManager" , "test_applier" ).
1978
+ Body (apply ).
1979
+ Do (context .TODO ()).
1980
+ Get ()
1981
+ if err != nil {
1982
+ t .Fatalf ("Failed to create object using Apply patch: %v" , err )
1983
+ }
1984
+
1985
+ // ensure the container is deleted even though a controller updated a field of the container
1986
+ deployment , ok := patched .(* appsv1.Deployment )
1987
+ if ! ok {
1988
+ t .Fatalf ("Failed to convert response object to Deployment" )
1989
+ }
1990
+ if * deployment .Spec .Replicas != 4 {
1991
+ t .Errorf ("Expected deployment.spec.replicas to be 4, but got %d" , deployment .Spec .Replicas )
1992
+ }
1993
+ }
1994
+
1876
1995
// TestApplyCanRemoveMapItemsContributedToByControllers verifies that when an applier creates an
1877
1996
// object, a controller modifies the contents of the map item via update, and the applier
1878
1997
// then omits the item from its applied configuration, that the item is removed.
0 commit comments