mirror of
https://github.com/niusmallnan/steve.git
synced 2025-06-25 14:11:36 +00:00
Add fields to cluster
This commit is contained in:
parent
0849182bdd
commit
2eb87bffc1
@ -3,14 +3,21 @@ package clusters
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/rancher/steve/pkg/clustercache"
|
"github.com/rancher/steve/pkg/clustercache"
|
||||||
"github.com/rancher/steve/pkg/schemaserver/store/empty"
|
"github.com/rancher/steve/pkg/schemaserver/store/empty"
|
||||||
"github.com/rancher/steve/pkg/schemaserver/types"
|
"github.com/rancher/steve/pkg/schemaserver/types"
|
||||||
"github.com/rancher/steve/pkg/server/store/proxy"
|
"github.com/rancher/steve/pkg/server/store/proxy"
|
||||||
|
"github.com/rancher/steve/pkg/server/store/switchschema"
|
||||||
|
"github.com/rancher/steve/pkg/server/store/switchstore"
|
||||||
|
"github.com/rancher/wrangler/pkg/data"
|
||||||
"github.com/rancher/wrangler/pkg/schemas/validation"
|
"github.com/rancher/wrangler/pkg/schemas/validation"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/apimachinery/pkg/version"
|
||||||
|
"k8s.io/client-go/discovery"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -31,15 +38,22 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
type Cluster struct {
|
func Register(ctx context.Context, schemas *types.APISchemas, cg proxy.ClientGetter, cluster clustercache.ClusterCache) error {
|
||||||
}
|
k8s, err := cg.AdminK8sInterface()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func Register(ctx context.Context, schemas *types.APISchemas, cg proxy.ClientGetter, cluster clustercache.ClusterCache) {
|
|
||||||
shell := &shell{
|
shell := &shell{
|
||||||
cg: cg,
|
cg: cg,
|
||||||
namespace: "dashboard-shells",
|
namespace: "dashboard-shells",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
picker := &picker{
|
||||||
|
start: time.Now(),
|
||||||
|
discovery: k8s.Discovery(),
|
||||||
|
}
|
||||||
|
|
||||||
cluster.OnAdd(ctx, shell.PurgeOldShell)
|
cluster.OnAdd(ctx, shell.PurgeOldShell)
|
||||||
cluster.OnChange(ctx, func(gvr schema.GroupVersionResource, key string, obj, oldObj runtime.Object) error {
|
cluster.OnChange(ctx, func(gvr schema.GroupVersionResource, key string, obj, oldObj runtime.Object) error {
|
||||||
return shell.PurgeOldShell(gvr, key, obj)
|
return shell.PurgeOldShell(gvr, key, obj)
|
||||||
@ -47,74 +61,112 @@ func Register(ctx context.Context, schemas *types.APISchemas, cg proxy.ClientGet
|
|||||||
schemas.MustImportAndCustomize(Cluster{}, func(schema *types.APISchema) {
|
schemas.MustImportAndCustomize(Cluster{}, func(schema *types.APISchema) {
|
||||||
schema.CollectionMethods = []string{http.MethodGet}
|
schema.CollectionMethods = []string{http.MethodGet}
|
||||||
schema.ResourceMethods = []string{http.MethodGet}
|
schema.ResourceMethods = []string{http.MethodGet}
|
||||||
schema.Store = &Store{}
|
schema.Formatter = Format
|
||||||
|
schema.Store = &switchstore.Store{
|
||||||
|
Picker: picker.Picker,
|
||||||
|
}
|
||||||
schema.LinkHandlers = map[string]http.Handler{
|
schema.LinkHandlers = map[string]http.Handler{
|
||||||
"shell": shell,
|
"shell": shell,
|
||||||
}
|
}
|
||||||
|
|
||||||
schema.Formatter = func(request *types.APIRequest, resource *types.RawResource) {
|
|
||||||
resource.Links["api"] = request.URLBuilder.RelativeToRoot("/k8s/clusters/" + resource.ID)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Cluster struct {
|
||||||
|
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
|
Spec ClusterSpec `json:"spec"`
|
||||||
|
Status ClusterStatus `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ClusterSpec struct {
|
||||||
|
DisplayName string `json:"displayName"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ClusterStatus struct {
|
||||||
|
Driver string `json:"driver"`
|
||||||
|
Version *version.Info `json:"version,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func Format(request *types.APIRequest, resource *types.RawResource) {
|
||||||
|
copy := [][]string{
|
||||||
|
{"spec", "displayName"},
|
||||||
|
{"metadata", "creationTimestamp"},
|
||||||
|
{"status", "driver"},
|
||||||
|
{"status", "version"},
|
||||||
|
}
|
||||||
|
|
||||||
|
from := resource.APIObject.Data()
|
||||||
|
to := data.New()
|
||||||
|
|
||||||
|
for _, keys := range copy {
|
||||||
|
to.SetNested(data.GetValueN(from, keys...), keys...)
|
||||||
|
}
|
||||||
|
|
||||||
|
resource.APIObject.Object = to
|
||||||
|
resource.Links["api"] = request.URLBuilder.RelativeToRoot("/k8s/clusters/" + resource.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Store struct {
|
type Store struct {
|
||||||
empty.Store
|
empty.Store
|
||||||
|
|
||||||
|
start time.Time
|
||||||
|
discovery discovery.DiscoveryInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
func toClusterList(obj types.APIObjectList, err error) (types.APIObjectList, error) {
|
type picker struct {
|
||||||
for i := range obj.Objects {
|
start time.Time
|
||||||
obj.Objects[i], _ = toCluster(obj.Objects[i], err)
|
discovery discovery.DiscoveryInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *picker) Picker(apiOp *types.APIRequest, schema *types.APISchema, verb, id string) (types.Store, error) {
|
||||||
|
clusters := apiOp.Schemas.LookupSchema(rancherCluster)
|
||||||
|
if clusters == nil {
|
||||||
|
return &Store{
|
||||||
|
start: p.start,
|
||||||
|
discovery: p.discovery,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
return obj, err
|
return &switchschema.Store{
|
||||||
}
|
Schema: clusters,
|
||||||
|
}, nil
|
||||||
func toCluster(obj types.APIObject, err error) (types.APIObject, error) {
|
|
||||||
return types.APIObject{
|
|
||||||
Type: "cluster",
|
|
||||||
ID: obj.ID,
|
|
||||||
Object: &Cluster{},
|
|
||||||
}, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) ByID(apiOp *types.APIRequest, schema *types.APISchema, id string) (types.APIObject, error) {
|
func (s *Store) ByID(apiOp *types.APIRequest, schema *types.APISchema, id string) (types.APIObject, error) {
|
||||||
clusters := apiOp.Schemas.LookupSchema(rancherCluster)
|
if id == localID {
|
||||||
if clusters == nil {
|
return s.newLocal(), nil
|
||||||
if id == localID {
|
|
||||||
return local, nil
|
|
||||||
}
|
|
||||||
return types.APIObject{}, validation.NotFound
|
|
||||||
}
|
}
|
||||||
return toCluster(clusters.Store.ByID(apiOp, clusters, id))
|
return types.APIObject{}, validation.NotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) List(apiOp *types.APIRequest, schema *types.APISchema) (types.APIObjectList, error) {
|
func (s *Store) List(apiOp *types.APIRequest, schema *types.APISchema) (types.APIObjectList, error) {
|
||||||
clusters := apiOp.Schemas.LookupSchema(rancherCluster)
|
return types.APIObjectList{
|
||||||
if clusters == nil {
|
Objects: []types.APIObject{
|
||||||
return localList, nil
|
s.newLocal(),
|
||||||
}
|
},
|
||||||
return toClusterList(clusters.Store.List(apiOp, clusters))
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) Watch(apiOp *types.APIRequest, schema *types.APISchema, w types.WatchRequest) (chan types.APIEvent, error) {
|
func (s *Store) newLocal() types.APIObject {
|
||||||
clusters := apiOp.Schemas.LookupSchema(rancherCluster)
|
cluster := &Cluster{
|
||||||
if clusters == nil {
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
return nil, nil
|
CreationTimestamp: metav1.NewTime(s.start),
|
||||||
|
},
|
||||||
|
Spec: ClusterSpec{
|
||||||
|
DisplayName: "Remote",
|
||||||
|
},
|
||||||
|
Status: ClusterStatus{
|
||||||
|
Driver: "remote",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
target, err := clusters.Store.Watch(apiOp, clusters, w)
|
version, err := s.discovery.ServerVersion()
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return nil, err
|
cluster.Status.Version = version
|
||||||
|
}
|
||||||
|
return types.APIObject{
|
||||||
|
Type: "cluster",
|
||||||
|
ID: localID,
|
||||||
|
Object: cluster,
|
||||||
}
|
}
|
||||||
|
|
||||||
result := make(chan types.APIEvent)
|
|
||||||
go func() {
|
|
||||||
defer close(result)
|
|
||||||
for event := range target {
|
|
||||||
event.Object, _ = toCluster(event.Object, nil)
|
|
||||||
result <- event
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
}
|
||||||
|
@ -20,14 +20,15 @@ import (
|
|||||||
"k8s.io/client-go/discovery"
|
"k8s.io/client-go/discovery"
|
||||||
)
|
)
|
||||||
|
|
||||||
func DefaultSchemas(ctx context.Context, baseSchema *types.APISchemas, ccache clustercache.ClusterCache, cg proxy.ClientGetter) *types.APISchemas {
|
func DefaultSchemas(ctx context.Context, baseSchema *types.APISchemas, ccache clustercache.ClusterCache, cg proxy.ClientGetter) (*types.APISchemas, error) {
|
||||||
counts.Register(baseSchema, ccache)
|
counts.Register(baseSchema, ccache)
|
||||||
subscribe.Register(baseSchema)
|
subscribe.Register(baseSchema)
|
||||||
apiroot.Register(baseSchema, []string{"v1"}, []string{"proxy:/apis"})
|
apiroot.Register(baseSchema, []string{"v1"}, []string{"proxy:/apis"})
|
||||||
userpreferences.Register(baseSchema, cg)
|
userpreferences.Register(baseSchema, cg)
|
||||||
clusters.Register(ctx, baseSchema, cg, ccache)
|
|
||||||
helm.Register(baseSchema)
|
helm.Register(baseSchema)
|
||||||
return baseSchema
|
|
||||||
|
err := clusters.Register(ctx, baseSchema, cg, ccache)
|
||||||
|
return baseSchema, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func DefaultSchemaTemplates(cf *client.Factory, lookup accesscontrol.AccessSetLookup, discovery discovery.DiscoveryInterface) []schema.Template {
|
func DefaultSchemaTemplates(cf *client.Factory, lookup accesscontrol.AccessSetLookup, discovery discovery.DiscoveryInterface) []schema.Template {
|
||||||
|
@ -67,7 +67,11 @@ func setup(ctx context.Context, server *Server) (http.Handler, *schema.Collectio
|
|||||||
|
|
||||||
ccache := clustercache.NewClusterCache(ctx, cf.DynamicClient())
|
ccache := clustercache.NewClusterCache(ctx, cf.DynamicClient())
|
||||||
|
|
||||||
server.BaseSchemas = resources.DefaultSchemas(ctx, server.BaseSchemas, ccache, cf)
|
server.BaseSchemas, err = resources.DefaultSchemas(ctx, server.BaseSchemas, ccache, cf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
server.SchemaTemplates = append(server.SchemaTemplates, resources.DefaultSchemaTemplates(cf, asl, server.K8s.Discovery())...)
|
server.SchemaTemplates = append(server.SchemaTemplates, resources.DefaultSchemaTemplates(cf, asl, server.K8s.Discovery())...)
|
||||||
|
|
||||||
cols, err := common.NewDynamicColumns(server.RestConfig)
|
cols, err := common.NewDynamicColumns(server.RestConfig)
|
||||||
|
59
pkg/server/store/switchstore/store.go
Normal file
59
pkg/server/store/switchstore/store.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package switchstore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/rancher/steve/pkg/schemaserver/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StorePicker func(apiOp *types.APIRequest, schema *types.APISchema, verb, id string) (types.Store, error)
|
||||||
|
|
||||||
|
type Store struct {
|
||||||
|
Picker StorePicker
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Store) Delete(apiOp *types.APIRequest, schema *types.APISchema, id string) (types.APIObject, error) {
|
||||||
|
s, err := e.Picker(apiOp, schema, "delete", id)
|
||||||
|
if err != nil {
|
||||||
|
return types.APIObject{}, err
|
||||||
|
}
|
||||||
|
return s.Delete(apiOp, schema, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Store) ByID(apiOp *types.APIRequest, schema *types.APISchema, id string) (types.APIObject, error) {
|
||||||
|
s, err := e.Picker(apiOp, schema, "get", id)
|
||||||
|
if err != nil {
|
||||||
|
return types.APIObject{}, err
|
||||||
|
}
|
||||||
|
return s.ByID(apiOp, schema, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Store) List(apiOp *types.APIRequest, schema *types.APISchema) (types.APIObjectList, error) {
|
||||||
|
s, err := e.Picker(apiOp, schema, "list", "")
|
||||||
|
if err != nil {
|
||||||
|
return types.APIObjectList{}, err
|
||||||
|
}
|
||||||
|
return s.List(apiOp, schema)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Store) Create(apiOp *types.APIRequest, schema *types.APISchema, data types.APIObject) (types.APIObject, error) {
|
||||||
|
s, err := e.Picker(apiOp, schema, "create", "")
|
||||||
|
if err != nil {
|
||||||
|
return types.APIObject{}, err
|
||||||
|
}
|
||||||
|
return s.Create(apiOp, schema, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Store) Update(apiOp *types.APIRequest, schema *types.APISchema, data types.APIObject, id string) (types.APIObject, error) {
|
||||||
|
s, err := e.Picker(apiOp, schema, "update", id)
|
||||||
|
if err != nil {
|
||||||
|
return types.APIObject{}, err
|
||||||
|
}
|
||||||
|
return s.Update(apiOp, schema, data, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Store) Watch(apiOp *types.APIRequest, schema *types.APISchema, wr types.WatchRequest) (chan types.APIEvent, error) {
|
||||||
|
s, err := e.Picker(apiOp, schema, "watch", "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return s.Watch(apiOp, schema, wr)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user