mirror of
https://github.com/niusmallnan/steve.git
synced 2025-09-08 16:39:36 +00:00
RBAC caching
This commit is contained in:
@@ -3,15 +3,15 @@ package schema
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/rancher/steve/pkg/accesscontrol"
|
||||
"github.com/rancher/steve/pkg/attributes"
|
||||
"github.com/rancher/steve/pkg/schema/table"
|
||||
"github.com/rancher/steve/pkg/schemaserver/types"
|
||||
"github.com/rancher/wrangler/pkg/data"
|
||||
"github.com/rancher/wrangler/pkg/name"
|
||||
"github.com/rancher/wrangler/pkg/schemas"
|
||||
"github.com/sirupsen/logrus"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/cache"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
)
|
||||
|
||||
@@ -28,32 +28,36 @@ type Collection struct {
|
||||
templates map[string]*Template
|
||||
byGVR map[schema.GroupVersionResource]string
|
||||
byGVK map[schema.GroupVersionKind]string
|
||||
cache *cache.LRUExpireCache
|
||||
lock sync.RWMutex
|
||||
|
||||
as accesscontrol.AccessSetLookup
|
||||
ctx context.Context
|
||||
running map[string]func()
|
||||
as accesscontrol.AccessSetLookup
|
||||
}
|
||||
|
||||
type Template struct {
|
||||
Group string
|
||||
Kind string
|
||||
ID string
|
||||
Customize func(*types.APISchema)
|
||||
Formatter types.Formatter
|
||||
Store types.Store
|
||||
Start func(ctx context.Context) error
|
||||
StoreFactory func(types.Store) types.Store
|
||||
Mapper schemas.Mapper
|
||||
Columns []table.Column
|
||||
ComputedColumns func(data.Object)
|
||||
Group string
|
||||
Kind string
|
||||
ID string
|
||||
Customize func(*types.APISchema)
|
||||
Formatter types.Formatter
|
||||
Store types.Store
|
||||
Start func(ctx context.Context) error
|
||||
StoreFactory func(types.Store) types.Store
|
||||
}
|
||||
|
||||
func NewCollection(baseSchema *types.APISchemas, access accesscontrol.AccessSetLookup) *Collection {
|
||||
func NewCollection(ctx context.Context, baseSchema *types.APISchemas, access accesscontrol.AccessSetLookup) *Collection {
|
||||
return &Collection{
|
||||
baseSchema: baseSchema,
|
||||
schemas: map[string]*types.APISchema{},
|
||||
templates: map[string]*Template{},
|
||||
byGVR: map[schema.GroupVersionResource]string{},
|
||||
byGVK: map[schema.GroupVersionKind]string{},
|
||||
cache: cache.NewLRUExpireCache(1000),
|
||||
ctx: ctx,
|
||||
as: access,
|
||||
running: map[string]func(){},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,18 +74,58 @@ func (c *Collection) Reset(schemas map[string]*types.APISchema) {
|
||||
if gvk.Kind != "" {
|
||||
byGVK[gvk] = s.ID
|
||||
}
|
||||
|
||||
c.applyTemplates(s)
|
||||
}
|
||||
|
||||
c.lock.Lock()
|
||||
c.startStopTemplate(schemas)
|
||||
c.schemas = schemas
|
||||
c.byGVR = byGVR
|
||||
c.byGVK = byGVK
|
||||
for _, k := range c.cache.Keys() {
|
||||
c.cache.Remove(k)
|
||||
}
|
||||
c.lock.Unlock()
|
||||
}
|
||||
|
||||
func (c *Collection) startStopTemplate(schemas map[string]*types.APISchema) {
|
||||
for id := range schemas {
|
||||
if _, ok := c.running[id]; ok {
|
||||
continue
|
||||
}
|
||||
template := c.templates[id]
|
||||
if template == nil || template.Start == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
subCtx, cancel := context.WithCancel(c.ctx)
|
||||
if err := template.Start(subCtx); err != nil {
|
||||
logrus.Errorf("failed to start schema template: %s", id)
|
||||
continue
|
||||
}
|
||||
c.running[id] = cancel
|
||||
}
|
||||
|
||||
for id, cancel := range c.running {
|
||||
if _, ok := schemas[id]; !ok {
|
||||
cancel()
|
||||
delete(c.running, id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Collection) Schema(id string) *types.APISchema {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
|
||||
return c.schemas[id]
|
||||
}
|
||||
|
||||
func (c *Collection) IDs() (result []string) {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
|
||||
seen := map[string]bool{}
|
||||
for _, id := range c.byGVR {
|
||||
if seen[id] {
|
||||
@@ -94,6 +138,9 @@ func (c *Collection) IDs() (result []string) {
|
||||
}
|
||||
|
||||
func (c *Collection) ByGVR(gvr schema.GroupVersionResource) string {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
|
||||
id, ok := c.byGVR[gvr]
|
||||
if ok {
|
||||
return id
|
||||
@@ -107,14 +154,16 @@ func (c *Collection) ByGVR(gvr schema.GroupVersionResource) string {
|
||||
}
|
||||
|
||||
func (c *Collection) ByGVK(gvk schema.GroupVersionKind) string {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
|
||||
return c.byGVK[gvk]
|
||||
}
|
||||
|
||||
func (c *Collection) TemplateForSchemaID(id string) *Template {
|
||||
return c.templates[id]
|
||||
}
|
||||
|
||||
func (c *Collection) AddTemplate(template *Template) {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
|
||||
if template.Kind != "" {
|
||||
c.templates[template.Group+"/"+template.Kind] = template
|
||||
}
|
||||
|
@@ -73,7 +73,7 @@ func refresh(gv schema.GroupVersion, groupToPreferredVersion map[string]string,
|
||||
if schema == nil {
|
||||
schema = &types.APISchema{
|
||||
Schema: &schemas.Schema{
|
||||
ID: GVKToSchemaID(gvk),
|
||||
ID: GVKToSchemaID(gvk),
|
||||
},
|
||||
}
|
||||
attributes.SetGVK(schema, gvk)
|
||||
|
@@ -3,13 +3,12 @@ package schema
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/rancher/steve/pkg/accesscontrol"
|
||||
"github.com/rancher/steve/pkg/attributes"
|
||||
"github.com/rancher/steve/pkg/schema/table"
|
||||
"github.com/rancher/steve/pkg/schemaserver/builtin"
|
||||
"github.com/rancher/steve/pkg/schemaserver/types"
|
||||
"github.com/rancher/wrangler/pkg/schemas"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
)
|
||||
|
||||
@@ -18,19 +17,31 @@ func newSchemas() (*types.APISchemas, error) {
|
||||
if err := apiSchemas.AddSchemas(builtin.Schemas); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
apiSchemas.InternalSchemas.DefaultMapper = func() schemas.Mapper {
|
||||
return newDefaultMapper()
|
||||
}
|
||||
|
||||
return apiSchemas, nil
|
||||
}
|
||||
|
||||
func (c *Collection) Schemas(user user.Info) (*types.APISchemas, error) {
|
||||
access := c.as.AccessFor(user)
|
||||
return c.schemasForSubject(access)
|
||||
val, ok := c.cache.Get(access.ID)
|
||||
if ok {
|
||||
schemas, _ := val.(*types.APISchemas)
|
||||
return schemas, nil
|
||||
}
|
||||
|
||||
schemas, err := c.schemasForSubject(access)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c.cache.Add(access.ID, schemas, 24*time.Hour)
|
||||
return schemas, nil
|
||||
}
|
||||
|
||||
func (c *Collection) schemasForSubject(access *accesscontrol.AccessSet) (*types.APISchemas, error) {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
|
||||
result, err := newSchemas()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -81,8 +92,6 @@ func (c *Collection) schemasForSubject(access *accesscontrol.AccessSet) (*types.
|
||||
s.CollectionMethods = append(s.CollectionMethods, http.MethodPost)
|
||||
}
|
||||
|
||||
c.applyTemplates(result, s)
|
||||
|
||||
if err := result.AddSchema(*s); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -91,7 +100,10 @@ func (c *Collection) schemasForSubject(access *accesscontrol.AccessSet) (*types.
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *Collection) applyTemplates(schemas *types.APISchemas, schema *types.APISchema) {
|
||||
func (c *Collection) applyTemplates(schema *types.APISchema) {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
|
||||
templates := []*Template{
|
||||
c.templates[schema.ID],
|
||||
c.templates[fmt.Sprintf("%s/%s", attributes.Group(schema), attributes.Kind(schema))],
|
||||
@@ -102,9 +114,6 @@ func (c *Collection) applyTemplates(schemas *types.APISchemas, schema *types.API
|
||||
if t == nil {
|
||||
continue
|
||||
}
|
||||
if t.Mapper != nil {
|
||||
schemas.InternalSchemas.AddMapper(schema.ID, t.Mapper)
|
||||
}
|
||||
if schema.Formatter == nil {
|
||||
schema.Formatter = t.Formatter
|
||||
}
|
||||
@@ -118,8 +127,5 @@ func (c *Collection) applyTemplates(schemas *types.APISchemas, schema *types.API
|
||||
if t.Customize != nil {
|
||||
t.Customize(schema)
|
||||
}
|
||||
if len(t.Columns) > 0 {
|
||||
schemas.InternalSchemas.AddMapper(schema.ID, table.NewColumns(t.ComputedColumns, t.Columns...))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user