mirror of
https://github.com/rancher/norman.git
synced 2025-09-01 15:18:20 +00:00
Updates
This commit is contained in:
@@ -112,7 +112,7 @@ func (a *APIRootStore) List(apiContext *types.APIContext, schema *types.Schema,
|
||||
|
||||
func apiVersionToAPIRootMap(version types.APIVersion) map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"type": "/v1-meta/schemas/apiRoot",
|
||||
"type": "/meta/schemas/apiRoot",
|
||||
"apiVersion": map[string]interface{}{
|
||||
"version": version.Version,
|
||||
"group": version.Group,
|
||||
|
@@ -11,7 +11,7 @@ var (
|
||||
Version = types.APIVersion{
|
||||
Group: "meta.cattle.io",
|
||||
Version: "v1",
|
||||
Path: "/v1-meta",
|
||||
Path: "/meta",
|
||||
}
|
||||
|
||||
Schema = types.Schema{
|
||||
|
@@ -29,6 +29,7 @@ type Server struct {
|
||||
schemas *types.Schemas
|
||||
QueryFilter types.QueryFilter
|
||||
StoreWrapper StoreWrapper
|
||||
URLParser parse.URLParser
|
||||
Defaults Defaults
|
||||
}
|
||||
|
||||
@@ -63,6 +64,7 @@ func NewAPIServer() *Server {
|
||||
ErrorHandler: httperror.ErrorHandler,
|
||||
},
|
||||
StoreWrapper: wrapper.Wrap,
|
||||
URLParser: parse.DefaultURLParser,
|
||||
QueryFilter: handler.QueryFilter,
|
||||
}
|
||||
|
||||
@@ -71,7 +73,7 @@ func NewAPIServer() *Server {
|
||||
}
|
||||
|
||||
func (s *Server) parser(rw http.ResponseWriter, req *http.Request) (*types.APIContext, error) {
|
||||
ctx, err := parse.Parse(rw, req, s.schemas, s.Resolver)
|
||||
ctx, err := parse.Parse(rw, req, s.schemas, s.URLParser, s.Resolver)
|
||||
ctx.ResponseWriter = s.ResponseWriters[ctx.ResponseFormat]
|
||||
if ctx.ResponseWriter == nil {
|
||||
ctx.ResponseWriter = s.ResponseWriters["json"]
|
||||
|
@@ -122,7 +122,14 @@ func (j *JSONResponseWriter) convert(b *builder.Builder, context *types.APIConte
|
||||
|
||||
func (j *JSONResponseWriter) addLinks(b *builder.Builder, schema *types.Schema, context *types.APIContext, input map[string]interface{}, rawResource *types.RawResource) {
|
||||
if rawResource.ID != "" {
|
||||
rawResource.Links["self"] = context.URLBuilder.ResourceLink(rawResource)
|
||||
self := context.URLBuilder.ResourceLink(rawResource)
|
||||
rawResource.Links["self"] = self
|
||||
if schema.CanUpdate() {
|
||||
rawResource.Links["update"] = self
|
||||
}
|
||||
if schema.CanDelete() {
|
||||
rawResource.Links["remove"] = self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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).
|
||||
|
@@ -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)
|
||||
|
43
generator/lifecycle_template.go
Normal file
43
generator/lifecycle_template.go
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
`
|
@@ -23,7 +23,7 @@ func ErrorHandler(request *types.APIContext, err error) {
|
||||
|
||||
func toError(apiError *APIError) map[string]interface{} {
|
||||
e := map[string]interface{}{
|
||||
"type": "/v1-meta/schemas/error",
|
||||
"type": "/meta/schemas/error",
|
||||
"code": apiError.code.code,
|
||||
"message": apiError.message,
|
||||
}
|
||||
|
119
lifecycle/object.go
Normal file
119
lifecycle/object.go
Normal file
@@ -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
|
||||
}
|
@@ -83,9 +83,13 @@ func (b *Builder) copyInputs(schema *types.Schema, input map[string]interface{},
|
||||
}
|
||||
|
||||
if op == List {
|
||||
if !convert.IsEmpty(input["type"]) {
|
||||
result["type"] = input["type"]
|
||||
}
|
||||
if !convert.IsEmpty(input["id"]) {
|
||||
result["id"] = input["id"]
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
161
parse/parse.go
161
parse/parse.go
@@ -2,11 +2,11 @@ package parse
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/rancher/norman/api/builtin"
|
||||
"github.com/rancher/norman/httperror"
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/rancher/norman/urlbuilder"
|
||||
)
|
||||
@@ -23,20 +23,83 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
type ParsedURL struct {
|
||||
Version string
|
||||
Type string
|
||||
ID string
|
||||
Link string
|
||||
Method string
|
||||
Action string
|
||||
SubContext map[string]string
|
||||
SubContextPrefix string
|
||||
}
|
||||
|
||||
type ResolverFunc func(typeName string, context *types.APIContext) error
|
||||
|
||||
func Parse(rw http.ResponseWriter, req *http.Request, schemas *types.Schemas, resolverFunc ResolverFunc) (*types.APIContext, error) {
|
||||
type URLParser func(schema *types.Schemas, url *url.URL) (ParsedURL, error)
|
||||
|
||||
func DefaultURLParser(schemas *types.Schemas, url *url.URL) (ParsedURL, error) {
|
||||
result := ParsedURL{}
|
||||
|
||||
version := Version(schemas, url.Path)
|
||||
if version == nil {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
path := url.Path
|
||||
path = multiSlashRegexp.ReplaceAllString(path, "/")
|
||||
|
||||
parts := strings.SplitN(path[len(version.Path):], "/", 4)
|
||||
prefix, parts, subContext := parseSubContext(version, parts)
|
||||
|
||||
result.Version = version.Path
|
||||
result.SubContext = subContext
|
||||
result.SubContextPrefix = prefix
|
||||
result.Action, result.Method = parseAction(url)
|
||||
|
||||
result.Type = safeIndex(parts, 1)
|
||||
result.ID = safeIndex(parts, 2)
|
||||
result.Link = safeIndex(parts, 3)
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func Parse(rw http.ResponseWriter, req *http.Request, schemas *types.Schemas, urlParser URLParser, resolverFunc ResolverFunc) (*types.APIContext, error) {
|
||||
var err error
|
||||
|
||||
result := &types.APIContext{
|
||||
Schemas: schemas,
|
||||
Request: req,
|
||||
Response: rw,
|
||||
Method: parseMethod(req),
|
||||
ResponseFormat: parseResponseFormat(req),
|
||||
}
|
||||
|
||||
result.URLBuilder, _ = urlbuilder.New(req, types.APIVersion{}, schemas)
|
||||
|
||||
// The response format is guarenteed to be set even in the event of an error
|
||||
result.ResponseFormat = parseResponseFormat(req)
|
||||
result.Version = parseVersion(schemas, req.URL.Path)
|
||||
result.Schemas = schemas
|
||||
parsedURL, err := urlParser(schemas, req.URL)
|
||||
// wait to check error, want to set as much as possible
|
||||
|
||||
result.SubContext = parsedURL.SubContext
|
||||
result.Type = parsedURL.Type
|
||||
result.ID = parsedURL.ID
|
||||
result.Link = parsedURL.Link
|
||||
result.Action = parsedURL.Action
|
||||
if parsedURL.Method != "" {
|
||||
result.Method = parsedURL.Method
|
||||
}
|
||||
|
||||
for i, version := range schemas.Versions() {
|
||||
if version.Path == parsedURL.Version {
|
||||
result.Version = &schemas.Versions()[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
if result.Version == nil {
|
||||
result.Method = http.MethodGet
|
||||
@@ -46,15 +109,16 @@ func Parse(rw http.ResponseWriter, req *http.Request, schemas *types.Schemas, re
|
||||
return result, nil
|
||||
}
|
||||
|
||||
result.Method = parseMethod(req)
|
||||
result.Action, result.Method = parseAction(req, result.Method)
|
||||
|
||||
result.URLBuilder, err = urlbuilder.New(req, *result.Version, result.Schemas)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
if err := parsePath(result, req, resolverFunc); err != nil {
|
||||
if parsedURL.SubContextPrefix != "" {
|
||||
result.URLBuilder.SetSubContext(parsedURL.SubContextPrefix)
|
||||
}
|
||||
|
||||
if err := resolverFunc(result.Type, result); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
@@ -66,6 +130,8 @@ func Parse(rw http.ResponseWriter, req *http.Request, schemas *types.Schemas, re
|
||||
return result, nil
|
||||
}
|
||||
|
||||
result.Type = result.Schema.ID
|
||||
|
||||
if err := ValidateMethod(result); err != nil {
|
||||
return result, err
|
||||
}
|
||||
@@ -73,33 +139,24 @@ func Parse(rw http.ResponseWriter, req *http.Request, schemas *types.Schemas, re
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func parseSubContext(parts []string, apiRequest *types.APIContext) []string {
|
||||
func parseSubContext(version *types.APIVersion, parts []string) (string, []string, map[string]string) {
|
||||
subContext := ""
|
||||
apiRequest.SubContext = map[string]string{}
|
||||
apiRequest.Attributes = map[string]interface{}{}
|
||||
result := map[string]string{}
|
||||
|
||||
for len(parts) > 3 && apiRequest.Version != nil && parts[3] != "" {
|
||||
for len(parts) > 3 && version != nil && parts[3] != "" {
|
||||
resourceType := parts[1]
|
||||
resourceID := parts[2]
|
||||
|
||||
if !apiRequest.Version.SubContexts[resourceType] {
|
||||
if !version.SubContexts[resourceType] {
|
||||
break
|
||||
}
|
||||
|
||||
if apiRequest.ReferenceValidator != nil && !apiRequest.ReferenceValidator.Validate(resourceType, resourceID) {
|
||||
return parts
|
||||
}
|
||||
|
||||
apiRequest.SubContext[resourceType] = resourceID
|
||||
result[resourceType] = resourceID
|
||||
subContext = subContext + "/" + resourceType + "/" + resourceID
|
||||
parts = append(parts[:1], parts[3:]...)
|
||||
}
|
||||
|
||||
if subContext != "" {
|
||||
apiRequest.URLBuilder.SetSubContext(subContext)
|
||||
}
|
||||
|
||||
return parts
|
||||
return subContext, parts, result
|
||||
}
|
||||
|
||||
func DefaultResolver(typeName string, apiContext *types.APIContext) error {
|
||||
@@ -120,50 +177,6 @@ func DefaultResolver(typeName string, apiContext *types.APIContext) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func parsePath(apiRequest *types.APIContext, request *http.Request, resolverFunc ResolverFunc) error {
|
||||
if apiRequest.Version == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
path := request.URL.Path
|
||||
path = multiSlashRegexp.ReplaceAllString(path, "/")
|
||||
|
||||
versionPrefix := apiRequest.Version.Path
|
||||
if !strings.HasPrefix(path, versionPrefix) {
|
||||
return nil
|
||||
}
|
||||
|
||||
parts := strings.Split(path[len(versionPrefix):], "/")
|
||||
parts = parseSubContext(parts, apiRequest)
|
||||
|
||||
if len(parts) > 4 {
|
||||
return httperror.NewAPIError(httperror.NotFound, "No handler for path")
|
||||
}
|
||||
|
||||
typeName := safeIndex(parts, 1)
|
||||
id := safeIndex(parts, 2)
|
||||
link := safeIndex(parts, 3)
|
||||
|
||||
if err := resolverFunc(typeName, apiRequest); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if apiRequest.Schema == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
apiRequest.Type = apiRequest.Schema.ID
|
||||
|
||||
if id == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
apiRequest.ID = id
|
||||
apiRequest.Link = link
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func safeIndex(slice []string, index int) string {
|
||||
if index >= len(slice) {
|
||||
return ""
|
||||
@@ -198,20 +211,16 @@ func parseMethod(req *http.Request) string {
|
||||
return method
|
||||
}
|
||||
|
||||
func parseAction(req *http.Request, method string) (string, string) {
|
||||
if req.Method != http.MethodPost {
|
||||
return "", method
|
||||
}
|
||||
|
||||
action := req.URL.Query().Get("action")
|
||||
func parseAction(url *url.URL) (string, string) {
|
||||
action := url.Query().Get("action")
|
||||
if action == "remove" {
|
||||
return "", http.MethodDelete
|
||||
}
|
||||
|
||||
return action, method
|
||||
return action, ""
|
||||
}
|
||||
|
||||
func parseVersion(schemas *types.Schemas, path string) *types.APIVersion {
|
||||
func Version(schemas *types.Schemas, path string) *types.APIVersion {
|
||||
path = multiSlashRegexp.ReplaceAllString(path, "/")
|
||||
for _, version := range schemas.Versions() {
|
||||
if version.Path == "" {
|
||||
|
@@ -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{
|
||||
|
@@ -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)
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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 {
|
||||
|
@@ -53,6 +53,14 @@ func (u *urlBuilder) SchemaLink(schema *types.Schema) string {
|
||||
return u.constructBasicURL(schema.Version, "schemas", schema.ID)
|
||||
}
|
||||
|
||||
func (u *urlBuilder) Link(linkName string, resource *types.RawResource) string {
|
||||
if resource.ID == "" || linkName == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
return u.constructBasicURL(resource.Schema.Version, resource.Schema.PluralName, resource.ID, strings.ToLower(linkName))
|
||||
}
|
||||
|
||||
func (u *urlBuilder) ResourceLink(resource *types.RawResource) string {
|
||||
if resource.ID == "" {
|
||||
return ""
|
||||
|
Reference in New Issue
Block a user