mirror of
https://github.com/niusmallnan/steve.git
synced 2025-09-13 21:39:45 +00:00
Refactor
This commit is contained in:
@@ -3,20 +3,19 @@ package apigroups
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/rancher/norman/v2/pkg/data"
|
||||
"github.com/rancher/norman/v2/pkg/store/empty"
|
||||
"github.com/rancher/norman/v2/pkg/types"
|
||||
"github.com/rancher/steve/pkg/schemaserver/store/empty"
|
||||
"github.com/rancher/steve/pkg/schemaserver/types"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/discovery"
|
||||
)
|
||||
|
||||
func Register(schemas *types.Schemas, discovery discovery.DiscoveryInterface) {
|
||||
schemas.MustImportAndCustomize(v1.APIGroup{}, func(schema *types.Schema) {
|
||||
func Register(schemas *types.APISchemas, discovery discovery.DiscoveryInterface) {
|
||||
schemas.MustImportAndCustomize(v1.APIGroup{}, func(schema *types.APISchema) {
|
||||
schema.CollectionMethods = []string{http.MethodGet}
|
||||
schema.ResourceMethods = []string{http.MethodGet}
|
||||
schema.Store = NewStore(discovery)
|
||||
schema.Formatter = func(request *types.APIRequest, resource *types.RawResource) {
|
||||
resource.ID = data.Object(resource.Values).String("name")
|
||||
resource.ID = resource.APIObject.Data().String("name")
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -34,38 +33,32 @@ func NewStore(discovery discovery.DiscoveryInterface) types.Store {
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Store) ByID(apiOp *types.APIRequest, schema *types.Schema, id string) (types.APIObject, error) {
|
||||
groupList, err := e.discovery.ServerGroups()
|
||||
if err != nil {
|
||||
return types.APIObject{}, err
|
||||
}
|
||||
|
||||
if id == "core" {
|
||||
id = ""
|
||||
}
|
||||
|
||||
for _, group := range groupList.Groups {
|
||||
if group.Name == id {
|
||||
return types.ToAPI(group), nil
|
||||
}
|
||||
}
|
||||
|
||||
return types.APIObject{}, nil
|
||||
func (e *Store) ByID(apiOp *types.APIRequest, schema *types.APISchema, id string) (types.APIObject, error) {
|
||||
return types.DefaultByID(e, apiOp, schema, id)
|
||||
}
|
||||
|
||||
func (e *Store) List(apiOp *types.APIRequest, schema *types.Schema, opt *types.QueryOptions) (types.APIObject, error) {
|
||||
groupList, err := e.discovery.ServerGroups()
|
||||
if err != nil {
|
||||
return types.APIObject{}, err
|
||||
func toAPIObject(schema *types.APISchema, group v1.APIGroup) types.APIObject {
|
||||
if group.Name == "" {
|
||||
group.Name = "core"
|
||||
}
|
||||
return types.APIObject{
|
||||
Type: schema.ID,
|
||||
ID: group.Name,
|
||||
Object: group,
|
||||
}
|
||||
|
||||
var result []interface{}
|
||||
}
|
||||
|
||||
func (e *Store) List(apiOp *types.APIRequest, schema *types.APISchema) (types.APIObjectList, error) {
|
||||
groupList, err := e.discovery.ServerGroups()
|
||||
if err != nil {
|
||||
return types.APIObjectList{}, err
|
||||
}
|
||||
|
||||
var result types.APIObjectList
|
||||
for _, item := range groupList.Groups {
|
||||
if item.Name == "" {
|
||||
item.Name = "core"
|
||||
}
|
||||
result = append(result, item)
|
||||
result.Objects = append(result.Objects, toAPIObject(schema, item))
|
||||
}
|
||||
|
||||
return types.ToAPI(result), nil
|
||||
return result, nil
|
||||
}
|
||||
|
@@ -1,9 +1,11 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"github.com/rancher/norman/v2/pkg/types"
|
||||
"github.com/rancher/steve/pkg/attributes"
|
||||
"github.com/rancher/steve/pkg/table"
|
||||
"github.com/rancher/steve/pkg/schema/table"
|
||||
"github.com/rancher/steve/pkg/schemaserver/types"
|
||||
"github.com/rancher/wrangler/pkg/schemas"
|
||||
"github.com/rancher/wrangler/pkg/schemas/mappers"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -22,12 +24,15 @@ var (
|
||||
)
|
||||
|
||||
type DefaultColumns struct {
|
||||
types.EmptyMapper
|
||||
mappers.EmptyMapper
|
||||
}
|
||||
|
||||
func (d *DefaultColumns) ModifySchema(schema *types.Schema, schemas *types.Schemas) error {
|
||||
if attributes.Columns(schema) == nil {
|
||||
attributes.SetColumns(schema, []table.Column{
|
||||
func (d *DefaultColumns) ModifySchema(schema *schemas.Schema, schemas *schemas.Schemas) error {
|
||||
as := &types.APISchema{
|
||||
Schema: schema,
|
||||
}
|
||||
if attributes.Columns(as) == nil {
|
||||
attributes.SetColumns(as, []table.Column{
|
||||
NameColumn,
|
||||
CreatedColumn,
|
||||
})
|
||||
|
111
pkg/server/resources/common/dynamiccolumns.go
Normal file
111
pkg/server/resources/common/dynamiccolumns.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/rancher/steve/pkg/attributes"
|
||||
"github.com/rancher/steve/pkg/schema/table"
|
||||
"github.com/rancher/steve/pkg/schemaserver/types"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
type DynamicColumns struct {
|
||||
client *rest.RESTClient
|
||||
}
|
||||
|
||||
func NewDynamicColumns(config *rest.Config) (*DynamicColumns, error) {
|
||||
c, err := newClient(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &DynamicColumns{
|
||||
client: c,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func hasGet(methods []string) bool {
|
||||
for _, method := range methods {
|
||||
if method == http.MethodGet {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (d *DynamicColumns) SetColumns(schema *types.APISchema) error {
|
||||
if attributes.Columns(schema) != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
gvr := attributes.GVR(schema)
|
||||
if gvr.Resource == "" {
|
||||
return nil
|
||||
}
|
||||
nsed := attributes.Namespaced(schema)
|
||||
|
||||
if !hasGet(schema.CollectionMethods) {
|
||||
return nil
|
||||
}
|
||||
|
||||
r := d.client.Get()
|
||||
if gvr.Group == "" {
|
||||
r.Prefix("api")
|
||||
} else {
|
||||
r.Prefix("apis", gvr.Group)
|
||||
}
|
||||
r.Prefix(gvr.Version)
|
||||
if nsed {
|
||||
r.Prefix("namespaces", "default")
|
||||
}
|
||||
r.Prefix(gvr.Resource)
|
||||
|
||||
obj, err := r.Do().Get()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t, ok := obj.(*metav1.Table)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
var cols []table.Column
|
||||
for _, cd := range t.ColumnDefinitions {
|
||||
cols = append(cols, table.Column{
|
||||
Name: cd.Name,
|
||||
Field: "metadata.computed.fields." + cd.Name,
|
||||
Type: cd.Type,
|
||||
Format: cd.Format,
|
||||
})
|
||||
}
|
||||
|
||||
if len(cols) > 0 {
|
||||
attributes.SetColumns(schema, cols)
|
||||
schema.Attributes["server-side-column"] = "true"
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func newClient(config *rest.Config) (*rest.RESTClient, error) {
|
||||
scheme := runtime.NewScheme()
|
||||
if err := metav1.AddMetaToScheme(scheme); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := metav1beta1.AddMetaToScheme(scheme); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config = rest.CopyConfig(config)
|
||||
config.UserAgent = rest.DefaultKubernetesUserAgent()
|
||||
config.AcceptContentTypes = "application/json;as=Table;v=v1beta1;g=meta.k8s.io"
|
||||
config.ContentType = "application/json;as=Table;v=v1beta1;g=meta.k8s.io"
|
||||
config.GroupVersion = &schema.GroupVersion{}
|
||||
config.NegotiatedSerializer = serializer.NewCodecFactory(scheme)
|
||||
config.APIPath = "/"
|
||||
return rest.RESTClientFor(config)
|
||||
}
|
@@ -1,25 +1,27 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"github.com/rancher/norman/v2/pkg/store/proxy"
|
||||
"github.com/rancher/norman/v2/pkg/types"
|
||||
"github.com/rancher/norman/v2/pkg/types/convert"
|
||||
"github.com/rancher/norman/v2/pkg/types/values"
|
||||
"github.com/rancher/steve/pkg/resources/schema"
|
||||
"github.com/rancher/steve/pkg/schema"
|
||||
"github.com/rancher/steve/pkg/schemaserver/types"
|
||||
"github.com/rancher/steve/pkg/server/store/proxy"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
)
|
||||
|
||||
func Register(collection *schema.Collection, clientGetter proxy.ClientGetter) error {
|
||||
collection.AddTemplate(&schema.Template{
|
||||
func DefaultTemplate(clientGetter proxy.ClientGetter) schema.Template {
|
||||
return schema.Template{
|
||||
Store: proxy.NewProxyStore(clientGetter),
|
||||
Formatter: Formatter,
|
||||
Mapper: &DefaultColumns{},
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func Formatter(request *types.APIRequest, resource *types.RawResource) {
|
||||
selfLink := convert.ToString(values.GetValueN(resource.Values, "metadata", "selfLink"))
|
||||
meta, err := meta.Accessor(resource.APIObject.Object)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
selfLink := meta.GetSelfLink()
|
||||
if selfLink == "" {
|
||||
return
|
||||
}
|
||||
|
@@ -5,15 +5,14 @@ import (
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
schema2 "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
"github.com/rancher/norman/v2/pkg/store/empty"
|
||||
"github.com/rancher/norman/v2/pkg/types"
|
||||
"github.com/rancher/steve/pkg/accesscontrol"
|
||||
"github.com/rancher/steve/pkg/attributes"
|
||||
"github.com/rancher/steve/pkg/clustercache"
|
||||
"github.com/rancher/steve/pkg/schemaserver/store/empty"
|
||||
"github.com/rancher/steve/pkg/schemaserver/types"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
schema2 "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -24,11 +23,11 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
func Register(schemas *types.Schemas, ccache clustercache.ClusterCache) {
|
||||
schemas.MustImportAndCustomize(Count{}, func(schema *types.Schema) {
|
||||
func Register(schemas *types.APISchemas, ccache clustercache.ClusterCache) {
|
||||
schemas.MustImportAndCustomize(Count{}, func(schema *types.APISchema) {
|
||||
schema.CollectionMethods = []string{http.MethodGet}
|
||||
schema.ResourceMethods = []string{http.MethodGet}
|
||||
schema.Attributes["access"] = accesscontrol.AccessListMap{
|
||||
schema.Attributes["access"] = accesscontrol.AccessListByVerb{
|
||||
"watch": accesscontrol.AccessList{
|
||||
{
|
||||
Namespace: "*",
|
||||
@@ -58,27 +57,39 @@ type Store struct {
|
||||
ccache clustercache.ClusterCache
|
||||
}
|
||||
|
||||
func (s *Store) ByID(apiOp *types.APIRequest, schema *types.Schema, id string) (types.APIObject, error) {
|
||||
c := s.getCount(apiOp)
|
||||
return types.ToAPI(c), nil
|
||||
func toAPIObject(c Count) types.APIObject {
|
||||
return types.APIObject{
|
||||
Type: "count",
|
||||
ID: c.ID,
|
||||
Object: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Store) List(apiOp *types.APIRequest, schema *types.Schema, opt *types.QueryOptions) (types.APIObject, error) {
|
||||
func (s *Store) ByID(apiOp *types.APIRequest, schema *types.APISchema, id string) (types.APIObject, error) {
|
||||
c := s.getCount(apiOp)
|
||||
return types.ToAPI([]interface{}{c}), nil
|
||||
return toAPIObject(c), nil
|
||||
}
|
||||
|
||||
func (s *Store) Watch(apiOp *types.APIRequest, schema *types.Schema, w types.WatchRequest) (chan types.APIEvent, error) {
|
||||
func (s *Store) List(apiOp *types.APIRequest, schema *types.APISchema) (types.APIObjectList, error) {
|
||||
c := s.getCount(apiOp)
|
||||
return types.APIObjectList{
|
||||
Objects: []types.APIObject{
|
||||
toAPIObject(c),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) Watch(apiOp *types.APIRequest, schema *types.APISchema, w types.WatchRequest) (chan types.APIEvent, error) {
|
||||
var (
|
||||
result = make(chan types.APIEvent, 100)
|
||||
counts map[string]ItemCount
|
||||
gvrToSchema = map[schema2.GroupVersionResource]*types.Schema{}
|
||||
gvrToSchema = map[schema2.GroupVersionResource]*types.APISchema{}
|
||||
countLock sync.Mutex
|
||||
)
|
||||
|
||||
counts = s.getCount(apiOp).Counts
|
||||
for id := range counts {
|
||||
schema := apiOp.Schemas.Schema(id)
|
||||
schema := apiOp.Schemas.LookupSchema(id)
|
||||
if schema == nil {
|
||||
continue
|
||||
}
|
||||
@@ -107,11 +118,6 @@ func (s *Store) Watch(apiOp *types.APIRequest, schema *types.Schema, w types.Wat
|
||||
return nil
|
||||
}
|
||||
|
||||
apiObj := apiOp.Filter(nil, schema, types.ToAPI(obj))
|
||||
if apiObj.IsNil() {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, namespace, revision, ok := getInfo(obj)
|
||||
if !ok {
|
||||
return nil
|
||||
@@ -151,7 +157,7 @@ func (s *Store) Watch(apiOp *types.APIRequest, schema *types.Schema, w types.Wat
|
||||
result <- types.APIEvent{
|
||||
Name: "resource.change",
|
||||
ResourceType: "counts",
|
||||
Object: types.ToAPI(Count{
|
||||
Object: toAPIObject(Count{
|
||||
ID: "count",
|
||||
Counts: countsCopy,
|
||||
}),
|
||||
@@ -170,8 +176,8 @@ func (s *Store) Watch(apiOp *types.APIRequest, schema *types.Schema, w types.Wat
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *Store) schemasToWatch(apiOp *types.APIRequest) (result []*types.Schema) {
|
||||
for _, schema := range apiOp.Schemas.Schemas() {
|
||||
func (s *Store) schemasToWatch(apiOp *types.APIRequest) (result []*types.APISchema) {
|
||||
for _, schema := range apiOp.Schemas.Schemas {
|
||||
if ignore[schema.ID] {
|
||||
continue
|
||||
}
|
||||
|
@@ -1,38 +1,28 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"github.com/rancher/norman/v2/pkg/store/apiroot"
|
||||
"github.com/rancher/norman/v2/pkg/subscribe"
|
||||
"github.com/rancher/norman/v2/pkg/types"
|
||||
"github.com/rancher/steve/pkg/accesscontrol"
|
||||
"github.com/rancher/steve/pkg/client"
|
||||
"github.com/rancher/steve/pkg/clustercache"
|
||||
"github.com/rancher/steve/pkg/resources/apigroups"
|
||||
"github.com/rancher/steve/pkg/resources/common"
|
||||
"github.com/rancher/steve/pkg/resources/core"
|
||||
"github.com/rancher/steve/pkg/resources/counts"
|
||||
"github.com/rancher/steve/pkg/resources/schema"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"github.com/rancher/steve/pkg/schema"
|
||||
"github.com/rancher/steve/pkg/schemaserver/store/apiroot"
|
||||
"github.com/rancher/steve/pkg/schemaserver/subscribe"
|
||||
"github.com/rancher/steve/pkg/schemaserver/types"
|
||||
"github.com/rancher/steve/pkg/server/resources/apigroups"
|
||||
"github.com/rancher/steve/pkg/server/resources/common"
|
||||
"github.com/rancher/steve/pkg/server/resources/counts"
|
||||
"k8s.io/client-go/discovery"
|
||||
)
|
||||
|
||||
func SchemaFactory(
|
||||
cf *client.Factory,
|
||||
as *accesscontrol.AccessStore,
|
||||
k8s kubernetes.Interface,
|
||||
ccache clustercache.ClusterCache,
|
||||
) (*schema.Collection, error) {
|
||||
baseSchema := types.EmptySchemas()
|
||||
collection := schema.NewCollection(baseSchema, as)
|
||||
|
||||
core.Register(collection)
|
||||
func DefaultSchemas(baseSchema *types.APISchemas, discovery discovery.DiscoveryInterface, ccache clustercache.ClusterCache) *types.APISchemas {
|
||||
counts.Register(baseSchema, ccache)
|
||||
subscribe.Register(baseSchema)
|
||||
apigroups.Register(baseSchema, k8s.Discovery())
|
||||
apigroups.Register(baseSchema, discovery)
|
||||
apiroot.Register(baseSchema, []string{"v1"}, []string{"proxy:/apis"})
|
||||
|
||||
if err := common.Register(collection, cf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return collection, nil
|
||||
return baseSchema
|
||||
}
|
||||
|
||||
func DefaultSchemaTemplates(cf *client.Factory) []schema.Template {
|
||||
return []schema.Template{
|
||||
common.DefaultTemplate(cf),
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user