mirror of
https://github.com/rancher/steve.git
synced 2025-07-01 09:12:12 +00:00
* Copy pkg/cache/sql from lasso to pkg/sqlcache * Rename import from github.com/rancher/lasso/pkg/cache/sql to github.com/rancher/steve/pkg/sqlcache * Fix filter.Match -> filter.Matches * go mod tidy * Fix lint errors * Remove lasso SQL cache mentions * Fix more CI lint errors * fix goimports Signed-off-by: Silvio Moioli <silvio@moioli.net> * fix tests (Match -> Matches) Signed-off-by: Silvio Moioli <silvio@moioli.net> * Fix Sort order --------- Signed-off-by: Silvio Moioli <silvio@moioli.net> Co-authored-by: Silvio Moioli <silvio@moioli.net>
153 lines
4.6 KiB
Go
153 lines
4.6 KiB
Go
// Package sqlpartition implements a store which converts a request to partitions based on the user's rbac for
|
|
// the resource. For example, a user may request all items of resource A, but only have permissions for resource A in
|
|
// namespaces x,y,z. The partitions will then store that information and be passed to the next store.
|
|
package sqlpartition
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/rancher/apiserver/pkg/types"
|
|
"github.com/rancher/steve/pkg/accesscontrol"
|
|
cachepartition "github.com/rancher/steve/pkg/sqlcache/partition"
|
|
"github.com/rancher/steve/pkg/stores/partition"
|
|
)
|
|
|
|
// Partitioner is an interface for interacting with partitions.
|
|
type Partitioner interface {
|
|
All(apiOp *types.APIRequest, schema *types.APISchema, verb, id string) ([]cachepartition.Partition, error)
|
|
Store() UnstructuredStore
|
|
}
|
|
|
|
type SchemaColumnSetter interface {
|
|
SetColumns(ctx context.Context, schema *types.APISchema) error
|
|
}
|
|
|
|
// Store implements types.proxyStore for partitions.
|
|
type Store struct {
|
|
Partitioner Partitioner
|
|
asl accesscontrol.AccessSetLookup
|
|
sqlReservedFields map[string]bool
|
|
}
|
|
|
|
// NewStore creates a types.proxyStore implementation with a partitioner
|
|
func NewStore(store UnstructuredStore, asl accesscontrol.AccessSetLookup) *Store {
|
|
s := &Store{
|
|
Partitioner: &rbacPartitioner{
|
|
proxyStore: store,
|
|
},
|
|
asl: asl,
|
|
}
|
|
sqlReservedFields := map[string]bool{}
|
|
for key, value := range types.ReservedFields {
|
|
if key == "id" {
|
|
continue
|
|
}
|
|
sqlReservedFields[key] = value
|
|
}
|
|
s.sqlReservedFields = sqlReservedFields
|
|
|
|
return s
|
|
}
|
|
|
|
// Delete deletes an object from a store.
|
|
func (s *Store) Delete(apiOp *types.APIRequest, schema *types.APISchema, id string) (types.APIObject, error) {
|
|
target := s.Partitioner.Store()
|
|
|
|
obj, warnings, err := target.Delete(apiOp, schema, id)
|
|
if err != nil {
|
|
return types.APIObject{}, err
|
|
}
|
|
return partition.ToAPI(schema, obj, warnings, types.ReservedFields), nil
|
|
}
|
|
|
|
// ByID looks up a single object by its ID.
|
|
func (s *Store) ByID(apiOp *types.APIRequest, schema *types.APISchema, id string) (types.APIObject, error) {
|
|
target := s.Partitioner.Store()
|
|
|
|
obj, warnings, err := target.ByID(apiOp, schema, id)
|
|
if err != nil {
|
|
return types.APIObject{}, err
|
|
}
|
|
return partition.ToAPI(schema, obj, warnings, types.ReservedFields), nil
|
|
}
|
|
|
|
// List returns a list of objects across all applicable partitions.
|
|
// If pagination parameters are used, it returns a segment of the list.
|
|
func (s *Store) List(apiOp *types.APIRequest, schema *types.APISchema) (types.APIObjectList, error) {
|
|
var (
|
|
result types.APIObjectList
|
|
)
|
|
|
|
partitions, err := s.Partitioner.All(apiOp, schema, "list", "")
|
|
if err != nil {
|
|
return result, err
|
|
}
|
|
|
|
store := s.Partitioner.Store()
|
|
|
|
list, total, continueToken, err := store.ListByPartitions(apiOp, schema, partitions)
|
|
if err != nil {
|
|
return result, err
|
|
}
|
|
|
|
result.Count = total
|
|
|
|
for _, item := range list {
|
|
item := item.DeepCopy()
|
|
// the sql cache automatically adds the ID through a transformFunc. Because of this, we have a different set of reserved fields for the SQL cache
|
|
result.Objects = append(result.Objects, partition.ToAPI(schema, item, nil, s.sqlReservedFields))
|
|
}
|
|
|
|
result.Revision = ""
|
|
result.Continue = continueToken
|
|
return result, nil
|
|
}
|
|
|
|
// Create creates a single object in the store.
|
|
func (s *Store) Create(apiOp *types.APIRequest, schema *types.APISchema, data types.APIObject) (types.APIObject, error) {
|
|
target := s.Partitioner.Store()
|
|
|
|
obj, warnings, err := target.Create(apiOp, schema, data)
|
|
if err != nil {
|
|
return types.APIObject{}, err
|
|
}
|
|
return partition.ToAPI(schema, obj, warnings, types.ReservedFields), nil
|
|
}
|
|
|
|
// Update updates a single object in the store.
|
|
func (s *Store) Update(apiOp *types.APIRequest, schema *types.APISchema, data types.APIObject, id string) (types.APIObject, error) {
|
|
target := s.Partitioner.Store()
|
|
|
|
obj, warnings, err := target.Update(apiOp, schema, data, id)
|
|
if err != nil {
|
|
return types.APIObject{}, err
|
|
}
|
|
return partition.ToAPI(schema, obj, warnings, types.ReservedFields), nil
|
|
}
|
|
|
|
// Watch returns a channel of events for a list or resource.
|
|
func (s *Store) Watch(apiOp *types.APIRequest, schema *types.APISchema, wr types.WatchRequest) (chan types.APIEvent, error) {
|
|
partitions, err := s.Partitioner.All(apiOp, schema, "watch", wr.ID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
store := s.Partitioner.Store()
|
|
|
|
response := make(chan types.APIEvent)
|
|
c, err := store.WatchByPartitions(apiOp, schema, wr, partitions)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
go func() {
|
|
defer close(response)
|
|
|
|
for i := range c {
|
|
response <- partition.ToAPIEvent(nil, schema, i)
|
|
}
|
|
}()
|
|
|
|
return response, nil
|
|
}
|