diff --git a/vendor.conf b/vendor.conf index 67b4fbb9..c410519e 100644 --- a/vendor.conf +++ b/vendor.conf @@ -5,4 +5,4 @@ k8s.io/kubernetes v1.8.3 bitbucket.org/ww/goautoneg a547fc61f48d567d5b4ec6f8aee5573d8efce11d https://github.com/rancher/goautoneg.git golang.org/x/sync fd80eb99c8f653c847d294a001bdf2a3a6f768f5 -github.com/rancher/norman a978cad0e8751968fec4371f9ab6df6d446a389b +github.com/rancher/norman 35fb4dfb92cdc8e0391504f83bbe0cdc97b03686 diff --git a/vendor/github.com/rancher/norman/clientbase/object_client.go b/vendor/github.com/rancher/norman/clientbase/object_client.go index 4e1f8efb..9969bfb1 100644 --- a/vendor/github.com/rancher/norman/clientbase/object_client.go +++ b/vendor/github.com/rancher/norman/clientbase/object_client.go @@ -4,6 +4,7 @@ import ( "encoding/json" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -150,6 +151,7 @@ func (p *ObjectClient) Update(name string, o runtime.Object) (runtime.Object, er if len(name) == 0 { return result, errors.New("object missing name") } + logrus.Debugf("UPDATE %s/%s/%s/%s/%s/%s", p.getAPIPrefix(), p.gvk.Group, p.gvk.Version, ns, p.resource.Name, name) err := p.restClient.Put(). Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version). NamespaceIfScoped(ns, p.resource.Namespaced). diff --git a/vendor/github.com/rancher/norman/clientbase/ops.go b/vendor/github.com/rancher/norman/clientbase/ops.go index f6883e63..0ea03eb7 100644 --- a/vendor/github.com/rancher/norman/clientbase/ops.go +++ b/vendor/github.com/rancher/norman/clientbase/ops.go @@ -96,12 +96,7 @@ func (a *APIOperations) DoList(schemaType string, opts *types.ListOpts, respObje return errors.New("Resource type [" + schemaType + "] is not listable") } - collectionURL, ok := schema.Links[COLLECTION] - if !ok { - return errors.New("Failed to find collection URL for [" + schemaType + "]") - } - - return a.DoGet(collectionURL, opts, respObject) + return a.DoGet(a.Opts.URL+"/"+schemaType, opts, respObject) } func (a *APIOperations) DoNext(nextURL string, respObject interface{}) error { diff --git a/vendor/github.com/rancher/norman/controller/generic_controller.go b/vendor/github.com/rancher/norman/controller/generic_controller.go index 93b455d1..bc3cdfa9 100644 --- a/vendor/github.com/rancher/norman/controller/generic_controller.go +++ b/vendor/github.com/rancher/norman/controller/generic_controller.go @@ -3,13 +3,16 @@ package controller import ( "context" "fmt" + "strings" "sync" "time" "github.com/juju/ratelimit" + errors2 "github.com/pkg/errors" "github.com/rancher/norman/clientbase" "github.com/rancher/norman/types" "github.com/sirupsen/logrus" + "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" @@ -197,17 +200,53 @@ func (g *genericController) processNextWorkItem() bool { return true } - utilruntime.HandleError(fmt.Errorf("%v %v %v", g.name, key, err)) + if err := filterConflictsError(err); err != nil { + utilruntime.HandleError(fmt.Errorf("%v %v %v", g.name, key, err)) + } + g.queue.AddRateLimited(key) return true } +func ignoreError(err error, checkString bool) bool { + err = errors2.Cause(err) + if errors.IsConflict(err) { + return true + } + if _, ok := err.(*ForgetError); ok { + return true + } + if checkString { + return strings.HasSuffix(err.Error(), "please apply your changes to the latest version and try again") + } + return false +} + +func filterConflictsError(err error) error { + if ignoreError(err, false) { + return nil + } + + if errs, ok := errors2.Cause(err).(*types.MultiErrors); ok { + var newErrors []error + for _, err := range errs.Errors { + if !ignoreError(err, true) { + newErrors = append(newErrors) + } + } + return types.NewErrors(newErrors...) + } + + return err +} + func (g *genericController) syncHandler(s string) (err error) { defer utilruntime.RecoverFromPanic(&err) var errs []error for _, handler := range g.handlers { + logrus.Debugf("%s calling handler %s %s", g.name, handler.name, s) if err := handler.handler(s); err != nil { errs = append(errs, &handlerError{ name: handler.name, @@ -215,7 +254,7 @@ func (g *genericController) syncHandler(s string) (err error) { }) } } - err = types.NewErrors(errs) + err = types.NewErrors(errs...) return } @@ -227,3 +266,7 @@ type handlerError struct { func (h *handlerError) Error() string { return fmt.Sprintf("[%s] failed with : %v", h.name, h.err) } + +func (h *handlerError) Cause() error { + return h.err +} diff --git a/vendor/github.com/rancher/norman/httperror/error.go b/vendor/github.com/rancher/norman/httperror/error.go index 9edc7b75..c721dfd9 100644 --- a/vendor/github.com/rancher/norman/httperror/error.go +++ b/vendor/github.com/rancher/norman/httperror/error.go @@ -103,3 +103,11 @@ func IsAPIError(err error) bool { _, ok := err.(*APIError) return ok } + +func IsConflict(err error) bool { + if apiError, ok := err.(*APIError); ok { + return apiError.code.Status == 409 + } + + return false +} diff --git a/vendor/github.com/rancher/norman/store/proxy/proxy_store.go b/vendor/github.com/rancher/norman/store/proxy/proxy_store.go index 5dd44579..f38cac45 100644 --- a/vendor/github.com/rancher/norman/store/proxy/proxy_store.go +++ b/vendor/github.com/rancher/norman/store/proxy/proxy_store.go @@ -4,6 +4,7 @@ import ( ejson "encoding/json" "net/http" "strings" + "time" "github.com/rancher/norman/types" "github.com/rancher/norman/types/convert" @@ -113,6 +114,11 @@ func (p *Store) getUser(apiContext *types.APIContext) string { } func (p *Store) doAuthed(apiContext *types.APIContext, request *rest.Request) rest.Result { + start := time.Now() + defer func() { + logrus.Debug("GET:", time.Now().Sub(start), p.resourcePlural) + }() + for _, header := range authHeaders { request.SetHeader(header, apiContext.Request.Header[http.CanonicalHeaderKey(header)]...) } @@ -157,7 +163,9 @@ func (p *Store) List(apiContext *types.APIContext, schema *types.Schema, opt *ty req := p.common(namespace, k8sClient.Get()) resultList := &unstructured.UnstructuredList{} + start := time.Now() err = req.Do().Into(resultList) + logrus.Debug("LIST:", time.Now().Sub(start), p.resourcePlural) if err != nil { return nil, err } @@ -168,7 +176,7 @@ func (p *Store) List(apiContext *types.APIContext, schema *types.Schema, opt *ty result = append(result, p.fromInternal(schema, obj.Object)) } - return apiContext.AccessControl.FilterList(apiContext, result, p.authContext), nil + return apiContext.AccessControl.FilterList(apiContext, schema, result, p.authContext), nil } func (p *Store) Watch(apiContext *types.APIContext, schema *types.Schema, opt *types.QueryOptions) (chan map[string]interface{}, error) { @@ -210,7 +218,7 @@ func (p *Store) Watch(apiContext *types.APIContext, schema *types.Schema, opt *t if event.Type == watch.Deleted && data.Object != nil { data.Object[".removed"] = true } - result <- apiContext.AccessControl.Filter(apiContext, data.Object, p.authContext) + result <- apiContext.AccessControl.Filter(apiContext, schema, data.Object, p.authContext) } logrus.Debugf("closing watcher for %s", schema.ID) close(result) diff --git a/vendor/github.com/rancher/norman/types/mapper/batchmove.go b/vendor/github.com/rancher/norman/types/mapper/batchmove.go index c0b4b7bb..c8a846e2 100644 --- a/vendor/github.com/rancher/norman/types/mapper/batchmove.go +++ b/vendor/github.com/rancher/norman/types/mapper/batchmove.go @@ -21,7 +21,7 @@ func (b *BatchMove) FromInternal(data map[string]interface{}) { } func (b *BatchMove) ToInternal(data map[string]interface{}) { - for i := len(b.moves) - 1; i >= 0; i++ { + for i := len(b.moves) - 1; i >= 0; i-- { b.moves[i].ToInternal(data) } } diff --git a/vendor/github.com/rancher/norman/types/mapper/required.go b/vendor/github.com/rancher/norman/types/mapper/required.go new file mode 100644 index 00000000..4c912b79 --- /dev/null +++ b/vendor/github.com/rancher/norman/types/mapper/required.go @@ -0,0 +1,29 @@ +package mapper + +import ( + "github.com/rancher/norman/types" +) + +type Required struct { + Fields []string +} + +func (e Required) FromInternal(data map[string]interface{}) { +} + +func (e Required) ToInternal(data map[string]interface{}) { +} + +func (e Required) ModifySchema(schema *types.Schema, schemas *types.Schemas) error { + for _, field := range e.Fields { + if err := ValidateField(field, schema); err != nil { + return err + } + + f := schema.ResourceFields[field] + f.Required = true + schema.ResourceFields[field] = f + } + + return nil +} diff --git a/vendor/github.com/rancher/norman/types/schemas.go b/vendor/github.com/rancher/norman/types/schemas.go index 53e6058f..2ebeff3e 100644 --- a/vendor/github.com/rancher/norman/types/schemas.go +++ b/vendor/github.com/rancher/norman/types/schemas.go @@ -57,7 +57,7 @@ func (s *Schemas) Init(initFunc SchemasInitFunc) *Schemas { } func (s *Schemas) Err() error { - return NewErrors(s.errors) + return NewErrors(s.errors...) } func (s *Schemas) AddSchemas(schema *Schemas) *Schemas { @@ -339,24 +339,24 @@ func (s *Schemas) SubContextVersionForSchema(schema *Schema) *APIVersion { return nil } -type multiErrors struct { - errors []error +type MultiErrors struct { + Errors []error } -func NewErrors(errors []error) error { +func NewErrors(errors ...error) error { if len(errors) == 0 { return nil } else if len(errors) == 1 { return errors[0] } - return &multiErrors{ - errors: errors, + return &MultiErrors{ + Errors: errors, } } -func (m *multiErrors) Error() string { +func (m *MultiErrors) Error() string { buf := bytes.NewBuffer(nil) - for _, err := range m.errors { + for _, err := range m.Errors { if buf.Len() > 0 { buf.WriteString(", ") } diff --git a/vendor/github.com/rancher/norman/types/server_types.go b/vendor/github.com/rancher/norman/types/server_types.go index 9a314a46..74c6c89a 100644 --- a/vendor/github.com/rancher/norman/types/server_types.go +++ b/vendor/github.com/rancher/norman/types/server_types.go @@ -75,8 +75,8 @@ type AccessControl interface { CanUpdate(apiContext *APIContext, obj map[string]interface{}, schema *Schema) bool CanDelete(apiContext *APIContext, obj map[string]interface{}, schema *Schema) bool - Filter(apiContext *APIContext, obj map[string]interface{}, context map[string]string) map[string]interface{} - FilterList(apiContext *APIContext, obj []map[string]interface{}, context map[string]string) []map[string]interface{} + Filter(apiContext *APIContext, schema *Schema, obj map[string]interface{}, context map[string]string) map[string]interface{} + FilterList(apiContext *APIContext, schema *Schema, obj []map[string]interface{}, context map[string]string) []map[string]interface{} } type APIContext struct {