Commit 022bff7f authored by Andy Goldstein's avatar Andy Goldstein

Switch admission to use shared informers

parent b437787a
...@@ -23,7 +23,6 @@ go_library( ...@@ -23,7 +23,6 @@ go_library(
"//pkg/client/informers/informers_generated/internalversion:go_default_library", "//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/cloudprovider:go_default_library", "//pkg/cloudprovider:go_default_library",
"//pkg/cloudprovider/providers:go_default_library", "//pkg/cloudprovider/providers:go_default_library",
"//pkg/controller/informers:go_default_library",
"//pkg/controller/serviceaccount:go_default_library", "//pkg/controller/serviceaccount:go_default_library",
"//pkg/generated/openapi:go_default_library", "//pkg/generated/openapi:go_default_library",
"//pkg/kubeapiserver:go_default_library", "//pkg/kubeapiserver:go_default_library",
......
...@@ -51,9 +51,8 @@ import ( ...@@ -51,9 +51,8 @@ import (
"k8s.io/kubernetes/pkg/apis/batch" "k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/capabilities" "k8s.io/kubernetes/pkg/capabilities"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion" informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
"k8s.io/kubernetes/pkg/cloudprovider" "k8s.io/kubernetes/pkg/cloudprovider"
"k8s.io/kubernetes/pkg/controller/informers"
serviceaccountcontroller "k8s.io/kubernetes/pkg/controller/serviceaccount" serviceaccountcontroller "k8s.io/kubernetes/pkg/controller/serviceaccount"
generatedopenapi "k8s.io/kubernetes/pkg/generated/openapi" generatedopenapi "k8s.io/kubernetes/pkg/generated/openapi"
"k8s.io/kubernetes/pkg/kubeapiserver" "k8s.io/kubernetes/pkg/kubeapiserver"
...@@ -270,17 +269,14 @@ func Run(s *options.ServerRunOptions) error { ...@@ -270,17 +269,14 @@ func Run(s *options.ServerRunOptions) error {
glog.Errorf("Failed to create clientset with KUBE_API_VERSIONS=%q. KUBE_API_VERSIONS is only for testing. Things will break.", kubeAPIVersions) glog.Errorf("Failed to create clientset with KUBE_API_VERSIONS=%q. KUBE_API_VERSIONS is only for testing. Things will break.", kubeAPIVersions)
} }
// TODO: Internal informers should switch to using 'pkg/client/informers/informers_generated', sharedInformers := informers.NewSharedInformerFactory(client, 10*time.Minute)
// the second informer created here. Refactor clients which take the former to accept the latter.
sharedInformers := informers.NewSharedInformerFactory(nil, client, 10*time.Minute)
internalSharedInformers := internalversion.NewSharedInformerFactory(client, 10*time.Minute)
if client == nil { if client == nil {
// TODO: Remove check once client can never be nil. // TODO: Remove check once client can never be nil.
glog.Errorf("Failed to setup bootstrap token authenticator because the loopback clientset was not setup properly.") glog.Errorf("Failed to setup bootstrap token authenticator because the loopback clientset was not setup properly.")
} else { } else {
authenticatorConfig.BootstrapTokenAuthenticator = bootstrap.NewTokenAuthenticator( authenticatorConfig.BootstrapTokenAuthenticator = bootstrap.NewTokenAuthenticator(
internalSharedInformers.Core().InternalVersion().Secrets().Lister().Secrets(v1.NamespaceSystem), sharedInformers.Core().InternalVersion().Secrets().Lister().Secrets(v1.NamespaceSystem),
) )
} }
...@@ -367,7 +363,6 @@ func Run(s *options.ServerRunOptions) error { ...@@ -367,7 +363,6 @@ func Run(s *options.ServerRunOptions) error {
} }
sharedInformers.Start(wait.NeverStop) sharedInformers.Start(wait.NeverStop)
internalSharedInformers.Start(wait.NeverStop)
m.GenericAPIServer.PrepareRun().Run(wait.NeverStop) m.GenericAPIServer.PrepareRun().Run(wait.NeverStop)
return nil return nil
} }
......
...@@ -36,8 +36,8 @@ go_library( ...@@ -36,8 +36,8 @@ go_library(
"//pkg/apis/extensions:go_default_library", "//pkg/apis/extensions:go_default_library",
"//pkg/apis/extensions/install:go_default_library", "//pkg/apis/extensions/install:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/cloudprovider/providers:go_default_library", "//pkg/cloudprovider/providers:go_default_library",
"//pkg/controller/informers:go_default_library",
"//pkg/generated/openapi:go_default_library", "//pkg/generated/openapi:go_default_library",
"//pkg/kubeapiserver:go_default_library", "//pkg/kubeapiserver:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library", "//pkg/kubeapiserver/admission:go_default_library",
......
...@@ -41,7 +41,7 @@ import ( ...@@ -41,7 +41,7 @@ import (
"k8s.io/kubernetes/federation/cmd/federation-apiserver/app/options" "k8s.io/kubernetes/federation/cmd/federation-apiserver/app/options"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/controller/informers" informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
"k8s.io/kubernetes/pkg/generated/openapi" "k8s.io/kubernetes/pkg/generated/openapi"
"k8s.io/kubernetes/pkg/kubeapiserver" "k8s.io/kubernetes/pkg/kubeapiserver"
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
...@@ -159,7 +159,7 @@ func Run(s *options.ServerRunOptions) error { ...@@ -159,7 +159,7 @@ func Run(s *options.ServerRunOptions) error {
if err != nil { if err != nil {
return fmt.Errorf("failed to create clientset: %v", err) return fmt.Errorf("failed to create clientset: %v", err)
} }
sharedInformers := informers.NewSharedInformerFactory(nil, client, 10*time.Minute) sharedInformers := informers.NewSharedInformerFactory(client, 10*time.Minute)
authorizationConfig := s.Authorization.ToAuthorizationConfig(sharedInformers) authorizationConfig := s.Authorization.ToAuthorizationConfig(sharedInformers)
apiAuthorizer, err := authorizationConfig.New() apiAuthorizer, err := authorizationConfig.New()
......
...@@ -25,7 +25,7 @@ go_library( ...@@ -25,7 +25,7 @@ go_library(
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = [
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/controller/informers:go_default_library", "//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//vendor:k8s.io/apiserver/pkg/admission", "//vendor:k8s.io/apiserver/pkg/admission",
"//vendor:k8s.io/apiserver/pkg/authorization/authorizer", "//vendor:k8s.io/apiserver/pkg/authorization/authorizer",
], ],
......
...@@ -20,7 +20,7 @@ import ( ...@@ -20,7 +20,7 @@ import (
"k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/controller/informers" informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
) )
// TODO add a `WantsToRun` which takes a stopCh. Might make it generic. // TODO add a `WantsToRun` which takes a stopCh. Might make it generic.
......
...@@ -24,10 +24,13 @@ go_library( ...@@ -24,10 +24,13 @@ go_library(
srcs = ["config.go"], srcs = ["config.go"],
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = [
"//pkg/apis/rbac:go_default_library",
"//pkg/auth/authorizer/abac:go_default_library", "//pkg/auth/authorizer/abac:go_default_library",
"//pkg/controller/informers:go_default_library", "//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/client/listers/rbac/internalversion:go_default_library",
"//pkg/kubeapiserver/authorizer/modes:go_default_library", "//pkg/kubeapiserver/authorizer/modes:go_default_library",
"//plugin/pkg/auth/authorizer/rbac:go_default_library", "//plugin/pkg/auth/authorizer/rbac:go_default_library",
"//vendor:k8s.io/apimachinery/pkg/labels",
"//vendor:k8s.io/apiserver/pkg/authorization/authorizer", "//vendor:k8s.io/apiserver/pkg/authorization/authorizer",
"//vendor:k8s.io/apiserver/pkg/authorization/authorizerfactory", "//vendor:k8s.io/apiserver/pkg/authorization/authorizerfactory",
"//vendor:k8s.io/apiserver/pkg/authorization/union", "//vendor:k8s.io/apiserver/pkg/authorization/union",
......
...@@ -21,12 +21,15 @@ import ( ...@@ -21,12 +21,15 @@ import (
"fmt" "fmt"
"time" "time"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/apiserver/pkg/authorization/authorizerfactory" "k8s.io/apiserver/pkg/authorization/authorizerfactory"
"k8s.io/apiserver/pkg/authorization/union" "k8s.io/apiserver/pkg/authorization/union"
"k8s.io/apiserver/plugin/pkg/authorizer/webhook" "k8s.io/apiserver/plugin/pkg/authorizer/webhook"
rbacapi "k8s.io/kubernetes/pkg/apis/rbac"
"k8s.io/kubernetes/pkg/auth/authorizer/abac" "k8s.io/kubernetes/pkg/auth/authorizer/abac"
"k8s.io/kubernetes/pkg/controller/informers" informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
rbaclisters "k8s.io/kubernetes/pkg/client/listers/rbac/internalversion"
"k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes" "k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes"
"k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac" "k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac"
) )
...@@ -56,6 +59,38 @@ type AuthorizationConfig struct { ...@@ -56,6 +59,38 @@ type AuthorizationConfig struct {
InformerFactory informers.SharedInformerFactory InformerFactory informers.SharedInformerFactory
} }
type roleGetter struct {
lister rbaclisters.RoleLister
}
func (g *roleGetter) GetRole(namespace, name string) (*rbacapi.Role, error) {
return g.lister.Roles(namespace).Get(name)
}
type roleBindingLister struct {
lister rbaclisters.RoleBindingLister
}
func (l *roleBindingLister) ListRoleBindings(namespace string) ([]*rbacapi.RoleBinding, error) {
return l.lister.RoleBindings(namespace).List(labels.Everything())
}
type clusterRoleGetter struct {
lister rbaclisters.ClusterRoleLister
}
func (g *clusterRoleGetter) GetClusterRole(name string) (*rbacapi.ClusterRole, error) {
return g.lister.Get(name)
}
type clusterRoleBindingLister struct {
lister rbaclisters.ClusterRoleBindingLister
}
func (l *clusterRoleBindingLister) ListClusterRoleBindings() ([]*rbacapi.ClusterRoleBinding, error) {
return l.lister.List(labels.Everything())
}
// New returns the right sort of union of multiple authorizer.Authorizer objects // New returns the right sort of union of multiple authorizer.Authorizer objects
// based on the authorizationMode or an error. // based on the authorizationMode or an error.
func (config AuthorizationConfig) New() (authorizer.Authorizer, error) { func (config AuthorizationConfig) New() (authorizer.Authorizer, error) {
...@@ -98,10 +133,10 @@ func (config AuthorizationConfig) New() (authorizer.Authorizer, error) { ...@@ -98,10 +133,10 @@ func (config AuthorizationConfig) New() (authorizer.Authorizer, error) {
authorizers = append(authorizers, webhookAuthorizer) authorizers = append(authorizers, webhookAuthorizer)
case modes.ModeRBAC: case modes.ModeRBAC:
rbacAuthorizer := rbac.New( rbacAuthorizer := rbac.New(
config.InformerFactory.Roles().Lister(), &roleGetter{config.InformerFactory.Rbac().InternalVersion().Roles().Lister()},
config.InformerFactory.RoleBindings().Lister(), &roleBindingLister{config.InformerFactory.Rbac().InternalVersion().RoleBindings().Lister()},
config.InformerFactory.ClusterRoles().Lister(), &clusterRoleGetter{config.InformerFactory.Rbac().InternalVersion().ClusterRoles().Lister()},
config.InformerFactory.ClusterRoleBindings().Lister(), &clusterRoleBindingLister{config.InformerFactory.Rbac().InternalVersion().ClusterRoleBindings().Lister()},
) )
authorizers = append(authorizers, rbacAuthorizer) authorizers = append(authorizers, rbacAuthorizer)
default: default:
......
...@@ -21,8 +21,8 @@ go_library( ...@@ -21,8 +21,8 @@ go_library(
deps = [ deps = [
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/api/v1:go_default_library", "//pkg/api/v1:go_default_library",
"//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/cloudprovider:go_default_library", "//pkg/cloudprovider:go_default_library",
"//pkg/controller/informers:go_default_library",
"//pkg/kubeapiserver/authenticator:go_default_library", "//pkg/kubeapiserver/authenticator:go_default_library",
"//pkg/kubeapiserver/authorizer:go_default_library", "//pkg/kubeapiserver/authorizer:go_default_library",
"//pkg/kubeapiserver/authorizer/modes:go_default_library", "//pkg/kubeapiserver/authorizer/modes:go_default_library",
......
...@@ -22,7 +22,7 @@ import ( ...@@ -22,7 +22,7 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
"k8s.io/kubernetes/pkg/controller/informers" informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
"k8s.io/kubernetes/pkg/kubeapiserver/authorizer" "k8s.io/kubernetes/pkg/kubeapiserver/authorizer"
authzmodes "k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes" authzmodes "k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes"
) )
......
...@@ -18,8 +18,8 @@ go_library( ...@@ -18,8 +18,8 @@ go_library(
deps = [ deps = [
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/client/listers/core/internalversion:go_default_library", "//pkg/client/listers/core/internalversion:go_default_library",
"//pkg/controller/informers:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library", "//pkg/kubeapiserver/admission:go_default_library",
"//vendor:github.com/hashicorp/golang-lru", "//vendor:github.com/hashicorp/golang-lru",
"//vendor:k8s.io/apimachinery/pkg/api/meta", "//vendor:k8s.io/apimachinery/pkg/api/meta",
...@@ -41,7 +41,7 @@ go_test( ...@@ -41,7 +41,7 @@ go_test(
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library", "//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
"//pkg/controller/informers:go_default_library", "//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library", "//pkg/kubeapiserver/admission:go_default_library",
"//vendor:k8s.io/apimachinery/pkg/api/equality", "//vendor:k8s.io/apimachinery/pkg/api/equality",
"//vendor:k8s.io/apimachinery/pkg/api/resource", "//vendor:k8s.io/apimachinery/pkg/api/resource",
......
...@@ -34,8 +34,8 @@ import ( ...@@ -34,8 +34,8 @@ import (
"k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/admission"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
coreinternallisters "k8s.io/kubernetes/pkg/client/listers/core/internalversion" informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
"k8s.io/kubernetes/pkg/controller/informers" corelisters "k8s.io/kubernetes/pkg/client/listers/core/internalversion"
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
) )
...@@ -54,7 +54,7 @@ type limitRanger struct { ...@@ -54,7 +54,7 @@ type limitRanger struct {
*admission.Handler *admission.Handler
client internalclientset.Interface client internalclientset.Interface
actions LimitRangerActions actions LimitRangerActions
lister coreinternallisters.LimitRangeLister lister corelisters.LimitRangeLister
// liveLookups holds the last few live lookups we've done to help ammortize cost on repeated lookup failures. // liveLookups holds the last few live lookups we've done to help ammortize cost on repeated lookup failures.
// This let's us handle the case of latent caches, by looking up actual results for a namespace on cache miss/no results. // This let's us handle the case of latent caches, by looking up actual results for a namespace on cache miss/no results.
...@@ -69,9 +69,9 @@ type liveLookupEntry struct { ...@@ -69,9 +69,9 @@ type liveLookupEntry struct {
} }
func (l *limitRanger) SetInformerFactory(f informers.SharedInformerFactory) { func (l *limitRanger) SetInformerFactory(f informers.SharedInformerFactory) {
limitRangeInformer := f.InternalLimitRanges().Informer() limitRangeInformer := f.Core().InternalVersion().LimitRanges()
l.SetReadyFunc(limitRangeInformer.HasSynced) l.SetReadyFunc(limitRangeInformer.Informer().HasSynced)
l.lister = f.InternalLimitRanges().Lister() l.lister = limitRangeInformer.Lister()
} }
func (l *limitRanger) Validate() error { func (l *limitRanger) Validate() error {
...@@ -167,6 +167,7 @@ func NewLimitRanger(actions LimitRangerActions) (admission.Interface, error) { ...@@ -167,6 +167,7 @@ func NewLimitRanger(actions LimitRangerActions) (admission.Interface, error) {
}, nil }, nil
} }
var _ = kubeapiserveradmission.WantsInformerFactory(&limitRanger{})
var _ = kubeapiserveradmission.WantsInternalClientSet(&limitRanger{}) var _ = kubeapiserveradmission.WantsInternalClientSet(&limitRanger{})
func (a *limitRanger) SetInternalClientSet(client internalclientset.Interface) { func (a *limitRanger) SetInternalClientSet(client internalclientset.Interface) {
......
...@@ -32,7 +32,7 @@ import ( ...@@ -32,7 +32,7 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
"k8s.io/kubernetes/pkg/controller/informers" informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
) )
...@@ -590,7 +590,7 @@ func newMockClientForTest(limitRanges []api.LimitRange) *fake.Clientset { ...@@ -590,7 +590,7 @@ func newMockClientForTest(limitRanges []api.LimitRange) *fake.Clientset {
// newHandlerForTest returns a handler configured for testing. // newHandlerForTest returns a handler configured for testing.
func newHandlerForTest(c clientset.Interface) (admission.Interface, informers.SharedInformerFactory, error) { func newHandlerForTest(c clientset.Interface) (admission.Interface, informers.SharedInformerFactory, error) {
f := informers.NewSharedInformerFactory(nil, c, 5*time.Minute) f := informers.NewSharedInformerFactory(c, 5*time.Minute)
handler, err := NewLimitRanger(&DefaultLimitRangerActions{}) handler, err := NewLimitRanger(&DefaultLimitRangerActions{})
if err != nil { if err != nil {
return nil, f, err return nil, f, err
......
...@@ -15,12 +15,12 @@ go_library( ...@@ -15,12 +15,12 @@ go_library(
deps = [ deps = [
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/controller/informers:go_default_library", "//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/client/listers/core/internalversion:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library", "//pkg/kubeapiserver/admission:go_default_library",
"//vendor:k8s.io/apimachinery/pkg/api/errors", "//vendor:k8s.io/apimachinery/pkg/api/errors",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apiserver/pkg/admission", "//vendor:k8s.io/apiserver/pkg/admission",
"//vendor:k8s.io/client-go/tools/cache",
], ],
) )
...@@ -33,7 +33,7 @@ go_test( ...@@ -33,7 +33,7 @@ go_test(
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library", "//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
"//pkg/controller/informers:go_default_library", "//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library", "//pkg/kubeapiserver/admission:go_default_library",
"//vendor:k8s.io/apimachinery/pkg/api/errors", "//vendor:k8s.io/apimachinery/pkg/api/errors",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
......
...@@ -23,10 +23,10 @@ import ( ...@@ -23,10 +23,10 @@ import (
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/admission"
"k8s.io/client-go/tools/cache"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/controller/informers" informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
corelisters "k8s.io/kubernetes/pkg/client/listers/core/internalversion"
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
) )
...@@ -41,14 +41,14 @@ func init() { ...@@ -41,14 +41,14 @@ func init() {
// It is useful in deployments that do not want to restrict creation of a namespace prior to its usage. // It is useful in deployments that do not want to restrict creation of a namespace prior to its usage.
type provision struct { type provision struct {
*admission.Handler *admission.Handler
client internalclientset.Interface client internalclientset.Interface
namespaceInformer cache.SharedIndexInformer namespaceLister corelisters.NamespaceLister
} }
var _ = kubeapiserveradmission.WantsInformerFactory(&provision{}) var _ = kubeapiserveradmission.WantsInformerFactory(&provision{})
var _ = kubeapiserveradmission.WantsInformerFactory(&provision{}) var _ = kubeapiserveradmission.WantsInternalClientSet(&provision{})
func (p *provision) Admit(a admission.Attributes) (err error) { func (p *provision) Admit(a admission.Attributes) error {
// if we're here, then we've already passed authentication, so we're allowed to do what we're trying to do // if we're here, then we've already passed authentication, so we're allowed to do what we're trying to do
// if we're here, then the API server has found a route, which means that if we have a non-empty namespace // if we're here, then the API server has found a route, which means that if we have a non-empty namespace
// its a namespaced resource. // its a namespaced resource.
...@@ -59,6 +59,16 @@ func (p *provision) Admit(a admission.Attributes) (err error) { ...@@ -59,6 +59,16 @@ func (p *provision) Admit(a admission.Attributes) (err error) {
if !p.WaitForReady() { if !p.WaitForReady() {
return admission.NewForbidden(a, fmt.Errorf("not yet ready to handle request")) return admission.NewForbidden(a, fmt.Errorf("not yet ready to handle request"))
} }
_, err := p.namespaceLister.Get(a.GetNamespace())
if err == nil {
return nil
}
if !errors.IsNotFound(err) {
return admission.NewForbidden(a, err)
}
namespace := &api.Namespace{ namespace := &api.Namespace{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: a.GetNamespace(), Name: a.GetNamespace(),
...@@ -66,17 +76,12 @@ func (p *provision) Admit(a admission.Attributes) (err error) { ...@@ -66,17 +76,12 @@ func (p *provision) Admit(a admission.Attributes) (err error) {
}, },
Status: api.NamespaceStatus{}, Status: api.NamespaceStatus{},
} }
_, exists, err := p.namespaceInformer.GetStore().Get(namespace)
if err != nil {
return admission.NewForbidden(a, err)
}
if exists {
return nil
}
_, err = p.client.Core().Namespaces().Create(namespace) _, err = p.client.Core().Namespaces().Create(namespace)
if err != nil && !errors.IsAlreadyExists(err) { if err != nil && !errors.IsAlreadyExists(err) {
return admission.NewForbidden(a, err) return admission.NewForbidden(a, err)
} }
return nil return nil
} }
...@@ -92,13 +97,14 @@ func (p *provision) SetInternalClientSet(client internalclientset.Interface) { ...@@ -92,13 +97,14 @@ func (p *provision) SetInternalClientSet(client internalclientset.Interface) {
} }
func (p *provision) SetInformerFactory(f informers.SharedInformerFactory) { func (p *provision) SetInformerFactory(f informers.SharedInformerFactory) {
p.namespaceInformer = f.InternalNamespaces().Informer() namespaceInformer := f.Core().InternalVersion().Namespaces()
p.SetReadyFunc(p.namespaceInformer.HasSynced) p.namespaceLister = namespaceInformer.Lister()
p.SetReadyFunc(namespaceInformer.Informer().HasSynced)
} }
func (p *provision) Validate() error { func (p *provision) Validate() error {
if p.namespaceInformer == nil { if p.namespaceLister == nil {
return fmt.Errorf("missing namespaceInformer") return fmt.Errorf("missing namespaceLister")
} }
if p.client == nil { if p.client == nil {
return fmt.Errorf("missing client") return fmt.Errorf("missing client")
......
...@@ -30,13 +30,13 @@ import ( ...@@ -30,13 +30,13 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
"k8s.io/kubernetes/pkg/controller/informers" informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
) )
// newHandlerForTest returns the admission controller configured for testing. // newHandlerForTest returns the admission controller configured for testing.
func newHandlerForTest(c clientset.Interface) (admission.Interface, informers.SharedInformerFactory, error) { func newHandlerForTest(c clientset.Interface) (admission.Interface, informers.SharedInformerFactory, error) {
f := informers.NewSharedInformerFactory(nil, c, 5*time.Minute) f := informers.NewSharedInformerFactory(c, 5*time.Minute)
handler := NewProvision() handler := NewProvision()
pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil) pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil)
pluginInitializer.Initialize(handler) pluginInitializer.Initialize(handler)
......
...@@ -15,12 +15,12 @@ go_library( ...@@ -15,12 +15,12 @@ go_library(
deps = [ deps = [
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/controller/informers:go_default_library", "//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/client/listers/core/internalversion:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library", "//pkg/kubeapiserver/admission:go_default_library",
"//vendor:k8s.io/apimachinery/pkg/api/errors", "//vendor:k8s.io/apimachinery/pkg/api/errors",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apiserver/pkg/admission", "//vendor:k8s.io/apiserver/pkg/admission",
"//vendor:k8s.io/client-go/tools/cache",
], ],
) )
...@@ -33,7 +33,7 @@ go_test( ...@@ -33,7 +33,7 @@ go_test(
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library", "//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
"//pkg/controller/informers:go_default_library", "//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library", "//pkg/kubeapiserver/admission:go_default_library",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apimachinery/pkg/runtime", "//vendor:k8s.io/apimachinery/pkg/runtime",
......
...@@ -23,10 +23,10 @@ import ( ...@@ -23,10 +23,10 @@ import (
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/admission"
"k8s.io/client-go/tools/cache"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/controller/informers" informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
corelisters "k8s.io/kubernetes/pkg/client/listers/core/internalversion"
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
) )
...@@ -41,14 +41,14 @@ func init() { ...@@ -41,14 +41,14 @@ func init() {
// It is useful in deployments that want to enforce pre-declaration of a Namespace resource. // It is useful in deployments that want to enforce pre-declaration of a Namespace resource.
type exists struct { type exists struct {
*admission.Handler *admission.Handler
client internalclientset.Interface client internalclientset.Interface
namespaceInformer cache.SharedIndexInformer namespaceLister corelisters.NamespaceLister
} }
var _ = kubeapiserveradmission.WantsInformerFactory(&exists{}) var _ = kubeapiserveradmission.WantsInformerFactory(&exists{})
var _ = kubeapiserveradmission.WantsInternalClientSet(&exists{}) var _ = kubeapiserveradmission.WantsInternalClientSet(&exists{})
func (e *exists) Admit(a admission.Attributes) (err error) { func (e *exists) Admit(a admission.Attributes) error {
// if we're here, then we've already passed authentication, so we're allowed to do what we're trying to do // if we're here, then we've already passed authentication, so we're allowed to do what we're trying to do
// if we're here, then the API server has found a route, which means that if we have a non-empty namespace // if we're here, then the API server has found a route, which means that if we have a non-empty namespace
// its a namespaced resource. // its a namespaced resource.
...@@ -60,20 +60,13 @@ func (e *exists) Admit(a admission.Attributes) (err error) { ...@@ -60,20 +60,13 @@ func (e *exists) Admit(a admission.Attributes) (err error) {
if !e.WaitForReady() { if !e.WaitForReady() {
return admission.NewForbidden(a, fmt.Errorf("not yet ready to handle request")) return admission.NewForbidden(a, fmt.Errorf("not yet ready to handle request"))
} }
namespace := &api.Namespace{ _, err := e.namespaceLister.Get(a.GetNamespace())
ObjectMeta: metav1.ObjectMeta{ if err == nil {
Name: a.GetNamespace(), return nil
Namespace: "",
},
Status: api.NamespaceStatus{},
} }
_, exists, err := e.namespaceInformer.GetStore().Get(namespace) if !errors.IsNotFound(err) {
if err != nil {
return errors.NewInternalError(err) return errors.NewInternalError(err)
} }
if exists {
return nil
}
// in case of latency in our caches, make a call direct to storage to verify that it truly exists or not // in case of latency in our caches, make a call direct to storage to verify that it truly exists or not
_, err = e.client.Core().Namespaces().Get(a.GetNamespace(), metav1.GetOptions{}) _, err = e.client.Core().Namespaces().Get(a.GetNamespace(), metav1.GetOptions{})
...@@ -99,13 +92,14 @@ func (e *exists) SetInternalClientSet(client internalclientset.Interface) { ...@@ -99,13 +92,14 @@ func (e *exists) SetInternalClientSet(client internalclientset.Interface) {
} }
func (e *exists) SetInformerFactory(f informers.SharedInformerFactory) { func (e *exists) SetInformerFactory(f informers.SharedInformerFactory) {
e.namespaceInformer = f.InternalNamespaces().Informer() namespaceInformer := f.Core().InternalVersion().Namespaces()
e.SetReadyFunc(e.namespaceInformer.HasSynced) e.namespaceLister = namespaceInformer.Lister()
e.SetReadyFunc(namespaceInformer.Informer().HasSynced)
} }
func (e *exists) Validate() error { func (e *exists) Validate() error {
if e.namespaceInformer == nil { if e.namespaceLister == nil {
return fmt.Errorf("missing namespaceInformer") return fmt.Errorf("missing namespaceLister")
} }
if e.client == nil { if e.client == nil {
return fmt.Errorf("missing client") return fmt.Errorf("missing client")
......
...@@ -29,13 +29,13 @@ import ( ...@@ -29,13 +29,13 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
"k8s.io/kubernetes/pkg/controller/informers" informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
) )
// newHandlerForTest returns the admission controller configured for testing. // newHandlerForTest returns the admission controller configured for testing.
func newHandlerForTest(c clientset.Interface) (admission.Interface, informers.SharedInformerFactory, error) { func newHandlerForTest(c clientset.Interface) (admission.Interface, informers.SharedInformerFactory, error) {
f := informers.NewSharedInformerFactory(nil, c, 5*time.Minute) f := informers.NewSharedInformerFactory(c, 5*time.Minute)
handler := NewExists() handler := NewExists()
pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil) pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil)
pluginInitializer.Initialize(handler) pluginInitializer.Initialize(handler)
......
...@@ -15,7 +15,8 @@ go_library( ...@@ -15,7 +15,8 @@ go_library(
deps = [ deps = [
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/controller/informers:go_default_library", "//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/client/listers/core/internalversion:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library", "//pkg/kubeapiserver/admission:go_default_library",
"//vendor:github.com/golang/glog", "//vendor:github.com/golang/glog",
"//vendor:k8s.io/apimachinery/pkg/api/errors", "//vendor:k8s.io/apimachinery/pkg/api/errors",
...@@ -23,7 +24,6 @@ go_library( ...@@ -23,7 +24,6 @@ go_library(
"//vendor:k8s.io/apimachinery/pkg/util/sets", "//vendor:k8s.io/apimachinery/pkg/util/sets",
"//vendor:k8s.io/apiserver/pkg/admission", "//vendor:k8s.io/apiserver/pkg/admission",
"//vendor:k8s.io/apiserver/pkg/util/cache", "//vendor:k8s.io/apiserver/pkg/util/cache",
"//vendor:k8s.io/client-go/tools/cache",
"//vendor:k8s.io/client-go/util/clock", "//vendor:k8s.io/client-go/util/clock",
], ],
) )
...@@ -37,7 +37,7 @@ go_test( ...@@ -37,7 +37,7 @@ go_test(
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library", "//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
"//pkg/controller/informers:go_default_library", "//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library", "//pkg/kubeapiserver/admission:go_default_library",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apimachinery/pkg/runtime", "//vendor:k8s.io/apimachinery/pkg/runtime",
......
...@@ -28,11 +28,11 @@ import ( ...@@ -28,11 +28,11 @@ import (
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/admission"
utilcache "k8s.io/apiserver/pkg/util/cache" utilcache "k8s.io/apiserver/pkg/util/cache"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/clock" "k8s.io/client-go/util/clock"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/controller/informers" informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
corelisters "k8s.io/kubernetes/pkg/client/listers/core/internalversion"
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
) )
...@@ -61,7 +61,7 @@ type lifecycle struct { ...@@ -61,7 +61,7 @@ type lifecycle struct {
*admission.Handler *admission.Handler
client internalclientset.Interface client internalclientset.Interface
immortalNamespaces sets.String immortalNamespaces sets.String
namespaceInformer cache.SharedIndexInformer namespaceLister corelisters.NamespaceLister
// forceLiveLookupCache holds a list of entries for namespaces that we have a strong reason to believe are stale in our local cache. // forceLiveLookupCache holds a list of entries for namespaces that we have a strong reason to believe are stale in our local cache.
// if a namespace is in this cache, then we will ignore our local state and always fetch latest from api server. // if a namespace is in this cache, then we will ignore our local state and always fetch latest from api server.
forceLiveLookupCache *utilcache.LRUExpireCache forceLiveLookupCache *utilcache.LRUExpireCache
...@@ -109,24 +109,31 @@ func (l *lifecycle) Admit(a admission.Attributes) error { ...@@ -109,24 +109,31 @@ func (l *lifecycle) Admit(a admission.Attributes) error {
} }
var ( var (
namespaceObj interface{} exists bool
exists bool err error
err error
) )
key := makeNamespaceKey(a.GetNamespace()) namespace, err := l.namespaceLister.Get(a.GetNamespace())
namespaceObj, exists, err = l.namespaceInformer.GetStore().Get(key)
if err != nil { if err != nil {
return errors.NewInternalError(err) if !errors.IsNotFound(err) {
return errors.NewInternalError(err)
}
} else {
exists = true
} }
if !exists && a.GetOperation() == admission.Create { if !exists && a.GetOperation() == admission.Create {
// give the cache time to observe the namespace before rejecting a create. // give the cache time to observe the namespace before rejecting a create.
// this helps when creating a namespace and immediately creating objects within it. // this helps when creating a namespace and immediately creating objects within it.
time.Sleep(missingNamespaceWait) time.Sleep(missingNamespaceWait)
namespaceObj, exists, err = l.namespaceInformer.GetStore().Get(key) namespace, err = l.namespaceLister.Get(a.GetNamespace())
if err != nil { switch {
case errors.IsNotFound(err):
// no-op
case err != nil:
return errors.NewInternalError(err) return errors.NewInternalError(err)
default:
exists = true
} }
if exists { if exists {
glog.V(4).Infof("found %s in cache after waiting", a.GetNamespace()) glog.V(4).Infof("found %s in cache after waiting", a.GetNamespace())
...@@ -137,17 +144,17 @@ func (l *lifecycle) Admit(a admission.Attributes) error { ...@@ -137,17 +144,17 @@ func (l *lifecycle) Admit(a admission.Attributes) error {
forceLiveLookup := false forceLiveLookup := false
if _, ok := l.forceLiveLookupCache.Get(a.GetNamespace()); ok { if _, ok := l.forceLiveLookupCache.Get(a.GetNamespace()); ok {
// we think the namespace was marked for deletion, but our current local cache says otherwise, we will force a live lookup. // we think the namespace was marked for deletion, but our current local cache says otherwise, we will force a live lookup.
forceLiveLookup = exists && namespaceObj.(*api.Namespace).Status.Phase == api.NamespaceActive forceLiveLookup = exists && namespace.Status.Phase == api.NamespaceActive
} }
// refuse to operate on non-existent namespaces // refuse to operate on non-existent namespaces
if !exists || forceLiveLookup { if !exists || forceLiveLookup {
// as a last resort, make a call directly to storage // as a last resort, make a call directly to storage
namespaceObj, err = l.client.Core().Namespaces().Get(a.GetNamespace(), metav1.GetOptions{}) namespace, err = l.client.Core().Namespaces().Get(a.GetNamespace(), metav1.GetOptions{})
if err != nil { switch {
if errors.IsNotFound(err) { case errors.IsNotFound(err):
return err return err
} case err != nil:
return errors.NewInternalError(err) return errors.NewInternalError(err)
} }
glog.V(4).Infof("found %s via storage lookup", a.GetNamespace()) glog.V(4).Infof("found %s via storage lookup", a.GetNamespace())
...@@ -155,7 +162,6 @@ func (l *lifecycle) Admit(a admission.Attributes) error { ...@@ -155,7 +162,6 @@ func (l *lifecycle) Admit(a admission.Attributes) error {
// ensure that we're not trying to create objects in terminating namespaces // ensure that we're not trying to create objects in terminating namespaces
if a.GetOperation() == admission.Create { if a.GetOperation() == admission.Create {
namespace := namespaceObj.(*api.Namespace)
if namespace.Status.Phase != api.NamespaceTerminating { if namespace.Status.Phase != api.NamespaceTerminating {
return nil return nil
} }
...@@ -182,8 +188,9 @@ func newLifecycleWithClock(immortalNamespaces sets.String, clock utilcache.Clock ...@@ -182,8 +188,9 @@ func newLifecycleWithClock(immortalNamespaces sets.String, clock utilcache.Clock
} }
func (l *lifecycle) SetInformerFactory(f informers.SharedInformerFactory) { func (l *lifecycle) SetInformerFactory(f informers.SharedInformerFactory) {
l.namespaceInformer = f.InternalNamespaces().Informer() namespaceInformer := f.Core().InternalVersion().Namespaces()
l.SetReadyFunc(l.namespaceInformer.HasSynced) l.namespaceLister = namespaceInformer.Lister()
l.SetReadyFunc(namespaceInformer.Informer().HasSynced)
} }
func (l *lifecycle) SetInternalClientSet(client internalclientset.Interface) { func (l *lifecycle) SetInternalClientSet(client internalclientset.Interface) {
...@@ -191,8 +198,8 @@ func (l *lifecycle) SetInternalClientSet(client internalclientset.Interface) { ...@@ -191,8 +198,8 @@ func (l *lifecycle) SetInternalClientSet(client internalclientset.Interface) {
} }
func (l *lifecycle) Validate() error { func (l *lifecycle) Validate() error {
if l.namespaceInformer == nil { if l.namespaceLister == nil {
return fmt.Errorf("missing namespaceInformer") return fmt.Errorf("missing namespaceLister")
} }
if l.client == nil { if l.client == nil {
return fmt.Errorf("missing client") return fmt.Errorf("missing client")
......
...@@ -31,7 +31,7 @@ import ( ...@@ -31,7 +31,7 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
"k8s.io/kubernetes/pkg/controller/informers" informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
) )
...@@ -42,7 +42,7 @@ func newHandlerForTest(c clientset.Interface) (admission.Interface, informers.Sh ...@@ -42,7 +42,7 @@ func newHandlerForTest(c clientset.Interface) (admission.Interface, informers.Sh
// newHandlerForTestWithClock returns a configured handler for testing. // newHandlerForTestWithClock returns a configured handler for testing.
func newHandlerForTestWithClock(c clientset.Interface, cacheClock clock.Clock) (admission.Interface, informers.SharedInformerFactory, error) { func newHandlerForTestWithClock(c clientset.Interface, cacheClock clock.Clock) (admission.Interface, informers.SharedInformerFactory, error) {
f := informers.NewSharedInformerFactory(nil, c, 5*time.Minute) f := informers.NewSharedInformerFactory(c, 5*time.Minute)
handler, err := newLifecycleWithClock(sets.NewString(metav1.NamespaceDefault, metav1.NamespaceSystem), cacheClock) handler, err := newLifecycleWithClock(sets.NewString(metav1.NamespaceDefault, metav1.NamespaceSystem), cacheClock)
if err != nil { if err != nil {
return nil, f, err return nil, f, err
......
...@@ -15,7 +15,8 @@ go_library( ...@@ -15,7 +15,8 @@ go_library(
deps = [ deps = [
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/controller/informers:go_default_library", "//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/client/listers/core/internalversion:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library", "//pkg/kubeapiserver/admission:go_default_library",
"//vendor:github.com/golang/glog", "//vendor:github.com/golang/glog",
"//vendor:k8s.io/apimachinery/pkg/api/errors", "//vendor:k8s.io/apimachinery/pkg/api/errors",
...@@ -23,7 +24,6 @@ go_library( ...@@ -23,7 +24,6 @@ go_library(
"//vendor:k8s.io/apimachinery/pkg/labels", "//vendor:k8s.io/apimachinery/pkg/labels",
"//vendor:k8s.io/apimachinery/pkg/util/yaml", "//vendor:k8s.io/apimachinery/pkg/util/yaml",
"//vendor:k8s.io/apiserver/pkg/admission", "//vendor:k8s.io/apiserver/pkg/admission",
"//vendor:k8s.io/client-go/tools/cache",
], ],
) )
...@@ -36,11 +36,10 @@ go_test( ...@@ -36,11 +36,10 @@ go_test(
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library", "//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
"//pkg/controller/informers:go_default_library", "//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library", "//pkg/kubeapiserver/admission:go_default_library",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apimachinery/pkg/labels", "//vendor:k8s.io/apimachinery/pkg/labels",
"//vendor:k8s.io/apimachinery/pkg/util/wait",
"//vendor:k8s.io/apiserver/pkg/admission", "//vendor:k8s.io/apiserver/pkg/admission",
], ],
) )
......
...@@ -28,10 +28,10 @@ import ( ...@@ -28,10 +28,10 @@ import (
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/yaml" "k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/admission"
"k8s.io/client-go/tools/cache"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/controller/informers" informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
corelisters "k8s.io/kubernetes/pkg/client/listers/core/internalversion"
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
) )
...@@ -51,13 +51,14 @@ func init() { ...@@ -51,13 +51,14 @@ func init() {
// podNodeSelector is an implementation of admission.Interface. // podNodeSelector is an implementation of admission.Interface.
type podNodeSelector struct { type podNodeSelector struct {
*admission.Handler *admission.Handler
client internalclientset.Interface client internalclientset.Interface
namespaceInformer cache.SharedIndexInformer namespaceLister corelisters.NamespaceLister
// global default node selector and namespace whitelists in a cluster. // global default node selector and namespace whitelists in a cluster.
clusterNodeSelectors map[string]string clusterNodeSelectors map[string]string
} }
var _ = kubeapiserveradmission.WantsInternalClientSet(&podNodeSelector{}) var _ = kubeapiserveradmission.WantsInternalClientSet(&podNodeSelector{})
var _ = kubeapiserveradmission.WantsInformerFactory(&podNodeSelector{})
type pluginConfig struct { type pluginConfig struct {
PodNodeSelectorPluginConfig map[string]string PodNodeSelectorPluginConfig map[string]string
...@@ -114,18 +115,8 @@ func (p *podNodeSelector) Admit(a admission.Attributes) error { ...@@ -114,18 +115,8 @@ func (p *podNodeSelector) Admit(a admission.Attributes) error {
nsName := a.GetNamespace() nsName := a.GetNamespace()
var namespace *api.Namespace var namespace *api.Namespace
namespaceObj, exists, err := p.namespaceInformer.GetStore().Get(&api.Namespace{ namespace, err := p.namespaceLister.Get(nsName)
ObjectMeta: metav1.ObjectMeta{ if errors.IsNotFound(err) {
Name: nsName,
Namespace: "",
},
})
if err != nil {
return errors.NewInternalError(err)
}
if exists {
namespace = namespaceObj.(*api.Namespace)
} else {
namespace, err = p.defaultGetNamespace(nsName) namespace, err = p.defaultGetNamespace(nsName)
if err != nil { if err != nil {
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
...@@ -133,7 +124,10 @@ func (p *podNodeSelector) Admit(a admission.Attributes) error { ...@@ -133,7 +124,10 @@ func (p *podNodeSelector) Admit(a admission.Attributes) error {
} }
return errors.NewInternalError(err) return errors.NewInternalError(err)
} }
} else if err != nil {
return errors.NewInternalError(err)
} }
namespaceNodeSelector, err := p.getNodeSelectorMap(namespace) namespaceNodeSelector, err := p.getNodeSelectorMap(namespace)
if err != nil { if err != nil {
return err return err
...@@ -173,13 +167,14 @@ func (a *podNodeSelector) SetInternalClientSet(client internalclientset.Interfac ...@@ -173,13 +167,14 @@ func (a *podNodeSelector) SetInternalClientSet(client internalclientset.Interfac
} }
func (p *podNodeSelector) SetInformerFactory(f informers.SharedInformerFactory) { func (p *podNodeSelector) SetInformerFactory(f informers.SharedInformerFactory) {
p.namespaceInformer = f.InternalNamespaces().Informer() namespaceInformer := f.Core().InternalVersion().Namespaces()
p.SetReadyFunc(p.namespaceInformer.HasSynced) p.namespaceLister = namespaceInformer.Lister()
p.SetReadyFunc(namespaceInformer.Informer().HasSynced)
} }
func (p *podNodeSelector) Validate() error { func (p *podNodeSelector) Validate() error {
if p.namespaceInformer == nil { if p.namespaceLister == nil {
return fmt.Errorf("missing namespaceInformer") return fmt.Errorf("missing namespaceLister")
} }
if p.client == nil { if p.client == nil {
return fmt.Errorf("missing client") return fmt.Errorf("missing client")
......
...@@ -22,12 +22,11 @@ import ( ...@@ -22,12 +22,11 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/admission"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
"k8s.io/kubernetes/pkg/controller/informers" informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
) )
...@@ -45,7 +44,9 @@ func TestPodAdmission(t *testing.T) { ...@@ -45,7 +44,9 @@ func TestPodAdmission(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("unexpected error initializing handler: %v", err) t.Errorf("unexpected error initializing handler: %v", err)
} }
informerFactory.Start(wait.NeverStop) stopCh := make(chan struct{})
defer close(stopCh)
informerFactory.Start(stopCh)
pod := &api.Pod{ pod := &api.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "testPod", Namespace: "testNamespace"}, ObjectMeta: metav1.ObjectMeta{Name: "testPod", Namespace: "testNamespace"},
...@@ -144,7 +145,7 @@ func TestPodAdmission(t *testing.T) { ...@@ -144,7 +145,7 @@ func TestPodAdmission(t *testing.T) {
for _, test := range tests { for _, test := range tests {
if !test.ignoreTestNamespaceNodeSelector { if !test.ignoreTestNamespaceNodeSelector {
namespace.ObjectMeta.Annotations = map[string]string{"scheduler.alpha.kubernetes.io/node-selector": test.namespaceNodeSelector} namespace.ObjectMeta.Annotations = map[string]string{"scheduler.alpha.kubernetes.io/node-selector": test.namespaceNodeSelector}
handler.namespaceInformer.GetStore().Update(namespace) informerFactory.Core().InternalVersion().Namespaces().Informer().GetStore().Update(namespace)
} }
handler.clusterNodeSelectors = make(map[string]string) handler.clusterNodeSelectors = make(map[string]string)
handler.clusterNodeSelectors["clusterDefaultNodeSelector"] = test.defaultNodeSelector handler.clusterNodeSelectors["clusterDefaultNodeSelector"] = test.defaultNodeSelector
...@@ -180,7 +181,7 @@ func TestHandles(t *testing.T) { ...@@ -180,7 +181,7 @@ func TestHandles(t *testing.T) {
// newHandlerForTest returns the admission controller configured for testing. // newHandlerForTest returns the admission controller configured for testing.
func newHandlerForTest(c clientset.Interface) (*podNodeSelector, informers.SharedInformerFactory, error) { func newHandlerForTest(c clientset.Interface) (*podNodeSelector, informers.SharedInformerFactory, error) {
f := informers.NewSharedInformerFactory(nil, c, 5*time.Minute) f := informers.NewSharedInformerFactory(c, 5*time.Minute)
handler := NewPodNodeSelector(nil) handler := NewPodNodeSelector(nil)
pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil) pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil)
pluginInitializer.Initialize(handler) pluginInitializer.Initialize(handler)
......
...@@ -21,6 +21,8 @@ go_library( ...@@ -21,6 +21,8 @@ go_library(
deps = [ deps = [
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/client/listers/core/internalversion:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library", "//pkg/kubeapiserver/admission:go_default_library",
"//pkg/quota:go_default_library", "//pkg/quota:go_default_library",
"//pkg/quota/install:go_default_library", "//pkg/quota/install:go_default_library",
...@@ -35,16 +37,15 @@ go_library( ...@@ -35,16 +37,15 @@ go_library(
"//vendor:k8s.io/apimachinery/pkg/apimachinery/announced", "//vendor:k8s.io/apimachinery/pkg/apimachinery/announced",
"//vendor:k8s.io/apimachinery/pkg/apimachinery/registered", "//vendor:k8s.io/apimachinery/pkg/apimachinery/registered",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apimachinery/pkg/labels",
"//vendor:k8s.io/apimachinery/pkg/runtime", "//vendor:k8s.io/apimachinery/pkg/runtime",
"//vendor:k8s.io/apimachinery/pkg/runtime/schema", "//vendor:k8s.io/apimachinery/pkg/runtime/schema",
"//vendor:k8s.io/apimachinery/pkg/runtime/serializer", "//vendor:k8s.io/apimachinery/pkg/runtime/serializer",
"//vendor:k8s.io/apimachinery/pkg/util/runtime", "//vendor:k8s.io/apimachinery/pkg/util/runtime",
"//vendor:k8s.io/apimachinery/pkg/util/sets", "//vendor:k8s.io/apimachinery/pkg/util/sets",
"//vendor:k8s.io/apimachinery/pkg/util/wait", "//vendor:k8s.io/apimachinery/pkg/util/wait",
"//vendor:k8s.io/apimachinery/pkg/watch",
"//vendor:k8s.io/apiserver/pkg/admission", "//vendor:k8s.io/apiserver/pkg/admission",
"//vendor:k8s.io/apiserver/pkg/storage/etcd", "//vendor:k8s.io/apiserver/pkg/storage/etcd",
"//vendor:k8s.io/client-go/tools/cache",
"//vendor:k8s.io/client-go/util/workqueue", "//vendor:k8s.io/client-go/util/workqueue",
], ],
) )
...@@ -57,6 +58,8 @@ go_test( ...@@ -57,6 +58,8 @@ go_test(
deps = [ deps = [
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library", "//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
"//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/controller:go_default_library",
"//pkg/quota:go_default_library", "//pkg/quota:go_default_library",
"//pkg/quota/generic:go_default_library", "//pkg/quota/generic:go_default_library",
"//pkg/quota/install:go_default_library", "//pkg/quota/install:go_default_library",
......
...@@ -24,6 +24,7 @@ import ( ...@@ -24,6 +24,7 @@ import (
"k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/admission"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
"k8s.io/kubernetes/pkg/quota" "k8s.io/kubernetes/pkg/quota"
"k8s.io/kubernetes/pkg/quota/install" "k8s.io/kubernetes/pkg/quota/install"
...@@ -59,6 +60,7 @@ type quotaAdmission struct { ...@@ -59,6 +60,7 @@ type quotaAdmission struct {
stopCh <-chan struct{} stopCh <-chan struct{}
registry quota.Registry registry quota.Registry
numEvaluators int numEvaluators int
quotaAccessor *quotaAccessor
evaluator Evaluator evaluator Evaluator
} }
...@@ -73,29 +75,41 @@ type liveLookupEntry struct { ...@@ -73,29 +75,41 @@ type liveLookupEntry struct {
// using the provided registry. The registry must have the capability to handle group/kinds that // using the provided registry. The registry must have the capability to handle group/kinds that
// are persisted by the server this admission controller is intercepting // are persisted by the server this admission controller is intercepting
func NewResourceQuota(registry quota.Registry, config *resourcequotaapi.Configuration, numEvaluators int, stopCh <-chan struct{}) (admission.Interface, error) { func NewResourceQuota(registry quota.Registry, config *resourcequotaapi.Configuration, numEvaluators int, stopCh <-chan struct{}) (admission.Interface, error) {
quotaAccessor, err := newQuotaAccessor()
if err != nil {
return nil, err
}
return &quotaAdmission{ return &quotaAdmission{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
stopCh: stopCh, stopCh: stopCh,
registry: registry, registry: registry,
numEvaluators: numEvaluators, numEvaluators: numEvaluators,
config: config, config: config,
quotaAccessor: quotaAccessor,
evaluator: NewQuotaEvaluator(quotaAccessor, registry, nil, config, numEvaluators, stopCh),
}, nil }, nil
} }
func (a *quotaAdmission) SetInternalClientSet(client internalclientset.Interface) { func (a *quotaAdmission) SetInternalClientSet(client internalclientset.Interface) {
var err error a.quotaAccessor.client = client
quotaAccessor, err := newQuotaAccessor(client) }
if err != nil {
// TODO handle errors more cleanly
panic(err)
}
go quotaAccessor.Run(a.stopCh)
a.evaluator = NewQuotaEvaluator(quotaAccessor, a.registry, nil, a.config, a.numEvaluators, a.stopCh) func (a *quotaAdmission) SetInformerFactory(f informers.SharedInformerFactory) {
a.quotaAccessor.lister = f.Core().InternalVersion().ResourceQuotas().Lister()
} }
// Validate ensures an authorizer is set. // Validate ensures an authorizer is set.
func (a *quotaAdmission) Validate() error { func (a *quotaAdmission) Validate() error {
if a.quotaAccessor == nil {
return fmt.Errorf("missing quotaAccessor")
}
if a.quotaAccessor.client == nil {
return fmt.Errorf("missing quotaAccessor.client")
}
if a.quotaAccessor.lister == nil {
return fmt.Errorf("missing quotaAccessor.lister")
}
if a.evaluator == nil { if a.evaluator == nil {
return fmt.Errorf("missing evaluator") return fmt.Errorf("missing evaluator")
} }
......
...@@ -20,17 +20,14 @@ import ( ...@@ -20,17 +20,14 @@ import (
"fmt" "fmt"
"time" "time"
"github.com/golang/glog"
lru "github.com/hashicorp/golang-lru" lru "github.com/hashicorp/golang-lru"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/labels"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/apiserver/pkg/storage/etcd" "k8s.io/apiserver/pkg/storage/etcd"
"k8s.io/client-go/tools/cache"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
corelisters "k8s.io/kubernetes/pkg/client/listers/core/internalversion"
) )
// QuotaAccessor abstracts the get/set logic from the rest of the Evaluator. This could be a test stub, a straight passthrough, // QuotaAccessor abstracts the get/set logic from the rest of the Evaluator. This could be a test stub, a straight passthrough,
...@@ -47,9 +44,8 @@ type QuotaAccessor interface { ...@@ -47,9 +44,8 @@ type QuotaAccessor interface {
type quotaAccessor struct { type quotaAccessor struct {
client clientset.Interface client clientset.Interface
// indexer that holds quota objects by namespace // lister can list/get quota objects from a shared informer's cache
indexer cache.Indexer lister corelisters.ResourceQuotaLister
reflector *cache.Reflector
// liveLookups holds the last few live lookups we've done to help ammortize cost on repeated lookup failures. // liveLookups holds the last few live lookups we've done to help ammortize cost on repeated lookup failures.
// This let's us handle the case of latent caches, by looking up actual results for a namespace on cache miss/no results. // This let's us handle the case of latent caches, by looking up actual results for a namespace on cache miss/no results.
...@@ -63,7 +59,7 @@ type quotaAccessor struct { ...@@ -63,7 +59,7 @@ type quotaAccessor struct {
} }
// newQuotaAccessor creates an object that conforms to the QuotaAccessor interface to be used to retrieve quota objects. // newQuotaAccessor creates an object that conforms to the QuotaAccessor interface to be used to retrieve quota objects.
func newQuotaAccessor(client clientset.Interface) (*quotaAccessor, error) { func newQuotaAccessor() (*quotaAccessor, error) {
liveLookupCache, err := lru.New(100) liveLookupCache, err := lru.New(100)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -72,36 +68,15 @@ func newQuotaAccessor(client clientset.Interface) (*quotaAccessor, error) { ...@@ -72,36 +68,15 @@ func newQuotaAccessor(client clientset.Interface) (*quotaAccessor, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
lw := &cache.ListWatch{
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
return client.Core().ResourceQuotas(metav1.NamespaceAll).List(options)
},
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
return client.Core().ResourceQuotas(metav1.NamespaceAll).Watch(options)
},
}
indexer, reflector := cache.NewNamespaceKeyedIndexerAndReflector(lw, &api.ResourceQuota{}, 0)
// client and lister will be set when SetInternalClientSet and SetInformerFactory are invoked
return &quotaAccessor{ return &quotaAccessor{
client: client,
indexer: indexer,
reflector: reflector,
liveLookupCache: liveLookupCache, liveLookupCache: liveLookupCache,
liveTTL: time.Duration(30 * time.Second), liveTTL: time.Duration(30 * time.Second),
updatedQuotas: updatedCache, updatedQuotas: updatedCache,
}, nil }, nil
} }
// Run begins watching and syncing.
func (e *quotaAccessor) Run(stopCh <-chan struct{}) {
defer utilruntime.HandleCrash()
e.reflector.RunUntil(stopCh)
<-stopCh
glog.Infof("Shutting down quota accessor")
}
func (e *quotaAccessor) UpdateQuotaStatus(newQuota *api.ResourceQuota) error { func (e *quotaAccessor) UpdateQuotaStatus(newQuota *api.ResourceQuota) error {
updatedQuota, err := e.client.Core().ResourceQuotas(newQuota.Namespace).UpdateStatus(newQuota) updatedQuota, err := e.client.Core().ResourceQuotas(newQuota.Namespace).UpdateStatus(newQuota)
if err != nil { if err != nil {
...@@ -136,9 +111,9 @@ func (e *quotaAccessor) checkCache(quota *api.ResourceQuota) *api.ResourceQuota ...@@ -136,9 +111,9 @@ func (e *quotaAccessor) checkCache(quota *api.ResourceQuota) *api.ResourceQuota
func (e *quotaAccessor) GetQuotas(namespace string) ([]api.ResourceQuota, error) { func (e *quotaAccessor) GetQuotas(namespace string) ([]api.ResourceQuota, error) {
// determine if there are any quotas in this namespace // determine if there are any quotas in this namespace
// if there are no quotas, we don't need to do anything // if there are no quotas, we don't need to do anything
items, err := e.indexer.Index("namespace", &api.ResourceQuota{ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: ""}}) items, err := e.lister.ResourceQuotas(namespace).List(labels.Everything())
if err != nil { if err != nil {
return nil, fmt.Errorf("error resolving quota.") return nil, fmt.Errorf("error resolving quota: %v", err)
} }
// if there are no items held in our indexer, check our live-lookup LRU, if that misses, do the live lookup to prime it. // if there are no items held in our indexer, check our live-lookup LRU, if that misses, do the live lookup to prime it.
...@@ -169,7 +144,7 @@ func (e *quotaAccessor) GetQuotas(namespace string) ([]api.ResourceQuota, error) ...@@ -169,7 +144,7 @@ func (e *quotaAccessor) GetQuotas(namespace string) ([]api.ResourceQuota, error)
resourceQuotas := []api.ResourceQuota{} resourceQuotas := []api.ResourceQuota{}
for i := range items { for i := range items {
quota := items[i].(*api.ResourceQuota) quota := items[i]
quota = e.checkCache(quota) quota = e.checkCache(quota)
// always make a copy. We're going to muck around with this and we should never mutate the originals // always make a copy. We're going to muck around with this and we should never mutate the originals
resourceQuotas = append(resourceQuotas, *quota) resourceQuotas = append(resourceQuotas, *quota)
......
...@@ -15,7 +15,8 @@ go_library( ...@@ -15,7 +15,8 @@ go_library(
deps = [ deps = [
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/apis/extensions:go_default_library", "//pkg/apis/extensions:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/client/listers/extensions/internalversion:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library", "//pkg/kubeapiserver/admission:go_default_library",
"//pkg/security/podsecuritypolicy:go_default_library", "//pkg/security/podsecuritypolicy:go_default_library",
"//pkg/security/podsecuritypolicy/util:go_default_library", "//pkg/security/podsecuritypolicy/util:go_default_library",
...@@ -23,15 +24,11 @@ go_library( ...@@ -23,15 +24,11 @@ go_library(
"//pkg/serviceaccount:go_default_library", "//pkg/serviceaccount:go_default_library",
"//pkg/util/maps:go_default_library", "//pkg/util/maps:go_default_library",
"//vendor:github.com/golang/glog", "//vendor:github.com/golang/glog",
"//vendor:k8s.io/apimachinery/pkg/api/errors", "//vendor:k8s.io/apimachinery/pkg/labels",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apimachinery/pkg/runtime",
"//vendor:k8s.io/apimachinery/pkg/util/validation/field", "//vendor:k8s.io/apimachinery/pkg/util/validation/field",
"//vendor:k8s.io/apimachinery/pkg/watch",
"//vendor:k8s.io/apiserver/pkg/admission", "//vendor:k8s.io/apiserver/pkg/admission",
"//vendor:k8s.io/apiserver/pkg/authentication/user", "//vendor:k8s.io/apiserver/pkg/authentication/user",
"//vendor:k8s.io/apiserver/pkg/authorization/authorizer", "//vendor:k8s.io/apiserver/pkg/authorization/authorizer",
"//vendor:k8s.io/client-go/tools/cache",
], ],
) )
...@@ -43,6 +40,9 @@ go_test( ...@@ -43,6 +40,9 @@ go_test(
deps = [ deps = [
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/apis/extensions:go_default_library", "//pkg/apis/extensions:go_default_library",
"//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/client/listers/extensions/internalversion:go_default_library",
"//pkg/controller:go_default_library",
"//pkg/security/apparmor:go_default_library", "//pkg/security/apparmor:go_default_library",
"//pkg/security/podsecuritypolicy:go_default_library", "//pkg/security/podsecuritypolicy:go_default_library",
"//pkg/security/podsecuritypolicy/seccomp:go_default_library", "//pkg/security/podsecuritypolicy/seccomp:go_default_library",
...@@ -54,7 +54,6 @@ go_test( ...@@ -54,7 +54,6 @@ go_test(
"//vendor:k8s.io/apiserver/pkg/admission", "//vendor:k8s.io/apiserver/pkg/admission",
"//vendor:k8s.io/apiserver/pkg/authentication/user", "//vendor:k8s.io/apiserver/pkg/authentication/user",
"//vendor:k8s.io/apiserver/pkg/authorization/authorizer", "//vendor:k8s.io/apiserver/pkg/authorization/authorizer",
"//vendor:k8s.io/client-go/tools/cache",
], ],
) )
......
...@@ -23,18 +23,15 @@ import ( ...@@ -23,18 +23,15 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/authentication/user" "k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/client-go/tools/cache"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
extensionslisters "k8s.io/kubernetes/pkg/client/listers/extensions/internalversion"
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
psp "k8s.io/kubernetes/pkg/security/podsecuritypolicy" psp "k8s.io/kubernetes/pkg/security/podsecuritypolicy"
psputil "k8s.io/kubernetes/pkg/security/podsecuritypolicy/util" psputil "k8s.io/kubernetes/pkg/security/podsecuritypolicy/util"
...@@ -55,7 +52,7 @@ func init() { ...@@ -55,7 +52,7 @@ func init() {
} }
// PSPMatchFn allows plugging in how PSPs are matched against user information. // PSPMatchFn allows plugging in how PSPs are matched against user information.
type PSPMatchFn func(store cache.Store, user user.Info, sa user.Info, authz authorizer.Authorizer) ([]*extensions.PodSecurityPolicy, error) type PSPMatchFn func(lister extensionslisters.PodSecurityPolicyLister, user user.Info, sa user.Info, authz authorizer.Authorizer) ([]*extensions.PodSecurityPolicy, error)
// podSecurityPolicyPlugin holds state for and implements the admission plugin. // podSecurityPolicyPlugin holds state for and implements the admission plugin.
type podSecurityPolicyPlugin struct { type podSecurityPolicyPlugin struct {
...@@ -64,10 +61,7 @@ type podSecurityPolicyPlugin struct { ...@@ -64,10 +61,7 @@ type podSecurityPolicyPlugin struct {
pspMatcher PSPMatchFn pspMatcher PSPMatchFn
failOnNoPolicies bool failOnNoPolicies bool
authz authorizer.Authorizer authz authorizer.Authorizer
lister extensionslisters.PodSecurityPolicyLister
reflector *cache.Reflector
stopChan chan struct{}
store cache.Store
} }
// SetAuthorizer sets the authorizer. // SetAuthorizer sets the authorizer.
...@@ -80,22 +74,18 @@ func (plugin *podSecurityPolicyPlugin) Validate() error { ...@@ -80,22 +74,18 @@ func (plugin *podSecurityPolicyPlugin) Validate() error {
if plugin.authz == nil { if plugin.authz == nil {
return fmt.Errorf("%s requires an authorizer", PluginName) return fmt.Errorf("%s requires an authorizer", PluginName)
} }
if plugin.store == nil { if plugin.lister == nil {
return fmt.Errorf("%s requires an client", PluginName) return fmt.Errorf("%s requires a lister", PluginName)
}
if plugin.store == nil {
return fmt.Errorf("%s requires an client", PluginName)
} }
return nil return nil
} }
var _ admission.Interface = &podSecurityPolicyPlugin{} var _ admission.Interface = &podSecurityPolicyPlugin{}
var _ kubeapiserveradmission.WantsAuthorizer = &podSecurityPolicyPlugin{} var _ kubeapiserveradmission.WantsAuthorizer = &podSecurityPolicyPlugin{}
var _ kubeapiserveradmission.WantsInternalClientSet = &podSecurityPolicyPlugin{} var _ kubeapiserveradmission.WantsInformerFactory = &podSecurityPolicyPlugin{}
// NewPlugin creates a new PSP admission plugin. // NewPlugin creates a new PSP admission plugin.
func NewPlugin(strategyFactory psp.StrategyFactory, pspMatcher PSPMatchFn, failOnNoPolicies bool) *podSecurityPolicyPlugin { func NewPlugin(strategyFactory psp.StrategyFactory, pspMatcher PSPMatchFn, failOnNoPolicies bool) *podSecurityPolicyPlugin {
return &podSecurityPolicyPlugin{ return &podSecurityPolicyPlugin{
Handler: admission.NewHandler(admission.Create, admission.Update), Handler: admission.NewHandler(admission.Create, admission.Update),
strategyFactory: strategyFactory, strategyFactory: strategyFactory,
...@@ -104,35 +94,10 @@ func NewPlugin(strategyFactory psp.StrategyFactory, pspMatcher PSPMatchFn, failO ...@@ -104,35 +94,10 @@ func NewPlugin(strategyFactory psp.StrategyFactory, pspMatcher PSPMatchFn, failO
} }
} }
func (a *podSecurityPolicyPlugin) SetInternalClientSet(client internalclientset.Interface) { func (a *podSecurityPolicyPlugin) SetInformerFactory(f informers.SharedInformerFactory) {
a.store = cache.NewStore(cache.MetaNamespaceKeyFunc) podSecurityPolicyInformer := f.Extensions().InternalVersion().PodSecurityPolicies()
a.reflector = cache.NewReflector( a.lister = podSecurityPolicyInformer.Lister()
&cache.ListWatch{ a.SetReadyFunc(podSecurityPolicyInformer.Informer().HasSynced)
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
return client.Extensions().PodSecurityPolicies().List(options)
},
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
return client.Extensions().PodSecurityPolicies().Watch(options)
},
},
&extensions.PodSecurityPolicy{},
a.store,
0,
)
a.Run()
}
func (a *podSecurityPolicyPlugin) Run() {
if a.stopChan == nil {
a.stopChan = make(chan struct{})
}
a.reflector.RunUntil(a.stopChan)
}
func (a *podSecurityPolicyPlugin) Stop() {
if a.stopChan != nil {
close(a.stopChan)
a.stopChan = nil
}
} }
// Admit determines if the pod should be admitted based on the requested security context // Admit determines if the pod should be admitted based on the requested security context
...@@ -165,7 +130,7 @@ func (c *podSecurityPolicyPlugin) Admit(a admission.Attributes) error { ...@@ -165,7 +130,7 @@ func (c *podSecurityPolicyPlugin) Admit(a admission.Attributes) error {
saInfo = serviceaccount.UserInfo(a.GetNamespace(), pod.Spec.ServiceAccountName, "") saInfo = serviceaccount.UserInfo(a.GetNamespace(), pod.Spec.ServiceAccountName, "")
} }
matchedPolicies, err := c.pspMatcher(c.store, a.GetUserInfo(), saInfo, c.authz) matchedPolicies, err := c.pspMatcher(c.lister, a.GetUserInfo(), saInfo, c.authz)
if err != nil { if err != nil {
return admission.NewForbidden(a, err) return admission.NewForbidden(a, err)
} }
...@@ -308,21 +273,21 @@ func (c *podSecurityPolicyPlugin) createProvidersFromPolicies(psps []*extensions ...@@ -308,21 +273,21 @@ func (c *podSecurityPolicyPlugin) createProvidersFromPolicies(psps []*extensions
return providers, errs return providers, errs
} }
// getMatchingPolicies returns policies from the store. For now this returns everything // getMatchingPolicies returns policies from the lister. For now this returns everything
// in the future it can filter based on UserInfo and permissions. // in the future it can filter based on UserInfo and permissions.
// //
// TODO: this will likely need optimization since the initial implementation will // TODO: this will likely need optimization since the initial implementation will
// always query for authorization. Needs scale testing and possibly checking against // always query for authorization. Needs scale testing and possibly checking against
// a cache. // a cache.
func getMatchingPolicies(store cache.Store, user user.Info, sa user.Info, authz authorizer.Authorizer) ([]*extensions.PodSecurityPolicy, error) { func getMatchingPolicies(lister extensionslisters.PodSecurityPolicyLister, user user.Info, sa user.Info, authz authorizer.Authorizer) ([]*extensions.PodSecurityPolicy, error) {
matchedPolicies := make([]*extensions.PodSecurityPolicy, 0) matchedPolicies := make([]*extensions.PodSecurityPolicy, 0)
for _, c := range store.List() { list, err := lister.List(labels.Everything())
constraint, ok := c.(*extensions.PodSecurityPolicy) if err != nil {
if !ok { return nil, err
return nil, errors.NewInternalError(fmt.Errorf("error converting object from store to a pod security policy: %v", c)) }
}
for _, constraint := range list {
if authorizedForPolicy(user, constraint, authz) || authorizedForPolicy(sa, constraint, authz) { if authorizedForPolicy(user, constraint, authz) || authorizedForPolicy(sa, constraint, authz) {
matchedPolicies = append(matchedPolicies, constraint) matchedPolicies = append(matchedPolicies, constraint)
} }
......
...@@ -30,9 +30,11 @@ import ( ...@@ -30,9 +30,11 @@ import (
kadmission "k8s.io/apiserver/pkg/admission" kadmission "k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/authentication/user" "k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/client-go/tools/cache"
kapi "k8s.io/kubernetes/pkg/api" kapi "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
extensionslisters "k8s.io/kubernetes/pkg/client/listers/extensions/internalversion"
"k8s.io/kubernetes/pkg/controller"
"k8s.io/kubernetes/pkg/security/apparmor" "k8s.io/kubernetes/pkg/security/apparmor"
kpsp "k8s.io/kubernetes/pkg/security/podsecuritypolicy" kpsp "k8s.io/kubernetes/pkg/security/podsecuritypolicy"
"k8s.io/kubernetes/pkg/security/podsecuritypolicy/seccomp" "k8s.io/kubernetes/pkg/security/podsecuritypolicy/seccomp"
...@@ -43,13 +45,13 @@ const defaultContainerName = "test-c" ...@@ -43,13 +45,13 @@ const defaultContainerName = "test-c"
// NewTestAdmission provides an admission plugin with test implementations of internal structs. It uses // NewTestAdmission provides an admission plugin with test implementations of internal structs. It uses
// an authorizer that always returns true. // an authorizer that always returns true.
func NewTestAdmission(store cache.Store) kadmission.Interface { func NewTestAdmission(lister extensionslisters.PodSecurityPolicyLister) kadmission.Interface {
return &podSecurityPolicyPlugin{ return &podSecurityPolicyPlugin{
Handler: kadmission.NewHandler(kadmission.Create), Handler: kadmission.NewHandler(kadmission.Create),
store: store,
strategyFactory: kpsp.NewSimpleStrategyFactory(), strategyFactory: kpsp.NewSimpleStrategyFactory(),
pspMatcher: getMatchingPolicies, pspMatcher: getMatchingPolicies,
authz: &TestAuthorizer{}, authz: &TestAuthorizer{},
lister: lister,
} }
} }
...@@ -1337,13 +1339,14 @@ func TestAdmitSysctls(t *testing.T) { ...@@ -1337,13 +1339,14 @@ func TestAdmitSysctls(t *testing.T) {
} }
func testPSPAdmit(testCaseName string, psps []*extensions.PodSecurityPolicy, pod *kapi.Pod, shouldPass bool, expectedPSP string, t *testing.T) { func testPSPAdmit(testCaseName string, psps []*extensions.PodSecurityPolicy, pod *kapi.Pod, shouldPass bool, expectedPSP string, t *testing.T) {
store := cache.NewStore(cache.MetaNamespaceKeyFunc) informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
store := informerFactory.Extensions().InternalVersion().PodSecurityPolicies().Informer().GetStore()
for _, psp := range psps { for _, psp := range psps {
store.Add(psp) store.Add(psp)
} }
plugin := NewTestAdmission(store) plugin := NewTestAdmission(informerFactory.Extensions().InternalVersion().PodSecurityPolicies().Lister())
attrs := kadmission.NewAttributesRecord(pod, nil, kapi.Kind("Pod").WithVersion("version"), "namespace", "", kapi.Resource("pods").WithVersion("version"), "", kadmission.Create, &user.DefaultInfo{}) attrs := kadmission.NewAttributesRecord(pod, nil, kapi.Kind("Pod").WithVersion("version"), "namespace", "", kapi.Resource("pods").WithVersion("version"), "", kadmission.Create, &user.DefaultInfo{})
err := plugin.Admit(attrs) err := plugin.Admit(attrs)
...@@ -1505,11 +1508,8 @@ func TestCreateProvidersFromConstraints(t *testing.T) { ...@@ -1505,11 +1508,8 @@ func TestCreateProvidersFromConstraints(t *testing.T) {
} }
for k, v := range testCases { for k, v := range testCases {
store := cache.NewStore(cache.MetaNamespaceKeyFunc)
admit := &podSecurityPolicyPlugin{ admit := &podSecurityPolicyPlugin{
Handler: kadmission.NewHandler(kadmission.Create, kadmission.Update), Handler: kadmission.NewHandler(kadmission.Create, kadmission.Update),
store: store,
strategyFactory: kpsp.NewSimpleStrategyFactory(), strategyFactory: kpsp.NewSimpleStrategyFactory(),
} }
...@@ -1628,13 +1628,15 @@ func TestGetMatchingPolicies(t *testing.T) { ...@@ -1628,13 +1628,15 @@ func TestGetMatchingPolicies(t *testing.T) {
}, },
} }
for k, v := range tests { for k, v := range tests {
store := cache.NewStore(cache.MetaNamespaceKeyFunc) informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
pspInformer := informerFactory.Extensions().InternalVersion().PodSecurityPolicies()
store := pspInformer.Informer().GetStore()
for _, psp := range v.inPolicies { for _, psp := range v.inPolicies {
store.Add(psp) store.Add(psp)
} }
authz := &TestAuthorizer{disallowed: v.disallowedPolicies} authz := &TestAuthorizer{disallowed: v.disallowedPolicies}
allowedPolicies, err := getMatchingPolicies(store, v.user, v.sa, authz) allowedPolicies, err := getMatchingPolicies(pspInformer.Lister(), v.user, v.sa, authz)
if err != nil { if err != nil {
t.Errorf("%s got unexpected error %#v", k, err) t.Errorf("%s got unexpected error %#v", k, err)
continue continue
......
...@@ -18,19 +18,18 @@ go_library( ...@@ -18,19 +18,18 @@ go_library(
deps = [ deps = [
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/client/listers/core/internalversion:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library", "//pkg/kubeapiserver/admission:go_default_library",
"//pkg/kubelet/types:go_default_library", "//pkg/kubelet/types:go_default_library",
"//pkg/serviceaccount:go_default_library", "//pkg/serviceaccount:go_default_library",
"//vendor:k8s.io/apimachinery/pkg/api/errors", "//vendor:k8s.io/apimachinery/pkg/api/errors",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apimachinery/pkg/fields", "//vendor:k8s.io/apimachinery/pkg/labels",
"//vendor:k8s.io/apimachinery/pkg/runtime",
"//vendor:k8s.io/apimachinery/pkg/runtime/schema", "//vendor:k8s.io/apimachinery/pkg/runtime/schema",
"//vendor:k8s.io/apimachinery/pkg/util/sets", "//vendor:k8s.io/apimachinery/pkg/util/sets",
"//vendor:k8s.io/apimachinery/pkg/watch",
"//vendor:k8s.io/apiserver/pkg/admission", "//vendor:k8s.io/apiserver/pkg/admission",
"//vendor:k8s.io/apiserver/pkg/storage/names", "//vendor:k8s.io/apiserver/pkg/storage/names",
"//vendor:k8s.io/client-go/tools/cache",
], ],
) )
...@@ -42,6 +41,8 @@ go_test( ...@@ -42,6 +41,8 @@ go_test(
deps = [ deps = [
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library", "//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
"//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/controller:go_default_library",
"//pkg/kubelet/types:go_default_library", "//pkg/kubelet/types:go_default_library",
"//vendor:k8s.io/apimachinery/pkg/api/errors", "//vendor:k8s.io/apimachinery/pkg/api/errors",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
......
...@@ -25,16 +25,15 @@ import ( ...@@ -25,16 +25,15 @@ import (
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/storage/names" "k8s.io/apiserver/pkg/storage/names"
"k8s.io/client-go/tools/cache"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
corelisters "k8s.io/kubernetes/pkg/client/listers/core/internalversion"
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
kubelet "k8s.io/kubernetes/pkg/kubelet/types" kubelet "k8s.io/kubernetes/pkg/kubelet/types"
"k8s.io/kubernetes/pkg/serviceaccount" "k8s.io/kubernetes/pkg/serviceaccount"
...@@ -75,15 +74,12 @@ type serviceAccount struct { ...@@ -75,15 +74,12 @@ type serviceAccount struct {
client internalclientset.Interface client internalclientset.Interface
serviceAccounts cache.Indexer serviceAccountLister corelisters.ServiceAccountLister
secrets cache.Indexer secretLister corelisters.SecretLister
stopChan chan struct{}
serviceAccountsReflector *cache.Reflector
secretsReflector *cache.Reflector
} }
var _ = kubeapiserveradmission.WantsInternalClientSet(&serviceAccount{}) var _ = kubeapiserveradmission.WantsInternalClientSet(&serviceAccount{})
var _ = kubeapiserveradmission.WantsInformerFactory(&serviceAccount{})
// NewServiceAccount returns an admission.Interface implementation which limits admission of Pod CREATE requests based on the pod's ServiceAccount: // NewServiceAccount returns an admission.Interface implementation which limits admission of Pod CREATE requests based on the pod's ServiceAccount:
// 1. If the pod does not specify a ServiceAccount, it sets the pod's ServiceAccount to "default" // 1. If the pod does not specify a ServiceAccount, it sets the pod's ServiceAccount to "default"
...@@ -105,38 +101,18 @@ func NewServiceAccount() *serviceAccount { ...@@ -105,38 +101,18 @@ func NewServiceAccount() *serviceAccount {
func (a *serviceAccount) SetInternalClientSet(cl internalclientset.Interface) { func (a *serviceAccount) SetInternalClientSet(cl internalclientset.Interface) {
a.client = cl a.client = cl
a.serviceAccounts, a.serviceAccountsReflector = cache.NewNamespaceKeyedIndexerAndReflector( }
&cache.ListWatch{
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
return cl.Core().ServiceAccounts(metav1.NamespaceAll).List(options)
},
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
return cl.Core().ServiceAccounts(metav1.NamespaceAll).Watch(options)
},
},
&api.ServiceAccount{},
0,
)
tokenSelector := fields.SelectorFromSet(map[string]string{api.SecretTypeField: string(api.SecretTypeServiceAccountToken)})
a.secrets, a.secretsReflector = cache.NewNamespaceKeyedIndexerAndReflector(
&cache.ListWatch{
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
options.FieldSelector = tokenSelector.String()
return cl.Core().Secrets(metav1.NamespaceAll).List(options)
},
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
options.FieldSelector = tokenSelector.String()
return cl.Core().Secrets(metav1.NamespaceAll).Watch(options)
},
},
&api.Secret{},
0,
)
if cl != nil { func (a *serviceAccount) SetInformerFactory(f informers.SharedInformerFactory) {
a.Run() serviceAccountInformer := f.Core().InternalVersion().ServiceAccounts()
} a.serviceAccountLister = serviceAccountInformer.Lister()
secretInformer := f.Core().InternalVersion().Secrets()
a.secretLister = secretInformer.Lister()
a.SetReadyFunc(func() bool {
return serviceAccountInformer.Informer().HasSynced() && secretInformer.Informer().HasSynced()
})
} }
// Validate ensures an authorizer is set. // Validate ensures an authorizer is set.
...@@ -144,35 +120,15 @@ func (a *serviceAccount) Validate() error { ...@@ -144,35 +120,15 @@ func (a *serviceAccount) Validate() error {
if a.client == nil { if a.client == nil {
return fmt.Errorf("missing client") return fmt.Errorf("missing client")
} }
if a.secrets == nil { if a.secretLister == nil {
return fmt.Errorf("missing secretsIndexer") return fmt.Errorf("missing secretLister")
} }
if a.secretsReflector == nil { if a.serviceAccountLister == nil {
return fmt.Errorf("missing secretsReflector") return fmt.Errorf("missing serviceAccountLister")
}
if a.serviceAccounts == nil {
return fmt.Errorf("missing serviceAccountsIndexer")
}
if a.serviceAccountsReflector == nil {
return fmt.Errorf("missing serviceAccountsReflector")
} }
return nil return nil
} }
func (s *serviceAccount) Run() {
if s.stopChan == nil {
s.stopChan = make(chan struct{})
s.serviceAccountsReflector.RunUntil(s.stopChan)
s.secretsReflector.RunUntil(s.stopChan)
}
}
func (s *serviceAccount) Stop() {
if s.stopChan != nil {
close(s.stopChan)
s.stopChan = nil
}
}
func (s *serviceAccount) Admit(a admission.Attributes) (err error) { func (s *serviceAccount) Admit(a admission.Attributes) (err error) {
if a.GetResource().GroupResource() != api.Resource("pods") { if a.GetResource().GroupResource() != api.Resource("pods") {
return nil return nil
...@@ -269,17 +225,12 @@ func (s *serviceAccount) enforceMountableSecrets(serviceAccount *api.ServiceAcco ...@@ -269,17 +225,12 @@ func (s *serviceAccount) enforceMountableSecrets(serviceAccount *api.ServiceAcco
// getServiceAccount returns the ServiceAccount for the given namespace and name if it exists // getServiceAccount returns the ServiceAccount for the given namespace and name if it exists
func (s *serviceAccount) getServiceAccount(namespace string, name string) (*api.ServiceAccount, error) { func (s *serviceAccount) getServiceAccount(namespace string, name string) (*api.ServiceAccount, error) {
key := &api.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Namespace: namespace}} serviceAccount, err := s.serviceAccountLister.ServiceAccounts(namespace).Get(name)
index, err := s.serviceAccounts.Index("namespace", key) if err == nil {
if err != nil { return serviceAccount, nil
return nil, err
} }
if !errors.IsNotFound(err) {
for _, obj := range index { return nil, err
serviceAccount := obj.(*api.ServiceAccount)
if serviceAccount.Name == name {
return serviceAccount, nil
}
} }
// Could not find in cache, attempt to look up directly // Could not find in cache, attempt to look up directly
...@@ -332,15 +283,15 @@ func (s *serviceAccount) getReferencedServiceAccountToken(serviceAccount *api.Se ...@@ -332,15 +283,15 @@ func (s *serviceAccount) getReferencedServiceAccountToken(serviceAccount *api.Se
// getServiceAccountTokens returns all ServiceAccountToken secrets for the given ServiceAccount // getServiceAccountTokens returns all ServiceAccountToken secrets for the given ServiceAccount
func (s *serviceAccount) getServiceAccountTokens(serviceAccount *api.ServiceAccount) ([]*api.Secret, error) { func (s *serviceAccount) getServiceAccountTokens(serviceAccount *api.ServiceAccount) ([]*api.Secret, error) {
key := &api.Secret{ObjectMeta: metav1.ObjectMeta{Namespace: serviceAccount.Namespace}} tokens, err := s.secretLister.Secrets(serviceAccount.Namespace).List(labels.Everything())
index, err := s.secrets.Index("namespace", key)
if err != nil { if err != nil {
return nil, err return nil, err
} }
tokens := []*api.Secret{} for _, token := range tokens {
for _, obj := range index { if token.Type != api.SecretTypeServiceAccountToken {
token := obj.(*api.Secret) continue
}
if serviceaccount.InternalIsServiceAccountToken(token, serviceAccount) { if serviceaccount.InternalIsServiceAccountToken(token, serviceAccount) {
tokens = append(tokens, token) tokens = append(tokens, token)
......
...@@ -16,15 +16,13 @@ go_library( ...@@ -16,15 +16,13 @@ go_library(
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/apis/storage:go_default_library", "//pkg/apis/storage:go_default_library",
"//pkg/apis/storage/util:go_default_library", "//pkg/apis/storage/util:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/client/listers/storage/internalversion:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library", "//pkg/kubeapiserver/admission:go_default_library",
"//vendor:github.com/golang/glog", "//vendor:github.com/golang/glog",
"//vendor:k8s.io/apimachinery/pkg/api/errors", "//vendor:k8s.io/apimachinery/pkg/api/errors",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", "//vendor:k8s.io/apimachinery/pkg/labels",
"//vendor:k8s.io/apimachinery/pkg/runtime",
"//vendor:k8s.io/apimachinery/pkg/watch",
"//vendor:k8s.io/apiserver/pkg/admission", "//vendor:k8s.io/apiserver/pkg/admission",
"//vendor:k8s.io/client-go/tools/cache",
], ],
) )
...@@ -37,6 +35,8 @@ go_test( ...@@ -37,6 +35,8 @@ go_test(
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/apis/storage:go_default_library", "//pkg/apis/storage:go_default_library",
"//pkg/apis/storage/util:go_default_library", "//pkg/apis/storage/util:go_default_library",
"//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/controller:go_default_library",
"//vendor:github.com/golang/glog", "//vendor:github.com/golang/glog",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apiserver/pkg/admission", "//vendor:k8s.io/apiserver/pkg/admission",
......
...@@ -23,15 +23,13 @@ import ( ...@@ -23,15 +23,13 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/watch"
admission "k8s.io/apiserver/pkg/admission" admission "k8s.io/apiserver/pkg/admission"
"k8s.io/client-go/tools/cache"
api "k8s.io/kubernetes/pkg/api" api "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/storage" "k8s.io/kubernetes/pkg/apis/storage"
storageutil "k8s.io/kubernetes/pkg/apis/storage/util" storageutil "k8s.io/kubernetes/pkg/apis/storage/util"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
storagelisters "k8s.io/kubernetes/pkg/client/listers/storage/internalversion"
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
) )
...@@ -49,15 +47,12 @@ func init() { ...@@ -49,15 +47,12 @@ func init() {
// claimDefaulterPlugin holds state for and implements the admission plugin. // claimDefaulterPlugin holds state for and implements the admission plugin.
type claimDefaulterPlugin struct { type claimDefaulterPlugin struct {
*admission.Handler *admission.Handler
client internalclientset.Interface
reflector *cache.Reflector lister storagelisters.StorageClassLister
stopChan chan struct{}
store cache.Store
} }
var _ admission.Interface = &claimDefaulterPlugin{} var _ admission.Interface = &claimDefaulterPlugin{}
var _ = kubeapiserveradmission.WantsInternalClientSet(&claimDefaulterPlugin{}) var _ = kubeapiserveradmission.WantsInformerFactory(&claimDefaulterPlugin{})
// newPlugin creates a new admission plugin. // newPlugin creates a new admission plugin.
func newPlugin() *claimDefaulterPlugin { func newPlugin() *claimDefaulterPlugin {
...@@ -66,55 +61,20 @@ func newPlugin() *claimDefaulterPlugin { ...@@ -66,55 +61,20 @@ func newPlugin() *claimDefaulterPlugin {
} }
} }
func (a *claimDefaulterPlugin) SetInternalClientSet(client internalclientset.Interface) { func (a *claimDefaulterPlugin) SetInformerFactory(f informers.SharedInformerFactory) {
a.client = client informer := f.Storage().InternalVersion().StorageClasses()
a.store = cache.NewStore(cache.MetaNamespaceKeyFunc) a.lister = informer.Lister()
a.reflector = cache.NewReflector( a.SetReadyFunc(informer.Informer().HasSynced)
&cache.ListWatch{
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
return client.Storage().StorageClasses().List(options)
},
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
return client.Storage().StorageClasses().Watch(options)
},
},
&storage.StorageClass{},
a.store,
0,
)
if client != nil {
a.Run()
}
} }
// Validate ensures an authorizer is set. // Validate ensures an authorizer is set.
func (a *claimDefaulterPlugin) Validate() error { func (a *claimDefaulterPlugin) Validate() error {
if a.client == nil { if a.lister == nil {
return fmt.Errorf("missing client") return fmt.Errorf("missing lister")
}
if a.reflector == nil {
return fmt.Errorf("missing reflector")
}
if a.store == nil {
return fmt.Errorf("missing store")
} }
return nil return nil
} }
func (a *claimDefaulterPlugin) Run() {
if a.stopChan == nil {
a.stopChan = make(chan struct{})
}
a.reflector.RunUntil(a.stopChan)
}
func (a *claimDefaulterPlugin) Stop() {
if a.stopChan != nil {
close(a.stopChan)
a.stopChan = nil
}
}
// Admit sets the default value of a PersistentVolumeClaim's storage class, in case the user did // Admit sets the default value of a PersistentVolumeClaim's storage class, in case the user did
// not provide a value. // not provide a value.
// //
...@@ -143,7 +103,7 @@ func (c *claimDefaulterPlugin) Admit(a admission.Attributes) error { ...@@ -143,7 +103,7 @@ func (c *claimDefaulterPlugin) Admit(a admission.Attributes) error {
glog.V(4).Infof("no storage class for claim %s (generate: %s)", pvc.Name, pvc.GenerateName) glog.V(4).Infof("no storage class for claim %s (generate: %s)", pvc.Name, pvc.GenerateName)
def, err := getDefaultClass(c.store) def, err := getDefaultClass(c.lister)
if err != nil { if err != nil {
return admission.NewForbidden(a, err) return admission.NewForbidden(a, err)
} }
...@@ -161,13 +121,14 @@ func (c *claimDefaulterPlugin) Admit(a admission.Attributes) error { ...@@ -161,13 +121,14 @@ func (c *claimDefaulterPlugin) Admit(a admission.Attributes) error {
} }
// getDefaultClass returns the default StorageClass from the store, or nil. // getDefaultClass returns the default StorageClass from the store, or nil.
func getDefaultClass(store cache.Store) (*storage.StorageClass, error) { func getDefaultClass(lister storagelisters.StorageClassLister) (*storage.StorageClass, error) {
list, err := lister.List(labels.Everything())
if err != nil {
return nil, err
}
defaultClasses := []*storage.StorageClass{} defaultClasses := []*storage.StorageClass{}
for _, c := range store.List() { for _, class := range list {
class, ok := c.(*storage.StorageClass)
if !ok {
return nil, errors.NewInternalError(fmt.Errorf("error converting stored object to StorageClass: %v", c))
}
if storageutil.IsDefaultAnnotation(class.ObjectMeta) { if storageutil.IsDefaultAnnotation(class.ObjectMeta) {
defaultClasses = append(defaultClasses, class) defaultClasses = append(defaultClasses, class)
glog.V(4).Infof("getDefaultClass added: %s", class.Name) glog.V(4).Infof("getDefaultClass added: %s", class.Name)
......
...@@ -26,6 +26,8 @@ import ( ...@@ -26,6 +26,8 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/storage" "k8s.io/kubernetes/pkg/apis/storage"
storageutil "k8s.io/kubernetes/pkg/apis/storage/util" storageutil "k8s.io/kubernetes/pkg/apis/storage/util"
informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
"k8s.io/kubernetes/pkg/controller"
) )
func TestAdmission(t *testing.T) { func TestAdmission(t *testing.T) {
...@@ -193,9 +195,10 @@ func TestAdmission(t *testing.T) { ...@@ -193,9 +195,10 @@ func TestAdmission(t *testing.T) {
claim := clone.(*api.PersistentVolumeClaim) claim := clone.(*api.PersistentVolumeClaim)
ctrl := newPlugin() ctrl := newPlugin()
ctrl.SetInternalClientSet(nil) informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
ctrl.SetInformerFactory(informerFactory)
for _, c := range test.classes { for _, c := range test.classes {
ctrl.store.Add(c) informerFactory.Storage().InternalVersion().StorageClasses().Informer().GetStore().Add(c)
} }
attrs := admission.NewAttributesRecord( attrs := admission.NewAttributesRecord(
claim, // new object claim, // new object
......
...@@ -310,7 +310,12 @@ func ClusterRoles() []rbac.ClusterRole { ...@@ -310,7 +310,12 @@ func ClusterRoles() []rbac.ClusterRole {
"services", "services",
"serviceaccounts", "serviceaccounts",
).RuleOrDie(), ).RuleOrDie(),
rbac.NewRule("list", "watch").Groups(extensionsGroup).Resources("daemonsets", "deployments", "replicasets").RuleOrDie(), rbac.NewRule("list", "watch").Groups(extensionsGroup).Resources(
"daemonsets",
"deployments",
"podsecuritypolicies",
"replicasets",
).RuleOrDie(),
rbac.NewRule("list", "watch").Groups(batchGroup).Resources("jobs", "cronjobs").RuleOrDie(), rbac.NewRule("list", "watch").Groups(batchGroup).Resources("jobs", "cronjobs").RuleOrDie(),
rbac.NewRule("list", "watch").Groups(appsGroup).Resources("statefulsets").RuleOrDie(), rbac.NewRule("list", "watch").Groups(appsGroup).Resources("statefulsets").RuleOrDie(),
rbac.NewRule("list", "watch").Groups(policyGroup).Resources("poddisruptionbudgets").RuleOrDie(), rbac.NewRule("list", "watch").Groups(policyGroup).Resources("poddisruptionbudgets").RuleOrDie(),
......
...@@ -489,6 +489,7 @@ items: ...@@ -489,6 +489,7 @@ items:
resources: resources:
- daemonsets - daemonsets
- deployments - deployments
- podsecuritypolicies
- replicasets - replicasets
verbs: verbs:
- list - list
......
...@@ -39,6 +39,7 @@ import ( ...@@ -39,6 +39,7 @@ import (
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/clientset" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/externalversions" informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/externalversions"
internalinformers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
"k8s.io/kubernetes/pkg/controller" "k8s.io/kubernetes/pkg/controller"
replicationcontroller "k8s.io/kubernetes/pkg/controller/replication" replicationcontroller "k8s.io/kubernetes/pkg/controller/replication"
resourcequotacontroller "k8s.io/kubernetes/pkg/controller/resourcequota" resourcequotacontroller "k8s.io/kubernetes/pkg/controller/resourcequota"
...@@ -73,6 +74,8 @@ func TestQuota(t *testing.T) { ...@@ -73,6 +74,8 @@ func TestQuota(t *testing.T) {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
admission.(kubeadmission.WantsInternalClientSet).SetInternalClientSet(internalClientset) admission.(kubeadmission.WantsInternalClientSet).SetInternalClientSet(internalClientset)
internalInformers := internalinformers.NewSharedInformerFactory(internalClientset, controller.NoResyncPeriodFunc())
admission.(kubeadmission.WantsInformerFactory).SetInformerFactory(internalInformers)
defer close(admissionCh) defer close(admissionCh)
masterConfig := framework.NewIntegrationTestMasterConfig() masterConfig := framework.NewIntegrationTestMasterConfig()
...@@ -113,6 +116,7 @@ func TestQuota(t *testing.T) { ...@@ -113,6 +116,7 @@ func TestQuota(t *testing.T) {
ControllerFactory: resourcequotacontroller.NewReplenishmentControllerFactory(informers), ControllerFactory: resourcequotacontroller.NewReplenishmentControllerFactory(informers),
} }
go resourcequotacontroller.NewResourceQuotaController(resourceQuotaControllerOptions).Run(2, controllerCh) go resourcequotacontroller.NewResourceQuotaController(resourceQuotaControllerOptions).Run(2, controllerCh)
internalInformers.Start(controllerCh)
informers.Start(controllerCh) informers.Start(controllerCh)
startTime := time.Now() startTime := time.Now()
...@@ -257,6 +261,8 @@ func TestQuotaLimitedResourceDenial(t *testing.T) { ...@@ -257,6 +261,8 @@ func TestQuotaLimitedResourceDenial(t *testing.T) {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
admission.(kubeadmission.WantsInternalClientSet).SetInternalClientSet(internalClientset) admission.(kubeadmission.WantsInternalClientSet).SetInternalClientSet(internalClientset)
internalInformers := internalinformers.NewSharedInformerFactory(internalClientset, controller.NoResyncPeriodFunc())
admission.(kubeadmission.WantsInformerFactory).SetInformerFactory(internalInformers)
defer close(admissionCh) defer close(admissionCh)
masterConfig := framework.NewIntegrationTestMasterConfig() masterConfig := framework.NewIntegrationTestMasterConfig()
...@@ -295,6 +301,7 @@ func TestQuotaLimitedResourceDenial(t *testing.T) { ...@@ -295,6 +301,7 @@ func TestQuotaLimitedResourceDenial(t *testing.T) {
ControllerFactory: resourcequotacontroller.NewReplenishmentControllerFactory(informers), ControllerFactory: resourcequotacontroller.NewReplenishmentControllerFactory(informers),
} }
go resourcequotacontroller.NewResourceQuotaController(resourceQuotaControllerOptions).Run(2, controllerCh) go resourcequotacontroller.NewResourceQuotaController(resourceQuotaControllerOptions).Run(2, controllerCh)
internalInformers.Start(controllerCh)
informers.Start(controllerCh) informers.Start(controllerCh)
// try to create a pod // try to create a pod
......
...@@ -48,6 +48,7 @@ import ( ...@@ -48,6 +48,7 @@ import (
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset" "k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/externalversions" informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/externalversions"
internalinformers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
"k8s.io/kubernetes/pkg/controller" "k8s.io/kubernetes/pkg/controller"
serviceaccountcontroller "k8s.io/kubernetes/pkg/controller/serviceaccount" serviceaccountcontroller "k8s.io/kubernetes/pkg/controller/serviceaccount"
"k8s.io/kubernetes/pkg/serviceaccount" "k8s.io/kubernetes/pkg/serviceaccount"
...@@ -407,6 +408,8 @@ func startServiceAccountTestServer(t *testing.T) (*clientset.Clientset, restclie ...@@ -407,6 +408,8 @@ func startServiceAccountTestServer(t *testing.T) (*clientset.Clientset, restclie
// Set up admission plugin to auto-assign serviceaccounts to pods // Set up admission plugin to auto-assign serviceaccounts to pods
serviceAccountAdmission := serviceaccountadmission.NewServiceAccount() serviceAccountAdmission := serviceaccountadmission.NewServiceAccount()
serviceAccountAdmission.SetInternalClientSet(internalRootClientset) serviceAccountAdmission.SetInternalClientSet(internalRootClientset)
internalInformers := internalinformers.NewSharedInformerFactory(internalRootClientset, controller.NoResyncPeriodFunc())
serviceAccountAdmission.SetInformerFactory(internalInformers)
masterConfig := framework.NewMasterConfig() masterConfig := framework.NewMasterConfig()
masterConfig.GenericConfig.EnableIndex = true masterConfig.GenericConfig.EnableIndex = true
...@@ -428,13 +431,11 @@ func startServiceAccountTestServer(t *testing.T) (*clientset.Clientset, restclie ...@@ -428,13 +431,11 @@ func startServiceAccountTestServer(t *testing.T) (*clientset.Clientset, restclie
serviceaccountcontroller.DefaultServiceAccountsControllerOptions(), serviceaccountcontroller.DefaultServiceAccountsControllerOptions(),
) )
informers.Start(stopCh) informers.Start(stopCh)
internalInformers.Start(stopCh)
go serviceAccountController.Run(5, stopCh) go serviceAccountController.Run(5, stopCh)
// Start the admission plugin reflectors
serviceAccountAdmission.Run()
stop := func() { stop := func() {
close(stopCh) close(stopCh)
serviceAccountAdmission.Stop()
apiServer.Close() apiServer.Close()
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment