mirror of https://github.com/k3s-io/k3s
Protect against nil panic in apply
parent
4103f40fc2
commit
183ff5237d
|
@ -313,6 +313,7 @@ func RunApply(f cmdutil.Factory, cmd *cobra.Command, out, errOut io.Writer, opti
|
||||||
decoder: decoder,
|
decoder: decoder,
|
||||||
mapping: info.Mapping,
|
mapping: info.Mapping,
|
||||||
helper: helper,
|
helper: helper,
|
||||||
|
clientFunc: f.UnstructuredClientForMapping,
|
||||||
clientsetFunc: f.ClientSet,
|
clientsetFunc: f.ClientSet,
|
||||||
overwrite: overwrite,
|
overwrite: overwrite,
|
||||||
backOff: clockwork.NewRealClock(),
|
backOff: clockwork.NewRealClock(),
|
||||||
|
@ -496,7 +497,7 @@ func (p *pruner) prune(namespace string, mapping *meta.RESTMapping, shortOutput
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !p.dryRun {
|
if !p.dryRun {
|
||||||
if err := p.delete(namespace, name, mapping, c); err != nil {
|
if err := p.delete(namespace, name, mapping); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -505,7 +506,12 @@ func (p *pruner) prune(namespace string, mapping *meta.RESTMapping, shortOutput
|
||||||
return nil
|
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)
|
return runDelete(namespace, name, mapping, c, nil, p.cascade, p.gracePeriod, p.clientsetFunc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -538,7 +544,11 @@ func runDelete(namespace, name string, mapping *meta.RESTMapping, c resource.RES
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *patcher) delete(namespace, name string) error {
|
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 {
|
type patcher struct {
|
||||||
|
@ -547,6 +557,7 @@ type patcher struct {
|
||||||
|
|
||||||
mapping *meta.RESTMapping
|
mapping *meta.RESTMapping
|
||||||
helper *resource.Helper
|
helper *resource.Helper
|
||||||
|
clientFunc resource.ClientMapperFunc
|
||||||
clientsetFunc func() (internalclientset.Interface, error)
|
clientsetFunc func() (internalclientset.Interface, error)
|
||||||
|
|
||||||
overwrite bool
|
overwrite bool
|
||||||
|
|
|
@ -33,6 +33,7 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
restclient "k8s.io/client-go/rest"
|
||||||
"k8s.io/client-go/rest/fake"
|
"k8s.io/client-go/rest/fake"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/testapi"
|
"k8s.io/kubernetes/pkg/api/testapi"
|
||||||
|
@ -1012,3 +1013,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)
|
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("kubectl", 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue