diff --git a/vendor.conf b/vendor.conf index 0250c890..fcccbc50 100644 --- a/vendor.conf +++ b/vendor.conf @@ -3,5 +3,5 @@ github.com/rancher/types k8s.io/kubernetes v1.8.3 transitive=true,staging=true bitbucket.org/ww/goautoneg a547fc61f48d567d5b4ec6f8aee5573d8efce11d https://github.com/rancher/goautoneg.git -github.com/rancher/norman 5ec6a8d719917fcca3cab8e8e9036384385ced40 +github.com/rancher/norman 18d3f69aa84ed39326e731ebfa509cf104bf9ad1 transitive=true golang.org/x/sync fd80eb99c8f653c847d294a001bdf2a3a6f768f5 diff --git a/vendor/github.com/rancher/norman/clientbase/object_client.go b/vendor/github.com/rancher/norman/clientbase/object_client.go index edef0dc1..ceb9333a 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" + "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" @@ -47,6 +48,15 @@ func (p *ObjectClient) Create(o runtime.Object) (runtime.Object, error) { if obj, ok := o.(metav1.Object); ok && obj.GetNamespace() != "" { ns = obj.GetNamespace() } + if t, err := meta.TypeAccessor(o); err == nil { + if t.GetKind() == "" { + t.SetKind(p.gvk.Kind) + } + if t.GetAPIVersion() == "" { + apiVersion, _ := p.gvk.ToAPIVersionAndKind() + t.SetAPIVersion(apiVersion) + } + } result := p.Factory.Object() err := p.restClient.Post(). Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version). diff --git a/vendor/github.com/rancher/norman/generator/generator.go b/vendor/github.com/rancher/norman/generator/generator.go index dd9ecb1c..4ed33b26 100644 --- a/vendor/github.com/rancher/norman/generator/generator.go +++ b/vendor/github.com/rancher/norman/generator/generator.go @@ -135,6 +135,36 @@ func generateType(outputDir string, schema *types.Schema, schemas *types.Schemas }) } +func generateLifecycle(external bool, outputDir string, schema *types.Schema, schemas *types.Schemas) error { + filePath := strings.ToLower("zz_generated_" + addUnderscore(schema.ID) + "_lifecycle_adapter.go") + output, err := os.Create(path.Join(outputDir, filePath)) + if err != nil { + return err + } + defer output.Close() + + typeTemplate, err := template.New("lifecycle.template"). + Funcs(funcs()). + Parse(strings.Replace(lifecycleTemplate, "%BACK%", "`", -1)) + if err != nil { + return err + } + + importPackage := "" + prefix := "" + if external { + parts := strings.Split(schema.PkgName, "/vendor/") + importPackage = fmt.Sprintf("\"%s\"", parts[len(parts)-1]) + prefix = schema.Version.Version + "." + } + + return typeTemplate.Execute(output, map[string]interface{}{ + "schema": schema, + "importPackage": importPackage, + "prefix": prefix, + }) +} + func generateController(external bool, outputDir string, schema *types.Schema, schemas *types.Schemas) error { filePath := strings.ToLower("zz_generated_" + addUnderscore(schema.ID) + "_controller.go") output, err := os.Create(path.Join(outputDir, filePath)) @@ -226,6 +256,10 @@ func GenerateControllerForTypes(version *types.APIVersion, k8sOutputPackage stri if err := generateController(true, k8sDir, schema, schemas); err != nil { return err } + + if err := generateLifecycle(true, k8sDir, schema, schemas); err != nil { + return err + } } if err := deepCopyGen(baseDir, k8sOutputPackage); err != nil { @@ -267,6 +301,9 @@ func Generate(schemas *types.Schemas, cattleOutputPackage, k8sOutputPackage stri if err := generateController(false, k8sDir, schema, schemas); err != nil { return err } + if err := generateLifecycle(false, k8sDir, schema, schemas); err != nil { + return err + } } generated = append(generated, schema) diff --git a/vendor/github.com/rancher/norman/generator/lifecycle_template.go b/vendor/github.com/rancher/norman/generator/lifecycle_template.go new file mode 100644 index 00000000..0be8bc8e --- /dev/null +++ b/vendor/github.com/rancher/norman/generator/lifecycle_template.go @@ -0,0 +1,43 @@ +package generator + +var lifecycleTemplate = `package {{.schema.Version.Version}} + +import ( + {{.importPackage}} + "k8s.io/apimachinery/pkg/runtime" + "github.com/rancher/norman/lifecycle" +) + +type {{.schema.CodeName}}Lifecycle interface { + Initialize(obj *{{.prefix}}{{.schema.CodeName}}) error + Remove(obj *{{.prefix}}{{.schema.CodeName}}) error + Updated(obj *{{.prefix}}{{.schema.CodeName}}) error +} + +type {{.schema.ID}}LifecycleAdapter struct { + lifecycle {{.schema.CodeName}}Lifecycle +} + +func (w *{{.schema.ID}}LifecycleAdapter) Initialize(obj runtime.Object) error { + return w.lifecycle.Initialize(obj.(*{{.prefix}}{{.schema.CodeName}})) +} + +func (w *{{.schema.ID}}LifecycleAdapter) Finalize(obj runtime.Object) error { + return w.lifecycle.Remove(obj.(*{{.prefix}}{{.schema.CodeName}})) +} + +func (w *{{.schema.ID}}LifecycleAdapter) Updated(obj runtime.Object) error { + return w.lifecycle.Updated(obj.(*{{.prefix}}{{.schema.CodeName}})) +} + +func New{{.schema.CodeName}}LifecycleAdapter(name string, client {{.schema.CodeName}}Interface, l {{.schema.CodeName}}Lifecycle) {{.schema.CodeName}}HandlerFunc { + adapter := &{{.schema.ID}}LifecycleAdapter{lifecycle: l} + syncFn := lifecycle.NewObjectLifecycleAdapter(name, adapter, client.ObjectClient()) + return func(key string, obj *{{.prefix}}{{.schema.CodeName}}) error { + if obj == nil { + return syncFn(key, nil) + } + return syncFn(key, obj) + } +} +` diff --git a/vendor/github.com/rancher/norman/lifecycle/object.go b/vendor/github.com/rancher/norman/lifecycle/object.go new file mode 100644 index 00000000..ca973017 --- /dev/null +++ b/vendor/github.com/rancher/norman/lifecycle/object.go @@ -0,0 +1,119 @@ +package lifecycle + +import ( + "github.com/rancher/norman/clientbase" + "github.com/rancher/norman/types/slice" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +var ( + initialized = "io.cattle.lifecycle.initialized" +) + +type ObjectLifecycle interface { + Initialize(obj runtime.Object) error + Finalize(obj runtime.Object) error + Updated(obj runtime.Object) error +} + +type objectLifecycleAdapter struct { + name string + lifecycle ObjectLifecycle + objectClient *clientbase.ObjectClient +} + +func NewObjectLifecycleAdapter(name string, lifecycle ObjectLifecycle, objectClient *clientbase.ObjectClient) func(key string, obj runtime.Object) error { + o := objectLifecycleAdapter{ + name: name, + lifecycle: lifecycle, + objectClient: objectClient, + } + return o.sync +} + +func (o *objectLifecycleAdapter) sync(key string, obj runtime.Object) error { + if obj == nil { + return nil + } + + metadata, err := meta.Accessor(obj) + if err != nil { + return err + } + + if cont, err := o.finalize(metadata, obj); err != nil || !cont { + return err + } + + if cont, err := o.initialize(metadata, obj); err != nil || !cont { + return err + } + + return o.lifecycle.Updated(obj.DeepCopyObject()) +} + +func (o *objectLifecycleAdapter) finalize(metadata metav1.Object, obj runtime.Object) (bool, error) { + // Check finalize + if metadata.GetDeletionTimestamp() == nil { + return true, nil + } + + if !slice.ContainsString(metadata.GetFinalizers(), o.name) { + return false, nil + } + + obj = obj.DeepCopyObject() + metadata, err := meta.Accessor(obj) + if err != nil { + return false, err + } + + var finalizers []string + for _, finalizer := range metadata.GetFinalizers() { + if finalizer == o.name { + continue + } + finalizers = append(finalizers, finalizer) + } + metadata.SetFinalizers(finalizers) + + if err := o.lifecycle.Finalize(obj); err != nil { + return false, err + } + + _, err = o.objectClient.Update(metadata.GetName(), obj) + return false, err +} + +func (o *objectLifecycleAdapter) initializeKey() string { + return initialized + "." + o.name +} + +func (o *objectLifecycleAdapter) initialize(metadata metav1.Object, obj runtime.Object) (bool, error) { + initialized := o.initializeKey() + + if metadata.GetLabels()[initialized] == "true" { + return true, nil + } + + obj = obj.DeepCopyObject() + metadata, err := meta.Accessor(obj) + if err != nil { + return false, err + } + + if metadata.GetLabels() == nil { + metadata.SetLabels(map[string]string{}) + } + + metadata.SetFinalizers(append(metadata.GetFinalizers(), o.name)) + metadata.GetLabels()[initialized] = "true" + if err := o.lifecycle.Initialize(obj); err != nil { + return false, err + } + + _, err = o.objectClient.Update(metadata.GetName(), obj) + return false, err +} diff --git a/vendor/github.com/rancher/norman/types/mapper/metadata.go b/vendor/github.com/rancher/norman/types/mapper/metadata.go index ddbfa5f8..2e06845d 100644 --- a/vendor/github.com/rancher/norman/types/mapper/metadata.go +++ b/vendor/github.com/rancher/norman/types/mapper/metadata.go @@ -15,7 +15,7 @@ func NewMetadataMapper() types.Mapper { Move{From: "deletionTimestamp", To: "removed"}, Drop{"deletionGracePeriodSeconds"}, Drop{"initializers"}, - Drop{"finalizers"}, + //Drop{"finalizers"}, Drop{"clusterName"}, ReadOnly{Field: "*"}, Access{ diff --git a/vendor/github.com/rancher/norman/types/schema_funcs.go b/vendor/github.com/rancher/norman/types/schema_funcs.go index df6f6ff6..b4543df1 100644 --- a/vendor/github.com/rancher/norman/types/schema_funcs.go +++ b/vendor/github.com/rancher/norman/types/schema_funcs.go @@ -24,3 +24,11 @@ func (v *APIVersion) Equals(other *APIVersion) bool { func (s *Schema) CanList() bool { return slice.ContainsString(s.CollectionMethods, http.MethodGet) } + +func (s *Schema) CanUpdate() bool { + return slice.ContainsString(s.ResourceMethods, http.MethodPut) +} + +func (s *Schema) CanDelete() bool { + return slice.ContainsString(s.ResourceMethods, http.MethodDelete) +} diff --git a/vendor/github.com/rancher/norman/types/schemas.go b/vendor/github.com/rancher/norman/types/schemas.go index 0732d31b..43613cac 100644 --- a/vendor/github.com/rancher/norman/types/schemas.go +++ b/vendor/github.com/rancher/norman/types/schemas.go @@ -60,7 +60,7 @@ func (s *Schemas) AddSchemas(schema *Schemas) *Schemas { } func (s *Schemas) AddSchema(schema *Schema) *Schemas { - schema.Type = "/v1-meta/schemas/schema" + schema.Type = "/meta/schemas/schema" if schema.ID == "" { s.errors = append(s.errors, fmt.Errorf("ID is not set on schema: %v", schema)) return s diff --git a/vendor/github.com/rancher/norman/types/server_types.go b/vendor/github.com/rancher/norman/types/server_types.go index d00f8295..4d4c3870 100644 --- a/vendor/github.com/rancher/norman/types/server_types.go +++ b/vendor/github.com/rancher/norman/types/server_types.go @@ -83,7 +83,7 @@ type APIContext struct { URLBuilder URLBuilder AccessControl AccessControl SubContext map[string]string - Attributes map[string]interface{} + //Attributes map[string]interface{} Request *http.Request Response http.ResponseWriter @@ -140,6 +140,7 @@ type URLBuilder interface { SubContextCollection(subContext *Schema, contextName string, schema *Schema) string SchemaLink(schema *Schema) string ResourceLink(resource *RawResource) string + Link(linkName string, resource *RawResource) string RelativeToRoot(path string) string Version(version APIVersion) string Marker(marker string) string diff --git a/vendor/github.com/rancher/norman/types/values/values.go b/vendor/github.com/rancher/norman/types/values/values.go index 634957b0..0b325435 100644 --- a/vendor/github.com/rancher/norman/types/values/values.go +++ b/vendor/github.com/rancher/norman/types/values/values.go @@ -1,5 +1,7 @@ package values +import "github.com/rancher/norman/types/convert" + func RemoveValue(data map[string]interface{}, keys ...string) (interface{}, bool) { for i, key := range keys { if i == len(keys)-1 { @@ -13,6 +15,30 @@ func RemoveValue(data map[string]interface{}, keys ...string) (interface{}, bool return nil, false } +func GetStringSlice(data map[string]interface{}, keys ...string) ([]string, bool) { + val, ok := GetValue(data, keys...) + if !ok { + return nil, ok + } + + slice, typeOk := val.([]string) + if typeOk { + return slice, typeOk + } + + sliceNext, typeOk := val.([]interface{}) + if !typeOk { + return nil, typeOk + } + + var result []string + for _, item := range sliceNext { + result = append(result, convert.ToString(item)) + } + + return result, true +} + func GetSlice(data map[string]interface{}, keys ...string) ([]map[string]interface{}, bool) { val, ok := GetValue(data, keys...) if !ok {