mirror of
https://github.com/rancher/steve.git
synced 2025-09-02 07:55:31 +00:00
Add column support
This commit is contained in:
@@ -122,3 +122,14 @@ func SetAPIResource(s *types.Schema, resource v1.APIResource) {
|
||||
SetVerbs(s, resource.Verbs)
|
||||
SetNamespaced(s, resource.Namespaced)
|
||||
}
|
||||
|
||||
func SetColumns(s *types.Schema, columns interface{}) {
|
||||
if s.Attributes == nil {
|
||||
s.Attributes = map[string]interface{}{}
|
||||
}
|
||||
s.Attributes["columns"] = columns
|
||||
}
|
||||
|
||||
func Columns(s *types.Schema) interface{} {
|
||||
return s.Attributes["columns"]
|
||||
}
|
||||
|
@@ -22,6 +22,7 @@ type handler struct {
|
||||
toSync int32
|
||||
schemas *schema2.Collection
|
||||
client discovery.DiscoveryInterface
|
||||
crd apiextcontrollerv1beta1.CustomResourceDefinitionClient
|
||||
}
|
||||
|
||||
func Register(ctx context.Context,
|
||||
@@ -33,6 +34,7 @@ func Register(ctx context.Context,
|
||||
h := &handler{
|
||||
client: discovery,
|
||||
schemas: schemas,
|
||||
crd: crd,
|
||||
}
|
||||
|
||||
apiService.OnChange(ctx, "schema", h.OnChangeAPIService)
|
||||
@@ -70,7 +72,7 @@ func (h *handler) refreshAll() error {
|
||||
}
|
||||
|
||||
logrus.Info("Refreshing all schemas")
|
||||
schemas, err := converter.ToSchemas(h.client)
|
||||
schemas, err := converter.ToSchemas(h.crd, h.client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
30
pkg/resources/common/defaultcolumns.go
Normal file
30
pkg/resources/common/defaultcolumns.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"github.com/rancher/naok/pkg/attributes"
|
||||
"github.com/rancher/naok/pkg/table"
|
||||
"github.com/rancher/norman/pkg/types"
|
||||
)
|
||||
|
||||
type DefaultColumns struct {
|
||||
types.EmptyMapper
|
||||
}
|
||||
|
||||
func (d *DefaultColumns) ModifySchema(schema *types.Schema, schemas *types.Schemas) error {
|
||||
if attributes.Columns(schema) == nil {
|
||||
attributes.SetColumns(schema, []table.Column{
|
||||
{
|
||||
Name: "Name",
|
||||
Field: "metadata.name",
|
||||
Type: "string",
|
||||
},
|
||||
{
|
||||
Name: "Created",
|
||||
Field: "metadata.creationTimestamp",
|
||||
Type: "date",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@@ -12,6 +12,7 @@ func Register(collection *schema.Collection, clientGetter proxy.ClientGetter) {
|
||||
collection.AddTemplate(&schema.Template{
|
||||
Store: proxy.NewProxyStore(clientGetter),
|
||||
Formatter: Formatter,
|
||||
Mapper: &DefaultColumns{},
|
||||
})
|
||||
}
|
||||
|
||||
|
@@ -2,8 +2,8 @@ package resources
|
||||
|
||||
import (
|
||||
"github.com/rancher/naok/pkg/accesscontrol"
|
||||
"github.com/rancher/naok/pkg/counts"
|
||||
"github.com/rancher/naok/pkg/resources/common"
|
||||
"github.com/rancher/naok/pkg/resources/counts"
|
||||
"github.com/rancher/naok/pkg/resources/schema"
|
||||
"github.com/rancher/norman/pkg/store/proxy"
|
||||
"github.com/rancher/norman/pkg/subscribe"
|
||||
|
@@ -29,6 +29,8 @@ type Template struct {
|
||||
Group string
|
||||
Kind string
|
||||
ID string
|
||||
RegisterType interface{}
|
||||
Customize func(*types.Schema)
|
||||
Formatter types.Formatter
|
||||
Store types.Store
|
||||
Mapper types.Mapper
|
||||
|
70
pkg/resources/schema/converter/crd.go
Normal file
70
pkg/resources/schema/converter/crd.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package converter
|
||||
|
||||
import (
|
||||
"github.com/rancher/naok/pkg/attributes"
|
||||
"github.com/rancher/naok/pkg/table"
|
||||
"github.com/rancher/norman/pkg/types"
|
||||
"github.com/rancher/wrangler-api/pkg/generated/controllers/apiextensions.k8s.io/v1beta1"
|
||||
beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
func AddCustomResources(crd v1beta1.CustomResourceDefinitionClient, schemas map[string]*types.Schema) error {
|
||||
crds, err := crd.List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, crd := range crds.Items {
|
||||
if crd.Status.AcceptedNames.Plural == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
var columns []table.Column
|
||||
for _, col := range crd.Spec.AdditionalPrinterColumns {
|
||||
columns = append(columns, table.Column{
|
||||
Name: col.Name,
|
||||
Field: col.JSONPath,
|
||||
Type: col.Type,
|
||||
})
|
||||
}
|
||||
|
||||
group, resource := crd.Spec.Group, crd.Status.AcceptedNames.Plural
|
||||
|
||||
if crd.Spec.Version != "" {
|
||||
forVersion(group, crd.Spec.Version, resource, schemas, crd.Spec.AdditionalPrinterColumns, columns)
|
||||
}
|
||||
for _, version := range crd.Spec.Versions {
|
||||
forVersion(group, version.Name, resource, schemas, crd.Spec.AdditionalPrinterColumns, columns)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func forVersion(group, version, resource string, schemas map[string]*types.Schema, columnDefs []beta1.CustomResourceColumnDefinition, columns []table.Column) {
|
||||
var versionColumns []table.Column
|
||||
for _, col := range columnDefs {
|
||||
versionColumns = append(versionColumns, table.Column{
|
||||
Name: col.Name,
|
||||
Field: col.JSONPath,
|
||||
Type: col.Type,
|
||||
})
|
||||
}
|
||||
if len(versionColumns) == 0 {
|
||||
versionColumns = columns
|
||||
}
|
||||
|
||||
id := GVRToSchemaID(schema.GroupVersionResource{
|
||||
Group: group,
|
||||
Version: version,
|
||||
Resource: resource,
|
||||
})
|
||||
|
||||
schema := schemas[id]
|
||||
if schema == nil {
|
||||
return
|
||||
}
|
||||
attributes.SetColumns(schema, columns)
|
||||
}
|
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/rancher/norman/pkg/types"
|
||||
"github.com/rancher/wrangler-api/pkg/generated/controllers/apiextensions.k8s.io/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/discovery"
|
||||
)
|
||||
@@ -15,14 +16,14 @@ func gvkToSchemaID(gvk schema.GroupVersionKind) string {
|
||||
return fmt.Sprintf("%s.%s.%s", gvk.Group, gvk.Version, gvk.Kind)
|
||||
}
|
||||
|
||||
func GVRToSchemaID(gvk schema.GroupVersionResource) string {
|
||||
if gvk.Group == "" {
|
||||
return fmt.Sprintf("core.%s.%s", gvk.Version, gvk.Resource)
|
||||
func GVRToSchemaID(gvr schema.GroupVersionResource) string {
|
||||
if gvr.Group == "" {
|
||||
return fmt.Sprintf("core.%s.%s", gvr.Version, gvr.Resource)
|
||||
}
|
||||
return fmt.Sprintf("%s.%s.%s", gvk.Group, gvk.Version, gvk.Resource)
|
||||
return fmt.Sprintf("%s.%s.%s", gvr.Group, gvr.Version, gvr.Resource)
|
||||
}
|
||||
|
||||
func ToSchemas(client discovery.DiscoveryInterface) (map[string]*types.Schema, error) {
|
||||
func ToSchemas(crd v1beta1.CustomResourceDefinitionClient, client discovery.DiscoveryInterface) (map[string]*types.Schema, error) {
|
||||
result := map[string]*types.Schema{}
|
||||
|
||||
if err := AddOpenAPI(client, result); err != nil {
|
||||
@@ -33,5 +34,9 @@ func ToSchemas(client discovery.DiscoveryInterface) (map[string]*types.Schema, e
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := AddCustomResources(crd, result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
@@ -3,9 +3,8 @@ package schema
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/rancher/norman/pkg/data"
|
||||
"github.com/rancher/norman/pkg/types"
|
||||
"github.com/rancher/norman/pkg/types/convert"
|
||||
"github.com/rancher/norman/pkg/types/values"
|
||||
)
|
||||
|
||||
func newDefaultMapper() types.Mapper {
|
||||
@@ -16,7 +15,7 @@ type defaultMapper struct {
|
||||
types.EmptyMapper
|
||||
}
|
||||
|
||||
func (d *defaultMapper) FromInternal(data map[string]interface{}) {
|
||||
func (d *defaultMapper) FromInternal(data data.Object) {
|
||||
if data["kind"] != "" && data["apiVersion"] != "" {
|
||||
if t, ok := data["type"]; ok && data != nil {
|
||||
data["_type"] = t
|
||||
@@ -27,8 +26,8 @@ func (d *defaultMapper) FromInternal(data map[string]interface{}) {
|
||||
return
|
||||
}
|
||||
|
||||
name := convert.ToString(values.GetValueN(data, "metadata", "name"))
|
||||
namespace := convert.ToString(values.GetValueN(data, "metadata", "namespace"))
|
||||
name := types.Name(data)
|
||||
namespace := types.Namespace(data)
|
||||
|
||||
if namespace == "" {
|
||||
data["id"] = name
|
||||
|
@@ -38,6 +38,16 @@ func (c *Collection) schemasForSubject(subjectKey string, access *accesscontrol.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, template := range c.templates {
|
||||
if template.RegisterType != nil {
|
||||
s, err := result.Import(template.RegisterType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.applyTemplates(result, s)
|
||||
}
|
||||
}
|
||||
|
||||
for _, s := range c.schemas {
|
||||
gr := attributes.GR(s)
|
||||
|
||||
@@ -78,7 +88,7 @@ func (c *Collection) schemasForSubject(subjectKey string, access *accesscontrol.
|
||||
s.CollectionMethods = append(s.CollectionMethods, http.MethodPost)
|
||||
}
|
||||
|
||||
c.applyTemplates(s)
|
||||
c.applyTemplates(result, s)
|
||||
|
||||
if err := result.AddSchema(*s); err != nil {
|
||||
return nil, err
|
||||
@@ -88,7 +98,7 @@ func (c *Collection) schemasForSubject(subjectKey string, access *accesscontrol.
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *Collection) applyTemplates(schema *types.Schema) {
|
||||
func (c *Collection) applyTemplates(schemas *types.Schemas, schema *types.Schema) {
|
||||
templates := []*Template{
|
||||
c.templates[schema.ID],
|
||||
c.templates[fmt.Sprintf("%s/%s", attributes.Group(schema), attributes.Kind(schema))],
|
||||
@@ -99,8 +109,8 @@ func (c *Collection) applyTemplates(schema *types.Schema) {
|
||||
if t == nil {
|
||||
continue
|
||||
}
|
||||
if schema.Mapper == nil {
|
||||
schema.Mapper = t.Mapper
|
||||
if t.Mapper != nil {
|
||||
schemas.AddMapper(schema.ID, t.Mapper)
|
||||
}
|
||||
if schema.Formatter == nil {
|
||||
schema.Formatter = t.Formatter
|
||||
@@ -108,5 +118,8 @@ func (c *Collection) applyTemplates(schema *types.Schema) {
|
||||
if schema.Store == nil {
|
||||
schema.Store = t.Store
|
||||
}
|
||||
if t.Customize != nil {
|
||||
t.Customize(schema)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,14 +1,14 @@
|
||||
package server
|
||||
package publicapi
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/rancher/naok/pkg/accesscontrol"
|
||||
"github.com/rancher/naok/pkg/attributes"
|
||||
k8sproxy "github.com/rancher/naok/pkg/proxy"
|
||||
"github.com/rancher/naok/pkg/resources/schema"
|
||||
"github.com/rancher/naok/pkg/server/router"
|
||||
"github.com/rancher/norman/pkg/api"
|
||||
"github.com/rancher/norman/pkg/types"
|
||||
"github.com/rancher/norman/pkg/urlbuilder"
|
||||
@@ -16,29 +16,30 @@ import (
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
func newAPIServer(cfg *rest.Config, sf schema.Factory) (http.Handler, error) {
|
||||
func NewHandler(cfg *rest.Config, sf schema.Factory) (http.Handler, error) {
|
||||
var (
|
||||
err error
|
||||
)
|
||||
|
||||
a := &apiServer{
|
||||
Router: mux.NewRouter(),
|
||||
sf: sf,
|
||||
server: api.NewAPIServer(),
|
||||
server: api.DefaultAPIServer(),
|
||||
}
|
||||
a.server.AccessControl = accesscontrol.NewAccessControl()
|
||||
|
||||
a.Router.NotFoundHandler, err = k8sproxy.Handler("/", cfg)
|
||||
proxy, err := k8sproxy.Handler("/", cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
a.Router.StrictSlash(true)
|
||||
a.server.AccessControl = accesscontrol.NewAccessControl()
|
||||
return a, a.routes()
|
||||
return router.Routes(router.Handlers{
|
||||
K8sResource: a.apiHandler(k8sAPI),
|
||||
GenericResource: a.apiHandler(nil),
|
||||
K8sProxy: proxy,
|
||||
}), nil
|
||||
}
|
||||
|
||||
type apiServer struct {
|
||||
*mux.Router
|
||||
sf schema.Factory
|
||||
server *api.Server
|
||||
}
|
||||
@@ -77,3 +78,21 @@ func (a *apiServer) Schema(base string, schema *types.Schema) string {
|
||||
}
|
||||
return urlbuilder.ConstructBasicURL(base, "v1", strings.ToLower(schema.ID))
|
||||
}
|
||||
|
||||
type APIFunc func(schema.Factory, *types.APIRequest)
|
||||
|
||||
func (a *apiServer) apiHandler(apiFunc APIFunc) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
a.api(rw, req, apiFunc)
|
||||
})
|
||||
}
|
||||
|
||||
func (a *apiServer) api(rw http.ResponseWriter, req *http.Request, apiFunc APIFunc) {
|
||||
apiOp, ok := a.common(rw, req)
|
||||
if ok {
|
||||
if apiFunc != nil {
|
||||
apiFunc(a.sf, apiOp)
|
||||
}
|
||||
a.server.Handle(apiOp)
|
||||
}
|
||||
}
|
38
pkg/server/publicapi/handlers.go
Normal file
38
pkg/server/publicapi/handlers.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package publicapi
|
||||
|
||||
import (
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/rancher/naok/pkg/attributes"
|
||||
"github.com/rancher/naok/pkg/resources/schema"
|
||||
"github.com/rancher/norman/pkg/types"
|
||||
runtimeschema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
func k8sAPI(sf schema.Factory, apiOp *types.APIRequest) {
|
||||
vars := mux.Vars(apiOp.Request)
|
||||
group := vars["group"]
|
||||
if group == "core" {
|
||||
group = ""
|
||||
}
|
||||
|
||||
apiOp.Name = vars["name"]
|
||||
apiOp.Type = sf.ByGVR(runtimeschema.GroupVersionResource{
|
||||
Version: vars["version"],
|
||||
Group: group,
|
||||
Resource: vars["resource"],
|
||||
})
|
||||
|
||||
nOrN := vars["nameorns"]
|
||||
if nOrN != "" {
|
||||
schema := apiOp.Schemas.Schema(apiOp.Type)
|
||||
if attributes.Namespaced(schema) {
|
||||
vars["namespace"] = nOrN
|
||||
} else {
|
||||
vars["name"] = nOrN
|
||||
}
|
||||
}
|
||||
|
||||
if namespace := vars["namespace"]; namespace != "" {
|
||||
apiOp.Namespaces = []string{namespace}
|
||||
}
|
||||
}
|
29
pkg/server/router/router.go
Normal file
29
pkg/server/router/router.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
type Handlers struct {
|
||||
K8sResource http.Handler
|
||||
GenericResource http.Handler
|
||||
K8sProxy http.Handler
|
||||
}
|
||||
|
||||
func Routes(h Handlers) http.Handler {
|
||||
m := mux.NewRouter()
|
||||
m.UseEncodedPath()
|
||||
m.StrictSlash(true)
|
||||
m.NotFoundHandler = h.K8sProxy
|
||||
|
||||
m.Path("/v1/{type:schemas}/{name:.*}").Handler(h.GenericResource)
|
||||
m.Path("/v1/{group}.{version}.{resource}").Handler(h.K8sResource)
|
||||
m.Path("/v1/{group}.{version}.{resource}/{nameorns}").Handler(h.K8sResource)
|
||||
m.Path("/v1/{group}.{version}.{resource}/{namespace}/{name}").Handler(h.K8sResource)
|
||||
m.Path("/v1/{type}").Handler(h.GenericResource)
|
||||
m.Path("/v1/{type}/{name}").Handler(h.GenericResource)
|
||||
|
||||
return m
|
||||
}
|
@@ -1,68 +0,0 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/rancher/naok/pkg/attributes"
|
||||
"github.com/rancher/norman/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
type APIFunc func(*types.APIRequest)
|
||||
|
||||
func (a *apiServer) routes() error {
|
||||
a.Path("/v1/{type:schemas}/{name:.*}").Handler(a.handle(nil))
|
||||
a.Path("/v1/{group}.{version}.{resource}").Handler(a.handle(a.k8sAPI))
|
||||
a.Path("/v1/{group}.{version}.{resource}/{nameorns}").Handler(a.handle(a.k8sAPI))
|
||||
a.Path("/v1/{group}.{version}.{resource}/{namespace}/{name}").Handler(a.handle(a.k8sAPI))
|
||||
a.Path("/v1/{type}").Handler(a.handle(nil))
|
||||
a.Path("/v1/{type}/{name}").Handler(a.handle(nil))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *apiServer) handle(apiFunc APIFunc) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
a.api(rw, req, apiFunc)
|
||||
})
|
||||
}
|
||||
|
||||
func (a *apiServer) api(rw http.ResponseWriter, req *http.Request, apiFunc APIFunc) {
|
||||
apiOp, ok := a.common(rw, req)
|
||||
if ok {
|
||||
if apiFunc != nil {
|
||||
apiFunc(apiOp)
|
||||
}
|
||||
a.server.Handle(apiOp)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *apiServer) k8sAPI(apiOp *types.APIRequest) {
|
||||
vars := mux.Vars(apiOp.Request)
|
||||
group := vars["group"]
|
||||
if group == "core" {
|
||||
group = ""
|
||||
}
|
||||
|
||||
apiOp.Name = vars["name"]
|
||||
apiOp.Type = a.sf.ByGVR(schema.GroupVersionResource{
|
||||
Version: vars["version"],
|
||||
Group: group,
|
||||
Resource: vars["resource"],
|
||||
})
|
||||
|
||||
nOrN := vars["nameorns"]
|
||||
if nOrN != "" {
|
||||
schema := apiOp.Schemas.Schema(apiOp.Type)
|
||||
if attributes.Namespaced(schema) {
|
||||
vars["namespace"] = nOrN
|
||||
} else {
|
||||
vars["name"] = nOrN
|
||||
}
|
||||
}
|
||||
|
||||
if namespace := vars["namespace"]; namespace != "" {
|
||||
apiOp.Namespaces = []string{namespace}
|
||||
}
|
||||
}
|
@@ -4,12 +4,11 @@ import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/rancher/naok/pkg/resources"
|
||||
|
||||
"github.com/rancher/naok/pkg/controllers/schema"
|
||||
|
||||
"github.com/rancher/naok/pkg/accesscontrol"
|
||||
"github.com/rancher/naok/pkg/client"
|
||||
"github.com/rancher/naok/pkg/controllers/schema"
|
||||
"github.com/rancher/naok/pkg/resources"
|
||||
"github.com/rancher/naok/pkg/server/publicapi"
|
||||
"github.com/rancher/wrangler-api/pkg/generated/controllers/apiextensions.k8s.io"
|
||||
"github.com/rancher/wrangler-api/pkg/generated/controllers/apiregistration.k8s.io"
|
||||
rbaccontroller "github.com/rancher/wrangler-api/pkg/generated/controllers/rbac"
|
||||
@@ -17,7 +16,6 @@ import (
|
||||
"github.com/rancher/wrangler/pkg/start"
|
||||
"github.com/sirupsen/logrus"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
@@ -52,7 +50,21 @@ func Run(ctx context.Context, cfg Config) error {
|
||||
return err
|
||||
}
|
||||
|
||||
starter, err := startAPI(ctx, cfg.ListenAddress, restConfig, k8s, crd, api, rbac)
|
||||
cf, err := client.NewFactory(restConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sf := resources.SchemaFactory(cf,
|
||||
accesscontrol.NewAccessStore(rbac.Rbac().V1()))
|
||||
|
||||
schema.Register(ctx,
|
||||
k8s.Discovery(),
|
||||
crd.Apiextensions().V1beta1().CustomResourceDefinition(),
|
||||
api.Apiregistration().V1().APIService(),
|
||||
sf)
|
||||
|
||||
handler, err := publicapi.NewHandler(restConfig, sf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -61,37 +73,6 @@ func Run(ctx context.Context, cfg Config) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := starter(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
<-ctx.Done()
|
||||
return nil
|
||||
}
|
||||
|
||||
func startAPI(ctx context.Context, listenAddress string, restConfig *rest.Config, k8s *kubernetes.Clientset, crd *apiextensions.Factory,
|
||||
api *apiregistration.Factory, rbac *rbaccontroller.Factory) (func() error, error) {
|
||||
|
||||
cf, err := client.NewFactory(restConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
as := accesscontrol.NewAccessStore(rbac.Rbac().V1())
|
||||
sf := resources.SchemaFactory(cf, as)
|
||||
|
||||
schema.Register(ctx,
|
||||
k8s.Discovery(),
|
||||
crd.Apiextensions().V1beta1().CustomResourceDefinition(),
|
||||
api.Apiregistration().V1().APIService(),
|
||||
sf)
|
||||
|
||||
return func() error {
|
||||
handler, err := newAPIServer(restConfig, sf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logrus.Infof("listening on %s", listenAddress)
|
||||
return http.ListenAndServe(listenAddress, handler)
|
||||
}, nil
|
||||
logrus.Infof("listening on %s", cfg.ListenAddress)
|
||||
return http.ListenAndServe(cfg.ListenAddress, handler)
|
||||
}
|
||||
|
35
pkg/table/mapper.go
Normal file
35
pkg/table/mapper.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/rancher/naok/pkg/attributes"
|
||||
"github.com/rancher/norman/pkg/data"
|
||||
"github.com/rancher/norman/pkg/types"
|
||||
)
|
||||
|
||||
type Column struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Field string `json:"field,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
type Table struct {
|
||||
Columns []Column
|
||||
Computed func(data.Object)
|
||||
}
|
||||
|
||||
type ColumnMapper struct {
|
||||
definition Table
|
||||
types.EmptyMapper
|
||||
}
|
||||
|
||||
func (t *ColumnMapper) FromInternal(d data.Object) {
|
||||
d.Map("metadata").Set("columns", t.definition.Columns)
|
||||
if t.definition.Computed != nil {
|
||||
t.definition.Computed(d)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *ColumnMapper) ModifySchema(schema *types.Schema, schemas *types.Schemas) error {
|
||||
attributes.SetColumns(schema, t.definition.Columns)
|
||||
return nil
|
||||
}
|
2
vendor/github.com/rancher/norman/pkg/api/server.go
generated
vendored
2
vendor/github.com/rancher/norman/pkg/api/server.go
generated
vendored
@@ -51,7 +51,7 @@ type Defaults struct {
|
||||
ErrorHandler types.ErrorHandler
|
||||
}
|
||||
|
||||
func NewAPIServer() *Server {
|
||||
func DefaultAPIServer() *Server {
|
||||
s := &Server{
|
||||
DefaultNamespace: "default",
|
||||
Schemas: types.EmptySchemas(),
|
||||
|
22
vendor/github.com/rancher/norman/pkg/data/data.go
generated
vendored
22
vendor/github.com/rancher/norman/pkg/data/data.go
generated
vendored
@@ -19,7 +19,29 @@ func (o Object) Map(names ...string) Object {
|
||||
return Object(m)
|
||||
}
|
||||
|
||||
func (o Object) Slice(names ...string) (result []Object) {
|
||||
v := values.GetValueN(o, names...)
|
||||
for _, item := range convert.ToInterfaceSlice(v) {
|
||||
result = append(result, Object(convert.ToMapInterface(item)))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (o Object) Values() (result []Object) {
|
||||
for k := range o {
|
||||
result = append(result, o.Map(k))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (o Object) String(names ...string) string {
|
||||
v := values.GetValueN(o, names...)
|
||||
return convert.ToString(v)
|
||||
}
|
||||
|
||||
func (o Object) Set(key string, obj interface{}) {
|
||||
if o == nil {
|
||||
return
|
||||
}
|
||||
o[key] = obj
|
||||
}
|
||||
|
16
vendor/github.com/rancher/norman/pkg/store/proxy/mapper.go
generated
vendored
16
vendor/github.com/rancher/norman/pkg/store/proxy/mapper.go
generated
vendored
@@ -1,6 +1,9 @@
|
||||
package proxy
|
||||
|
||||
import "github.com/rancher/norman/pkg/types"
|
||||
import (
|
||||
"github.com/rancher/norman/pkg/data"
|
||||
"github.com/rancher/norman/pkg/types"
|
||||
)
|
||||
|
||||
type AddAPIVersionKind struct {
|
||||
APIVersion string
|
||||
@@ -8,24 +11,21 @@ type AddAPIVersionKind struct {
|
||||
Next types.Mapper
|
||||
}
|
||||
|
||||
func (d AddAPIVersionKind) FromInternal(data map[string]interface{}) {
|
||||
func (d AddAPIVersionKind) FromInternal(data data.Object) {
|
||||
if d.Next != nil {
|
||||
d.Next.FromInternal(data)
|
||||
}
|
||||
}
|
||||
|
||||
func (d AddAPIVersionKind) ToInternal(data map[string]interface{}) error {
|
||||
func (d AddAPIVersionKind) ToInternal(data data.Object) error {
|
||||
if d.Next != nil {
|
||||
if err := d.Next.ToInternal(data); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if data == nil {
|
||||
return nil
|
||||
}
|
||||
data["apiVersion"] = d.APIVersion
|
||||
data["kind"] = d.Kind
|
||||
data.Set("apiVersion", d.APIVersion)
|
||||
data.Set("kind", d.Kind)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
46
vendor/github.com/rancher/norman/pkg/types/mapper.go
generated
vendored
46
vendor/github.com/rancher/norman/pkg/types/mapper.go
generated
vendored
@@ -1,23 +1,23 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/rancher/norman/pkg/types/convert"
|
||||
"github.com/rancher/norman/pkg/data"
|
||||
"github.com/rancher/norman/pkg/types/definition"
|
||||
)
|
||||
|
||||
type Mapper interface {
|
||||
FromInternal(data map[string]interface{})
|
||||
ToInternal(data map[string]interface{}) error
|
||||
FromInternal(data data.Object)
|
||||
ToInternal(data data.Object) error
|
||||
ModifySchema(schema *Schema, schemas *Schemas) error
|
||||
}
|
||||
|
||||
type EmptyMapper struct {
|
||||
}
|
||||
|
||||
func (e *EmptyMapper) FromInternal(data map[string]interface{}) {
|
||||
func (e *EmptyMapper) FromInternal(data data.Object) {
|
||||
}
|
||||
|
||||
func (e *EmptyMapper) ToInternal(data map[string]interface{}) error {
|
||||
func (e *EmptyMapper) ToInternal(data data.Object) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -27,13 +27,13 @@ func (e *EmptyMapper) ModifySchema(schema *Schema, schemas *Schemas) error {
|
||||
|
||||
type Mappers []Mapper
|
||||
|
||||
func (m Mappers) FromInternal(data map[string]interface{}) {
|
||||
func (m Mappers) FromInternal(data data.Object) {
|
||||
for _, mapper := range m {
|
||||
mapper.FromInternal(data)
|
||||
}
|
||||
}
|
||||
|
||||
func (m Mappers) ToInternal(data map[string]interface{}) error {
|
||||
func (m Mappers) ToInternal(data data.Object) error {
|
||||
var errors []error
|
||||
for i := len(m) - 1; i >= 0; i-- {
|
||||
errors = append(errors, m[i].ToInternal(data))
|
||||
@@ -59,23 +59,20 @@ type typeMapper struct {
|
||||
subMapSchemas map[string]*Schema
|
||||
}
|
||||
|
||||
func (t *typeMapper) FromInternal(data map[string]interface{}) {
|
||||
func (t *typeMapper) FromInternal(data data.Object) {
|
||||
for fieldName, schema := range t.subSchemas {
|
||||
if schema.Mapper == nil {
|
||||
continue
|
||||
}
|
||||
fieldData, _ := data[fieldName].(map[string]interface{})
|
||||
schema.Mapper.FromInternal(fieldData)
|
||||
schema.Mapper.FromInternal(data.Map(fieldName))
|
||||
}
|
||||
|
||||
for fieldName, schema := range t.subMapSchemas {
|
||||
if schema.Mapper == nil {
|
||||
continue
|
||||
}
|
||||
datas, _ := data[fieldName].(map[string]interface{})
|
||||
for _, fieldData := range datas {
|
||||
mapFieldData, _ := fieldData.(map[string]interface{})
|
||||
schema.Mapper.FromInternal(mapFieldData)
|
||||
for _, fieldData := range data.Map(fieldName).Values() {
|
||||
schema.Mapper.FromInternal(fieldData)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,17 +80,15 @@ func (t *typeMapper) FromInternal(data map[string]interface{}) {
|
||||
if schema.Mapper == nil {
|
||||
continue
|
||||
}
|
||||
datas, _ := data[fieldName].([]interface{})
|
||||
for _, fieldData := range datas {
|
||||
mapFieldData, _ := fieldData.(map[string]interface{})
|
||||
schema.Mapper.FromInternal(mapFieldData)
|
||||
for _, fieldData := range data.Slice(fieldName) {
|
||||
schema.Mapper.FromInternal(fieldData)
|
||||
}
|
||||
}
|
||||
|
||||
Mappers(t.Mappers).FromInternal(data)
|
||||
}
|
||||
|
||||
func (t *typeMapper) ToInternal(data map[string]interface{}) error {
|
||||
func (t *typeMapper) ToInternal(data data.Object) error {
|
||||
errors := Errors{}
|
||||
errors.Add(Mappers(t.Mappers).ToInternal(data))
|
||||
|
||||
@@ -101,9 +96,8 @@ func (t *typeMapper) ToInternal(data map[string]interface{}) error {
|
||||
if schema.Mapper == nil {
|
||||
continue
|
||||
}
|
||||
datas, _ := data[fieldName].([]interface{})
|
||||
for _, fieldData := range datas {
|
||||
errors.Add(schema.Mapper.ToInternal(convert.ToMapInterface(fieldData)))
|
||||
for _, fieldData := range data.Slice(fieldName) {
|
||||
errors.Add(schema.Mapper.ToInternal(fieldData))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,9 +105,8 @@ func (t *typeMapper) ToInternal(data map[string]interface{}) error {
|
||||
if schema.Mapper == nil {
|
||||
continue
|
||||
}
|
||||
datas, _ := data[fieldName].(map[string]interface{})
|
||||
for _, fieldData := range datas {
|
||||
errors.Add(schema.Mapper.ToInternal(convert.ToMapInterface(fieldData)))
|
||||
for _, fieldData := range data.Slice(fieldName) {
|
||||
errors.Add(schema.Mapper.ToInternal(fieldData))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,8 +114,7 @@ func (t *typeMapper) ToInternal(data map[string]interface{}) error {
|
||||
if schema.Mapper == nil {
|
||||
continue
|
||||
}
|
||||
fieldData, _ := data[fieldName].(map[string]interface{})
|
||||
errors.Add(schema.Mapper.ToInternal(fieldData))
|
||||
errors.Add(schema.Mapper.ToInternal(data.Map(fieldName)))
|
||||
}
|
||||
|
||||
return errors.Err()
|
||||
|
7
vendor/github.com/rancher/norman/pkg/types/server_types.go
generated
vendored
7
vendor/github.com/rancher/norman/pkg/types/server_types.go
generated
vendored
@@ -348,3 +348,10 @@ func APIChan(c <-chan APIEvent, f func(APIEvent) APIEvent) chan APIEvent {
|
||||
}()
|
||||
return result
|
||||
}
|
||||
|
||||
func FormatterChain(formatter Formatter, next Formatter) Formatter {
|
||||
return func(request *APIRequest, resource *RawResource) {
|
||||
formatter(request, resource)
|
||||
next(request, resource)
|
||||
}
|
||||
}
|
||||
|
4
vendor/modules.txt
vendored
4
vendor/modules.txt
vendored
@@ -42,16 +42,16 @@ github.com/pkg/errors
|
||||
github.com/rancher/norman/pkg/authorization
|
||||
github.com/rancher/norman/pkg/types
|
||||
github.com/rancher/norman/pkg/types/convert
|
||||
github.com/rancher/norman/pkg/store/empty
|
||||
github.com/rancher/norman/pkg/store/proxy
|
||||
github.com/rancher/norman/pkg/subscribe
|
||||
github.com/rancher/norman/pkg/types/values
|
||||
github.com/rancher/norman/pkg/store/empty
|
||||
github.com/rancher/norman/pkg/api/builtin
|
||||
github.com/rancher/norman/pkg/data
|
||||
github.com/rancher/norman/pkg/api
|
||||
github.com/rancher/norman/pkg/urlbuilder
|
||||
github.com/rancher/norman/pkg/httperror
|
||||
github.com/rancher/norman/pkg/types/slice
|
||||
github.com/rancher/norman/pkg/data
|
||||
github.com/rancher/norman/pkg/types/definition
|
||||
github.com/rancher/norman/pkg/types/convert/merge
|
||||
github.com/rancher/norman/pkg/api/writer
|
||||
|
Reference in New Issue
Block a user