@@ -18,9 +18,12 @@ package client_test
18
18
19
19
import (
20
20
"context"
21
+ "encoding/json"
21
22
"fmt"
22
23
"sync/atomic"
23
24
25
+ "k8s.io/apimachinery/pkg/types"
26
+
24
27
. "github.com/onsi/ginkgo"
25
28
. "github.com/onsi/gomega"
26
29
appsv1 "k8s.io/api/apps/v1"
@@ -62,6 +65,7 @@ var _ = Describe("Client", func() {
62
65
var count uint64 = 0
63
66
var replicaCount int32 = 2
64
67
var ns = "default"
68
+ var mergePatch []byte
65
69
66
70
BeforeEach (func (done Done ) {
67
71
atomic .AddUint64 (& count , 1 )
@@ -88,6 +92,15 @@ var _ = Describe("Client", func() {
88
92
Spec : corev1.NodeSpec {},
89
93
}
90
94
scheme = kscheme .Scheme
95
+ var err error
96
+ mergePatch , err = json .Marshal (map [string ]interface {}{
97
+ "metadata" : map [string ]interface {}{
98
+ "annotations" : map [string ]interface {}{
99
+ "foo" : "bar" ,
100
+ },
101
+ },
102
+ })
103
+ Expect (err ).NotTo (HaveOccurred ())
91
104
92
105
close (done )
93
106
}, serverSideTimeoutSeconds )
@@ -964,6 +977,224 @@ var _ = Describe("Client", func() {
964
977
})
965
978
})
966
979
980
+ Describe ("Patch" , func () {
981
+ Context ("with structured objects" , func () {
982
+ It ("should patch an existing object from a go struct" , func (done Done ) {
983
+ cl , err := client .New (cfg , client.Options {})
984
+ Expect (err ).NotTo (HaveOccurred ())
985
+ Expect (cl ).NotTo (BeNil ())
986
+
987
+ By ("initially creating a Deployment" )
988
+ dep , err := clientset .AppsV1 ().Deployments (ns ).Create (dep )
989
+ Expect (err ).NotTo (HaveOccurred ())
990
+
991
+ By ("patching the Deployment" )
992
+ err = cl .Patch (context .TODO (), dep , client .ConstantPatch (types .MergePatchType , mergePatch ))
993
+ Expect (err ).NotTo (HaveOccurred ())
994
+
995
+ By ("validating patched Deployment has new annotation" )
996
+ actual , err := clientset .AppsV1 ().Deployments (ns ).Get (dep .Name , metav1.GetOptions {})
997
+ Expect (err ).NotTo (HaveOccurred ())
998
+ Expect (actual ).NotTo (BeNil ())
999
+ Expect (actual .Annotations ["foo" ]).To (Equal ("bar" ))
1000
+
1001
+ close (done )
1002
+ })
1003
+
1004
+ It ("should patch an existing object non-namespace object from a go struct" , func (done Done ) {
1005
+ cl , err := client .New (cfg , client.Options {})
1006
+ Expect (err ).NotTo (HaveOccurred ())
1007
+ Expect (cl ).NotTo (BeNil ())
1008
+
1009
+ By ("initially creating a Node" )
1010
+ node , err := clientset .CoreV1 ().Nodes ().Create (node )
1011
+ Expect (err ).NotTo (HaveOccurred ())
1012
+
1013
+ By ("patching the Node" )
1014
+ nodeName := node .Name
1015
+ err = cl .Patch (context .TODO (), node , client .ConstantPatch (types .MergePatchType , mergePatch ))
1016
+ Expect (err ).NotTo (HaveOccurred ())
1017
+
1018
+ By ("validating the Node no longer exists" )
1019
+ actual , err := clientset .CoreV1 ().Nodes ().Get (nodeName , metav1.GetOptions {})
1020
+ Expect (err ).NotTo (HaveOccurred ())
1021
+ Expect (actual ).NotTo (BeNil ())
1022
+ Expect (actual .Annotations ["foo" ]).To (Equal ("bar" ))
1023
+
1024
+ close (done )
1025
+ })
1026
+
1027
+ It ("should fail if the object does not exists" , func (done Done ) {
1028
+ cl , err := client .New (cfg , client.Options {})
1029
+ Expect (err ).NotTo (HaveOccurred ())
1030
+ Expect (cl ).NotTo (BeNil ())
1031
+
1032
+ By ("Patching node before it is ever created" )
1033
+ err = cl .Patch (context .TODO (), node , client .ConstantPatch (types .MergePatchType , mergePatch ))
1034
+ Expect (err ).To (HaveOccurred ())
1035
+
1036
+ close (done )
1037
+ })
1038
+
1039
+ PIt ("should fail if the object doesn't have meta" , func () {
1040
+
1041
+ })
1042
+
1043
+ It ("should fail if the object cannot be mapped to a GVK" , func (done Done ) {
1044
+ By ("creating client with empty Scheme" )
1045
+ emptyScheme := runtime .NewScheme ()
1046
+ cl , err := client .New (cfg , client.Options {Scheme : emptyScheme })
1047
+ Expect (err ).NotTo (HaveOccurred ())
1048
+ Expect (cl ).NotTo (BeNil ())
1049
+
1050
+ By ("initially creating a Deployment" )
1051
+ dep , err := clientset .AppsV1 ().Deployments (ns ).Create (dep )
1052
+ Expect (err ).NotTo (HaveOccurred ())
1053
+
1054
+ By ("patching the Deployment fails" )
1055
+ err = cl .Patch (context .TODO (), dep , client .ConstantPatch (types .MergePatchType , mergePatch ))
1056
+ Expect (err ).To (HaveOccurred ())
1057
+ Expect (err .Error ()).To (ContainSubstring ("no kind is registered for the type" ))
1058
+
1059
+ close (done )
1060
+ })
1061
+
1062
+ PIt ("should fail if the GVK cannot be mapped to a Resource" , func () {
1063
+
1064
+ })
1065
+
1066
+ It ("should respect passed in update options" , func () {
1067
+ By ("creating a new client" )
1068
+ cl , err := client .New (cfg , client.Options {})
1069
+ Expect (err ).NotTo (HaveOccurred ())
1070
+ Expect (cl ).NotTo (BeNil ())
1071
+
1072
+ By ("initially creating a Deployment" )
1073
+ dep , err := clientset .AppsV1 ().Deployments (ns ).Create (dep )
1074
+ Expect (err ).NotTo (HaveOccurred ())
1075
+
1076
+ By ("patching the Deployment with dry-run" )
1077
+ err = cl .Patch (context .TODO (), dep , client .ConstantPatch (types .MergePatchType , mergePatch ), client .UpdatePatchWith (client .UpdateDryRunAll ()))
1078
+ Expect (err ).NotTo (HaveOccurred ())
1079
+
1080
+ By ("validating patched Deployment doesn't have the new annotation" )
1081
+ actual , err := clientset .AppsV1 ().Deployments (ns ).Get (dep .Name , metav1.GetOptions {})
1082
+ Expect (err ).NotTo (HaveOccurred ())
1083
+ Expect (actual ).NotTo (BeNil ())
1084
+ Expect (actual .Annotations ).NotTo (HaveKey ("foo" ))
1085
+ })
1086
+ })
1087
+ Context ("with unstructured objects" , func () {
1088
+ It ("should patch an existing object from a go struct" , func (done Done ) {
1089
+ cl , err := client .New (cfg , client.Options {})
1090
+ Expect (err ).NotTo (HaveOccurred ())
1091
+ Expect (cl ).NotTo (BeNil ())
1092
+
1093
+ By ("initially creating a Deployment" )
1094
+ dep , err := clientset .AppsV1 ().Deployments (ns ).Create (dep )
1095
+ Expect (err ).NotTo (HaveOccurred ())
1096
+
1097
+ By ("patching the Deployment" )
1098
+ depName := dep .Name
1099
+ u := & unstructured.Unstructured {}
1100
+ scheme .Convert (dep , u , nil )
1101
+ u .SetGroupVersionKind (schema.GroupVersionKind {
1102
+ Group : "apps" ,
1103
+ Kind : "Deployment" ,
1104
+ Version : "v1" ,
1105
+ })
1106
+ err = cl .Patch (context .TODO (), u , client .ConstantPatch (types .MergePatchType , mergePatch ))
1107
+ Expect (err ).NotTo (HaveOccurred ())
1108
+
1109
+ By ("validating patched Deployment has new annotation" )
1110
+ actual , err := clientset .AppsV1 ().Deployments (ns ).Get (depName , metav1.GetOptions {})
1111
+ Expect (err ).NotTo (HaveOccurred ())
1112
+ Expect (actual ).NotTo (BeNil ())
1113
+ Expect (actual .Annotations ["foo" ]).To (Equal ("bar" ))
1114
+
1115
+ close (done )
1116
+ })
1117
+
1118
+ It ("should patch an existing object non-namespace object from a go struct" , func (done Done ) {
1119
+ cl , err := client .New (cfg , client.Options {})
1120
+ Expect (err ).NotTo (HaveOccurred ())
1121
+ Expect (cl ).NotTo (BeNil ())
1122
+
1123
+ By ("initially creating a Node" )
1124
+ node , err := clientset .CoreV1 ().Nodes ().Create (node )
1125
+ Expect (err ).NotTo (HaveOccurred ())
1126
+
1127
+ By ("patching the Node" )
1128
+ nodeName := node .Name
1129
+ u := & unstructured.Unstructured {}
1130
+ scheme .Convert (node , u , nil )
1131
+ u .SetGroupVersionKind (schema.GroupVersionKind {
1132
+ Group : "" ,
1133
+ Kind : "Node" ,
1134
+ Version : "v1" ,
1135
+ })
1136
+ err = cl .Patch (context .TODO (), u , client .ConstantPatch (types .MergePatchType , mergePatch ))
1137
+ Expect (err ).NotTo (HaveOccurred ())
1138
+
1139
+ By ("validating pathed Node has new annotation" )
1140
+ actual , err := clientset .CoreV1 ().Nodes ().Get (nodeName , metav1.GetOptions {})
1141
+ Expect (err ).NotTo (HaveOccurred ())
1142
+ Expect (actual ).NotTo (BeNil ())
1143
+ Expect (actual .Annotations ["foo" ]).To (Equal ("bar" ))
1144
+
1145
+ close (done )
1146
+ })
1147
+
1148
+ It ("should fail if the object does not exist" , func (done Done ) {
1149
+ cl , err := client .New (cfg , client.Options {})
1150
+ Expect (err ).NotTo (HaveOccurred ())
1151
+ Expect (cl ).NotTo (BeNil ())
1152
+
1153
+ By ("Patching node before it is ever created" )
1154
+ u := & unstructured.Unstructured {}
1155
+ scheme .Convert (node , u , nil )
1156
+ u .SetGroupVersionKind (schema.GroupVersionKind {
1157
+ Group : "" ,
1158
+ Kind : "Node" ,
1159
+ Version : "v1" ,
1160
+ })
1161
+ err = cl .Patch (context .TODO (), node , client .ConstantPatch (types .MergePatchType , mergePatch ))
1162
+ Expect (err ).To (HaveOccurred ())
1163
+
1164
+ close (done )
1165
+ })
1166
+
1167
+ It ("should respect passed-in update options" , func () {
1168
+ By ("creating a new client" )
1169
+ cl , err := client .New (cfg , client.Options {})
1170
+ Expect (err ).NotTo (HaveOccurred ())
1171
+ Expect (cl ).NotTo (BeNil ())
1172
+
1173
+ By ("initially creating a Deployment" )
1174
+ dep , err := clientset .AppsV1 ().Deployments (ns ).Create (dep )
1175
+ Expect (err ).NotTo (HaveOccurred ())
1176
+
1177
+ By ("patching the Deployment" )
1178
+ depName := dep .Name
1179
+ u := & unstructured.Unstructured {}
1180
+ scheme .Convert (dep , u , nil )
1181
+ u .SetGroupVersionKind (schema.GroupVersionKind {
1182
+ Group : "apps" ,
1183
+ Kind : "Deployment" ,
1184
+ Version : "v1" ,
1185
+ })
1186
+ err = cl .Patch (context .TODO (), u , client .ConstantPatch (types .MergePatchType , mergePatch ), client .UpdatePatchWith (client .UpdateDryRunAll ()))
1187
+ Expect (err ).NotTo (HaveOccurred ())
1188
+
1189
+ By ("validating patched Deployment does not have the new annotation" )
1190
+ actual , err := clientset .AppsV1 ().Deployments (ns ).Get (depName , metav1.GetOptions {})
1191
+ Expect (err ).NotTo (HaveOccurred ())
1192
+ Expect (actual ).NotTo (BeNil ())
1193
+ Expect (actual .Annotations ).NotTo (HaveKey ("foo" ))
1194
+ })
1195
+ })
1196
+ })
1197
+
967
1198
Describe ("Get" , func () {
968
1199
Context ("with structured objects" , func () {
969
1200
It ("should fetch an existing object for a go struct" , func (done Done ) {
@@ -1984,6 +2215,46 @@ var _ = Describe("DelegatingReader", func() {
1984
2215
})
1985
2216
})
1986
2217
2218
+ var _ = Describe ("Patch" , func () {
2219
+ Describe ("CreateMergePatch" , func () {
2220
+ var cm * corev1.ConfigMap
2221
+
2222
+ BeforeEach (func () {
2223
+ cm = & corev1.ConfigMap {
2224
+ ObjectMeta : metav1.ObjectMeta {
2225
+ Namespace : metav1 .NamespaceDefault ,
2226
+ Name : "cm" ,
2227
+ },
2228
+ }
2229
+ })
2230
+
2231
+ It ("creates a merge patch with the modifications applied during the mutation" , func () {
2232
+ const (
2233
+ annotationKey = "test"
2234
+ annotationValue = "foo"
2235
+ )
2236
+
2237
+ By ("creating a merge patch" )
2238
+ patch := client .MergeFrom (cm .DeepCopy ())
2239
+
2240
+ By ("returning a patch with type MergePatch" )
2241
+ Expect (patch .Type ()).To (Equal (types .MergePatchType ))
2242
+
2243
+ By ("retrieving modifying the config map" )
2244
+ metav1 .SetMetaDataAnnotation (& cm .ObjectMeta , annotationKey , annotationValue )
2245
+
2246
+ By ("computing the patch data" )
2247
+ data , err := patch .Data (cm )
2248
+
2249
+ By ("returning no error" )
2250
+ Expect (err ).NotTo (HaveOccurred ())
2251
+
2252
+ By ("returning a patch with data only containing the annotation change" )
2253
+ Expect (data ).To (Equal ([]byte (fmt .Sprintf (`{"metadata":{"annotations":{"%s":"%s"}}}` , annotationKey , annotationValue ))))
2254
+ })
2255
+ })
2256
+ })
2257
+
1987
2258
type fakeReader struct {
1988
2259
Called int
1989
2260
}
0 commit comments