diff --git a/vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply.go b/vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply.go index c24f7d9d1355..61c32e99ff31 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply.go +++ b/vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply.go @@ -299,6 +299,7 @@ func RunApply(f cmdutil.Factory, cmd *cobra.Command, out, errOut io.Writer, opti decoder: decoder, mapping: info.Mapping, helper: helper, + clientFunc: f.UnstructuredClientForMapping, clientsetFunc: f.ClientSet, overwrite: overwrite, backOff: clockwork.NewRealClock(), @@ -492,7 +493,7 @@ func (p *pruner) prune(namespace string, mapping *meta.RESTMapping, shortOutput return err } if !p.dryRun { - if err := p.delete(namespace, name, mapping, c); err != nil { + if err := p.delete(namespace, name, mapping); err != nil { return err } } @@ -501,7 +502,12 @@ func (p *pruner) prune(namespace string, mapping *meta.RESTMapping, shortOutput return nil } -func (p *pruner) delete(namespace, name string, mapping *meta.RESTMapping, c resource.RESTClient) error { +func (p *pruner) delete(namespace, name string, mapping *meta.RESTMapping) error { + c, err := p.clientFunc(mapping) + if err != nil { + return err + } + return runDelete(namespace, name, mapping, c, nil, p.cascade, p.gracePeriod, p.clientsetFunc) } @@ -534,7 +540,11 @@ func runDelete(namespace, name string, mapping *meta.RESTMapping, c resource.RES } func (p *patcher) delete(namespace, name string) error { - return runDelete(namespace, name, p.mapping, nil, p.helper, p.cascade, p.gracePeriod, p.clientsetFunc) + c, err := p.clientFunc(p.mapping) + if err != nil { + return err + } + return runDelete(namespace, name, p.mapping, c, p.helper, p.cascade, p.gracePeriod, p.clientsetFunc) } type patcher struct { @@ -543,6 +553,7 @@ type patcher struct { mapping *meta.RESTMapping helper *resource.Helper + clientFunc resource.ClientMapperFunc clientsetFunc func() (internalclientset.Interface, error) overwrite bool diff --git a/vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply_test.go b/vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply_test.go index 9ccbbf478ce5..2ee03328cc43 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply_test.go +++ b/vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply_test.go @@ -33,6 +33,7 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + restclient "k8s.io/client-go/rest" "k8s.io/client-go/rest/fake" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/annotations" @@ -1015,3 +1016,103 @@ func checkPatchString(t *testing.T, req *http.Request) { t.Fatalf("patch annotation is not correct, expect:%s\n but got:%s\n", checkString, resultString) } } + +func TestForceApply(t *testing.T) { + initTestErrorHandler(t) + nameRC, currentRC := readAndAnnotateReplicationController(t, filenameRC) + pathRC := "/namespaces/test/replicationcontrollers/" + nameRC + pathRCList := "/namespaces/test/replicationcontrollers" + deleted := false + counts := map[string]int{} + expected := map[string]int{ + "getOk": 9, + "getNotFound": 1, + "getList": 1, + "patch": 6, + "delete": 1, + "put": 1, + "post": 1, + } + + f, tf, _, _ := cmdtesting.NewAPIFactory() + tf.Printer = &testPrinter{} + tf.UnstructuredClient = &fake.RESTClient{ + APIRegistry: api.Registry, + NegotiatedSerializer: unstructuredSerializer, + Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { + switch p, m := req.URL.Path, req.Method; { + case strings.HasSuffix(p, pathRC) && m == "GET": + if deleted { + counts["getNotFound"]++ + return &http.Response{StatusCode: 404, Header: defaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte{}))}, nil + } + counts["getOk"]++ + bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC)) + return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil + case strings.HasSuffix(p, pathRCList) && m == "GET": + counts["getList"]++ + rcObj := readUnstructuredFromFile(t, filenameRC) + list := &unstructured.UnstructuredList{ + Object: map[string]interface{}{ + "apiVersion": "v1", + "kind": "ReplicationControllerList", + }, + Items: []unstructured.Unstructured{*rcObj}, + } + listBytes, err := runtime.Encode(testapi.Default.Codec(), list) + if err != nil { + t.Fatal(err) + } + bodyRCList := ioutil.NopCloser(bytes.NewReader(listBytes)) + return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRCList}, nil + case strings.HasSuffix(p, pathRC) && m == "PATCH": + counts["patch"]++ + if counts["patch"] <= 6 { + statusErr := kubeerr.NewConflict(schema.GroupResource{Group: "", Resource: "rc"}, "test-rc", fmt.Errorf("the object has been modified. Please apply at first.")) + bodyBytes, _ := json.Marshal(statusErr) + bodyErr := ioutil.NopCloser(bytes.NewReader(bodyBytes)) + return &http.Response{StatusCode: http.StatusConflict, Header: defaultHeader(), Body: bodyErr}, nil + } + t.Fatalf("unexpected request: %#v after %v tries\n%#v", req.URL, counts["patch"], req) + return nil, nil + case strings.HasSuffix(p, pathRC) && m == "DELETE": + counts["delete"]++ + deleted = true + return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte{}))}, nil + case strings.HasSuffix(p, pathRC) && m == "PUT": + counts["put"]++ + bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC)) + return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil + case strings.HasSuffix(p, pathRCList) && m == "POST": + counts["post"]++ + deleted = false + bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC)) + return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil + default: + t.Fatalf("unexpected request: %#v\n%#v", req.URL, req) + return nil, nil + } + }), + } + tf.Client = tf.UnstructuredClient + tf.ClientConfig = &restclient.Config{} + tf.Namespace = "test" + buf := bytes.NewBuffer([]byte{}) + errBuf := bytes.NewBuffer([]byte{}) + + cmd := NewCmdApply(f, buf, errBuf) + cmd.Flags().Set("filename", filenameRC) + cmd.Flags().Set("output", "name") + cmd.Flags().Set("force", "true") + cmd.Run(cmd, []string{}) + + for method, exp := range expected { + if exp != counts[method] { + t.Errorf("Unexpected amount of %q API calls, wanted %v got %v", method, exp, counts[method]) + } + } + + if expected := "replicationcontroller/" + nameRC + "\n"; buf.String() != expected { + t.Fatalf("unexpected output: %s\nexpected: %s", buf.String(), expected) + } +}