mirror of
https://github.com/niusmallnan/steve.git
synced 2025-09-01 13:18:25 +00:00
Add namespace filtering
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/rancher/steve/pkg/accesscontrol"
|
||||
"github.com/rancher/steve/pkg/auth"
|
||||
"github.com/rancher/steve/pkg/client"
|
||||
"github.com/rancher/steve/pkg/schema"
|
||||
"github.com/rancher/steve/pkg/schemaserver/types"
|
||||
"github.com/rancher/steve/pkg/server/router"
|
||||
@@ -29,6 +30,7 @@ type Server struct {
|
||||
|
||||
RestConfig *rest.Config
|
||||
|
||||
ClientFactory *client.Factory
|
||||
BaseSchemas *types.APISchemas
|
||||
AccessSetLookup accesscontrol.AccessSetLookup
|
||||
SchemaTemplates []schema.Template
|
||||
|
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/rancher/steve/pkg/clustercache"
|
||||
"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"
|
||||
@@ -16,7 +15,6 @@ import (
|
||||
|
||||
func DefaultSchemas(baseSchema *types.APISchemas, discovery discovery.DiscoveryInterface, ccache clustercache.ClusterCache) *types.APISchemas {
|
||||
counts.Register(baseSchema, ccache)
|
||||
subscribe.Register(baseSchema)
|
||||
apigroups.Register(baseSchema, discovery)
|
||||
apiroot.Register(baseSchema, []string{"v1"}, []string{"proxy:/apis"})
|
||||
return baseSchema
|
||||
|
@@ -45,13 +45,18 @@ func setDefaults(server *Server) error {
|
||||
}
|
||||
|
||||
func setup(ctx context.Context, server *Server) (http.Handler, *schema.Collection, error) {
|
||||
if err := setDefaults(server); err != nil {
|
||||
err := setDefaults(server)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
cf, err := client.NewFactory(server.RestConfig, server.AuthMiddleware != nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
cf := server.ClientFactory
|
||||
if cf == nil {
|
||||
cf, err = client.NewFactory(server.RestConfig, server.AuthMiddleware != nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
server.ClientFactory = cf
|
||||
}
|
||||
|
||||
asl := server.AccessSetLookup
|
||||
|
@@ -32,8 +32,10 @@ var (
|
||||
type ClientGetter interface {
|
||||
Client(ctx *types.APIRequest, schema *types.APISchema, namespace string) (dynamic.ResourceInterface, error)
|
||||
AdminClient(ctx *types.APIRequest, schema *types.APISchema, namespace string) (dynamic.ResourceInterface, error)
|
||||
ClientForWatch(ctx *types.APIRequest, schema *types.APISchema, namespace string) (dynamic.ResourceInterface, error)
|
||||
AdminClientForWatch(ctx *types.APIRequest, schema *types.APISchema, namespace string) (dynamic.ResourceInterface, error)
|
||||
TableClient(ctx *types.APIRequest, schema *types.APISchema, namespace string) (dynamic.ResourceInterface, error)
|
||||
TableAdminClient(ctx *types.APIRequest, schema *types.APISchema, namespace string) (dynamic.ResourceInterface, error)
|
||||
TableClientForWatch(ctx *types.APIRequest, schema *types.APISchema, namespace string) (dynamic.ResourceInterface, error)
|
||||
TableAdminClientForWatch(ctx *types.APIRequest, schema *types.APISchema, namespace string) (dynamic.ResourceInterface, error)
|
||||
}
|
||||
|
||||
type Store struct {
|
||||
@@ -92,7 +94,7 @@ func toAPI(schema *types.APISchema, obj runtime.Object) types.APIObject {
|
||||
}
|
||||
|
||||
func (s *Store) byID(apiOp *types.APIRequest, schema *types.APISchema, id string) (*unstructured.Unstructured, error) {
|
||||
k8sClient, err := s.clientGetter.Client(apiOp, schema, apiOp.Namespace)
|
||||
k8sClient, err := s.clientGetter.TableClient(apiOp, schema, apiOp.Namespace)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -184,7 +186,7 @@ func tableToObjects(obj map[string]interface{}) []unstructured.Unstructured {
|
||||
}
|
||||
|
||||
func (s *Store) ByNames(apiOp *types.APIRequest, schema *types.APISchema, names sets.String) (types.APIObjectList, error) {
|
||||
adminClient, err := s.clientGetter.AdminClient(apiOp, schema, apiOp.Namespace)
|
||||
adminClient, err := s.clientGetter.TableAdminClient(apiOp, schema, apiOp.Namespace)
|
||||
if err != nil {
|
||||
return types.APIObjectList{}, err
|
||||
}
|
||||
@@ -206,7 +208,7 @@ func (s *Store) ByNames(apiOp *types.APIRequest, schema *types.APISchema, names
|
||||
}
|
||||
|
||||
func (s *Store) List(apiOp *types.APIRequest, schema *types.APISchema) (types.APIObjectList, error) {
|
||||
client, err := s.clientGetter.Client(apiOp, schema, apiOp.Namespace)
|
||||
client, err := s.clientGetter.TableClient(apiOp, schema, apiOp.Namespace)
|
||||
if err != nil {
|
||||
return types.APIObjectList{}, err
|
||||
}
|
||||
@@ -287,7 +289,7 @@ func (s *Store) listAndWatch(apiOp *types.APIRequest, k8sClient dynamic.Resource
|
||||
}
|
||||
|
||||
func (s *Store) WatchNames(apiOp *types.APIRequest, schema *types.APISchema, w types.WatchRequest, names sets.String) (chan types.APIEvent, error) {
|
||||
adminClient, err := s.clientGetter.ClientForWatch(apiOp, schema, apiOp.Namespace)
|
||||
adminClient, err := s.clientGetter.TableClientForWatch(apiOp, schema, apiOp.Namespace)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -310,7 +312,7 @@ func (s *Store) WatchNames(apiOp *types.APIRequest, schema *types.APISchema, w t
|
||||
}
|
||||
|
||||
func (s *Store) Watch(apiOp *types.APIRequest, schema *types.APISchema, w types.WatchRequest) (chan types.APIEvent, error) {
|
||||
client, err := s.clientGetter.ClientForWatch(apiOp, schema, apiOp.Namespace)
|
||||
client, err := s.clientGetter.TableClientForWatch(apiOp, schema, apiOp.Namespace)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -374,7 +376,7 @@ func (s *Store) Create(apiOp *types.APIRequest, schema *types.APISchema, params
|
||||
gvk := attributes.GVK(schema)
|
||||
input["apiVersion"], input["kind"] = gvk.ToAPIVersionAndKind()
|
||||
|
||||
k8sClient, err := s.clientGetter.Client(apiOp, schema, ns)
|
||||
k8sClient, err := s.clientGetter.TableClient(apiOp, schema, ns)
|
||||
if err != nil {
|
||||
return types.APIObject{}, err
|
||||
}
|
||||
@@ -395,7 +397,7 @@ func (s *Store) Update(apiOp *types.APIRequest, schema *types.APISchema, params
|
||||
)
|
||||
|
||||
ns := types.Namespace(input)
|
||||
k8sClient, err := s.clientGetter.Client(apiOp, schema, ns)
|
||||
k8sClient, err := s.clientGetter.TableClient(apiOp, schema, ns)
|
||||
if err != nil {
|
||||
return types.APIObject{}, err
|
||||
}
|
||||
@@ -460,7 +462,7 @@ func (s *Store) Delete(apiOp *types.APIRequest, schema *types.APISchema, id stri
|
||||
return types.APIObject{}, nil
|
||||
}
|
||||
|
||||
k8sClient, err := s.clientGetter.Client(apiOp, schema, apiOp.Namespace)
|
||||
k8sClient, err := s.clientGetter.TableClient(apiOp, schema, apiOp.Namespace)
|
||||
if err != nil {
|
||||
return types.APIObject{}, err
|
||||
}
|
||||
|
@@ -13,6 +13,19 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
)
|
||||
|
||||
type filterKey struct{}
|
||||
|
||||
func AddNamespaceConstraint(req *http.Request, names ...string) *http.Request {
|
||||
set := sets.NewString(names...)
|
||||
ctx := context.WithValue(req.Context(), filterKey{}, set)
|
||||
return req.WithContext(ctx)
|
||||
}
|
||||
|
||||
func getNamespaceConstraint(req *http.Request) (sets.String, bool) {
|
||||
set, ok := req.Context().Value(filterKey{}).(sets.String)
|
||||
return set, ok
|
||||
}
|
||||
|
||||
type RBACStore struct {
|
||||
*Store
|
||||
}
|
||||
@@ -24,6 +37,34 @@ type Partition struct {
|
||||
}
|
||||
|
||||
func isPassthrough(apiOp *types.APIRequest, schema *types.APISchema, verb string) ([]Partition, bool) {
|
||||
partitions, passthrough := isPassthroughUnconstrained(apiOp, schema, verb)
|
||||
namespaces, ok := getNamespaceConstraint(apiOp.Request)
|
||||
if !ok {
|
||||
return partitions, passthrough
|
||||
}
|
||||
|
||||
var result []Partition
|
||||
|
||||
if passthrough {
|
||||
for namespace := range namespaces {
|
||||
result = append(result, Partition{
|
||||
Namespace: namespace,
|
||||
All: true,
|
||||
})
|
||||
}
|
||||
return result, false
|
||||
}
|
||||
|
||||
for _, partition := range partitions {
|
||||
if namespaces.Has(partition.Namespace) {
|
||||
result = append(result, partition)
|
||||
}
|
||||
}
|
||||
|
||||
return result, false
|
||||
}
|
||||
|
||||
func isPassthroughUnconstrained(apiOp *types.APIRequest, schema *types.APISchema, verb string) ([]Partition, bool) {
|
||||
accessListByVerb, _ := attributes.Access(schema).(accesscontrol.AccessListByVerb)
|
||||
if accessListByVerb.All(verb) {
|
||||
return nil, true
|
||||
|
Reference in New Issue
Block a user