Skip to content

Commit 76648ff

Browse files
Like update, allow CLI create to clear resourceVersion
1 parent dbf28cb commit 76648ff

File tree

3 files changed

+110
-76
lines changed

3 files changed

+110
-76
lines changed

pkg/kubectl/cmd/create.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ Examples:
4747
client, err := f.Client(cmd, mapping)
4848
checkErr(err)
4949

50-
err = kubectl.NewRESTHelper(client, mapping).Create(namespace, data)
50+
err = kubectl.NewRESTHelper(client, mapping).Create(namespace, true, data)
5151
checkErr(err)
5252
fmt.Fprintf(out, "%s\n", name)
5353
},

pkg/kubectl/resthelper.go

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,37 @@ func (m *RESTHelper) Delete(namespace, name string) error {
5353
return m.RESTClient.Delete().Path(m.Resource).Namespace(namespace).Path(name).Do().Error()
5454
}
5555

56-
func (m *RESTHelper) Create(namespace string, data []byte) error {
57-
return m.RESTClient.Post().Path(m.Resource).Namespace(namespace).Body(data).Do().Error()
56+
func (m *RESTHelper) Create(namespace string, modify bool, data []byte) error {
57+
if modify {
58+
obj, err := m.Codec.Decode(data)
59+
if err != nil {
60+
// We don't know how to check a version on this object, but create it anyway
61+
return createResource(m.RESTClient, m.Resource, namespace, data)
62+
}
63+
64+
// Attempt to version the object based on client logic.
65+
version, err := m.Versioner.ResourceVersion(obj)
66+
if err != nil {
67+
// We don't know how to clear the version on this object, so send it to the server as is
68+
return createResource(m.RESTClient, m.Resource, namespace, data)
69+
}
70+
if version != "" {
71+
if err := m.Versioner.SetResourceVersion(obj, ""); err != nil {
72+
return err
73+
}
74+
newData, err := m.Codec.Encode(obj)
75+
if err != nil {
76+
return err
77+
}
78+
data = newData
79+
}
80+
}
81+
82+
return createResource(m.RESTClient, m.Resource, namespace, data)
83+
}
84+
85+
func createResource(c RESTClient, resourcePath, namespace string, data []byte) error {
86+
return c.Post().Path(resourcePath).Namespace(namespace).Body(data).Do().Error()
5887
}
5988

6089
func (m *RESTHelper) Update(namespace, name string, overwrite bool, data []byte) error {

pkg/kubectl/resthelper_test.go

Lines changed: 78 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -133,14 +133,28 @@ func TestRESTHelperDelete(t *testing.T) {
133133
}
134134

135135
func TestRESTHelperCreate(t *testing.T) {
136+
expectPost := func(req *http.Request) bool {
137+
if req.Method != "POST" {
138+
t.Errorf("unexpected method: %#v", req)
139+
return false
140+
}
141+
if req.URL.Query().Get("namespace") != "bar" {
142+
t.Errorf("url doesn't contain namespace: %#v", req)
143+
return false
144+
}
145+
return true
146+
}
147+
136148
tests := []struct {
137-
Resp *http.Response
138-
HttpErr error
139-
Object runtime.Object
149+
Resp *http.Response
150+
RespFunc httpClientFunc
151+
HttpErr error
152+
Modify bool
153+
Object runtime.Object
140154

141-
Err bool
142-
Data []byte
143-
Req func(*http.Request) bool
155+
ExpectObject runtime.Object
156+
Err bool
157+
Req func(*http.Request) bool
144158
}{
145159
{
146160
HttpErr: errors.New("failure"),
@@ -158,48 +172,65 @@ func TestRESTHelperCreate(t *testing.T) {
158172
StatusCode: http.StatusOK,
159173
Body: objBody(&api.Status{Status: api.StatusSuccess}),
160174
},
161-
Object: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}},
162-
Req: func(req *http.Request) bool {
163-
if req.Method != "POST" {
164-
t.Errorf("unexpected method: %#v", req)
165-
return false
166-
}
167-
if req.URL.Query().Get("namespace") != "bar" {
168-
t.Errorf("url doesn't contain namespace: %#v", req)
169-
return false
170-
}
171-
return true
172-
},
175+
Object: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}},
176+
ExpectObject: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}},
177+
Req: expectPost,
178+
},
179+
{
180+
Modify: false,
181+
Object: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "10"}},
182+
ExpectObject: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "10"}},
183+
Resp: &http.Response{StatusCode: http.StatusOK, Body: objBody(&api.Status{Status: api.StatusSuccess})},
184+
Req: expectPost,
185+
},
186+
{
187+
Modify: true,
188+
Object: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "10"}},
189+
ExpectObject: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}},
190+
Resp: &http.Response{StatusCode: http.StatusOK, Body: objBody(&api.Status{Status: api.StatusSuccess})},
191+
Req: expectPost,
173192
},
174193
}
175-
for _, test := range tests {
194+
for i, test := range tests {
176195
client := &FakeRESTClient{
177196
Resp: test.Resp,
178197
Err: test.HttpErr,
179198
}
199+
if test.RespFunc != nil {
200+
client.Client = test.RespFunc
201+
}
180202
modifier := &RESTHelper{
181203
RESTClient: client,
204+
Codec: testapi.Codec(),
205+
Versioner: testapi.MetadataAccessor(),
182206
}
183-
data := test.Data
207+
data := []byte{}
184208
if test.Object != nil {
185209
data = []byte(runtime.EncodeOrDie(testapi.Codec(), test.Object))
186210
}
187-
err := modifier.Create("bar", data)
211+
err := modifier.Create("bar", test.Modify, data)
188212
if (err != nil) != test.Err {
189-
t.Errorf("unexpected error: %f %v", test.Err, err)
213+
t.Errorf("%d: unexpected error: %f %v", i, test.Err, err)
190214
}
191215
if err != nil {
192216
continue
193217
}
194218
if test.Req != nil && !test.Req(client.Req) {
195-
t.Errorf("unexpected request: %#v", client.Req)
219+
t.Errorf("%d: unexpected request: %#v", i, client.Req)
196220
}
197-
if test.Data != nil {
198-
body, _ := ioutil.ReadAll(client.Req.Body)
199-
if !reflect.DeepEqual(test.Data, body) {
200-
t.Errorf("unexpected body: %s", string(body))
201-
}
221+
body, err := ioutil.ReadAll(client.Req.Body)
222+
if err != nil {
223+
t.Fatalf("%d: unexpected error: %#v", i, err)
224+
}
225+
t.Logf("got body: %s", string(body))
226+
expect := []byte{}
227+
if test.ExpectObject != nil {
228+
expect = []byte(runtime.EncodeOrDie(testapi.Codec(), test.ExpectObject))
202229
}
230+
if !reflect.DeepEqual(expect, body) {
231+
t.Errorf("%d: unexpected body: %s", i, string(body))
232+
}
233+
203234
}
204235
}
205236

@@ -268,6 +299,22 @@ func TestRESTHelperGet(t *testing.T) {
268299
}
269300

270301
func TestRESTHelperUpdate(t *testing.T) {
302+
expectPut := func(req *http.Request) bool {
303+
if req.Method != "PUT" {
304+
t.Errorf("unexpected method: %#v", req)
305+
return false
306+
}
307+
if !strings.HasSuffix(req.URL.Path, "/foo") {
308+
t.Errorf("url doesn't contain name: %#v", req)
309+
return false
310+
}
311+
if req.URL.Query().Get("namespace") != "bar" {
312+
t.Errorf("url doesn't contain namespace: %#v", req)
313+
return false
314+
}
315+
return true
316+
}
317+
271318
tests := []struct {
272319
Resp *http.Response
273320
RespFunc httpClientFunc
@@ -298,21 +345,7 @@ func TestRESTHelperUpdate(t *testing.T) {
298345
StatusCode: http.StatusOK,
299346
Body: objBody(&api.Status{Status: api.StatusSuccess}),
300347
},
301-
Req: func(req *http.Request) bool {
302-
if req.Method != "PUT" {
303-
t.Errorf("unexpected method: %#v", req)
304-
return false
305-
}
306-
if !strings.HasSuffix(req.URL.Path, "/foo") {
307-
t.Errorf("url doesn't contain name: %#v", req)
308-
return false
309-
}
310-
if req.URL.Query().Get("namespace") != "bar" {
311-
t.Errorf("url doesn't contain namespace: %#v", req)
312-
return false
313-
}
314-
return true
315-
},
348+
Req: expectPut,
316349
},
317350
{
318351
Object: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}},
@@ -325,41 +358,13 @@ func TestRESTHelperUpdate(t *testing.T) {
325358
}
326359
return &http.Response{StatusCode: http.StatusOK, Body: objBody(&api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "10"}})}, nil
327360
},
328-
Req: func(req *http.Request) bool {
329-
if req.Method != "PUT" {
330-
t.Errorf("unexpected method: %#v", req)
331-
return false
332-
}
333-
if !strings.HasSuffix(req.URL.Path, "/foo") {
334-
t.Errorf("url doesn't contain name: %#v", req)
335-
return false
336-
}
337-
if req.URL.Query().Get("namespace") != "bar" {
338-
t.Errorf("url doesn't contain namespace: %#v", req)
339-
return false
340-
}
341-
return true
342-
},
361+
Req: expectPut,
343362
},
344363
{
345364
Object: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "10"}},
346365
ExpectObject: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "10"}},
347366
Resp: &http.Response{StatusCode: http.StatusOK, Body: objBody(&api.Status{Status: api.StatusSuccess})},
348-
Req: func(req *http.Request) bool {
349-
if req.Method != "PUT" {
350-
t.Errorf("unexpected method: %#v", req)
351-
return false
352-
}
353-
if !strings.HasSuffix(req.URL.Path, "/foo") {
354-
t.Errorf("url doesn't contain name: %#v", req)
355-
return false
356-
}
357-
if req.URL.Query().Get("namespace") != "bar" {
358-
t.Errorf("url doesn't contain namespace: %#v", req)
359-
return false
360-
}
361-
return true
362-
},
367+
Req: expectPut,
363368
},
364369
}
365370
for i, test := range tests {

0 commit comments

Comments
 (0)