Unverified Commit 0ffd59e4 authored by Kubernetes Prow Robot's avatar Kubernetes Prow Robot Committed by GitHub

Merge pull request #74154 from mbohlool/gimli

Use Request Object interfaces instead of static scheme that is more appropriate for CRDs
parents 9ac5e491 0f186323
......@@ -70,7 +70,6 @@ func createAggregatorConfig(
&genericConfig,
externalInformers,
genericConfig.LoopbackClientConfig,
aggregatorscheme.Scheme,
pluginInitializers...)
if err != nil {
return nil, err
......
......@@ -52,7 +52,6 @@ func createAPIExtensionsConfig(
&genericConfig,
externalInformers,
genericConfig.LoopbackClientConfig,
apiextensionsapiserver.Scheme,
pluginInitializers...)
if err != nil {
return nil, err
......
......@@ -491,7 +491,6 @@ func buildGenericConfig(
genericConfig,
versionedInformers,
kubeClientConfig,
legacyscheme.Scheme,
pluginInitializers...)
if err != nil {
lastErr = fmt.Errorf("failed to initialize admission: %v", err)
......
......@@ -24,7 +24,9 @@ import (
type doNothingAdmission struct{}
func (doNothingAdmission) Admit(a admission.Attributes) error { return nil }
func (doNothingAdmission) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
return nil
}
func (doNothingAdmission) Handles(o admission.Operation) bool { return false }
func (doNothingAdmission) Validate() error { return nil }
......
......@@ -51,7 +51,6 @@ go_library(
"//plugin/pkg/admission/storage/persistentvolume/resize:go_default_library",
"//plugin/pkg/admission/storage/storageclass/setdefault:go_default_library",
"//plugin/pkg/admission/storage/storageobjectinuseprotection:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/admission:go_default_library",
......
......@@ -22,7 +22,6 @@ import (
"github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/server"
......@@ -108,7 +107,6 @@ func (a *AdmissionOptions) ApplyTo(
c *server.Config,
informers informers.SharedInformerFactory,
kubeAPIServerClientConfig *rest.Config,
scheme *runtime.Scheme,
pluginInitializers ...admission.PluginInitializer,
) error {
if a == nil {
......@@ -120,7 +118,7 @@ func (a *AdmissionOptions) ApplyTo(
a.GenericAdmission.EnablePlugins, a.GenericAdmission.DisablePlugins = computePluginNames(a.PluginNames, a.GenericAdmission.RecommendedPluginOrder)
}
return a.GenericAdmission.ApplyTo(c, informers, kubeAPIServerClientConfig, scheme, pluginInitializers...)
return a.GenericAdmission.ApplyTo(c, informers, kubeAPIServerClientConfig, pluginInitializers...)
}
// explicitly disable all plugins that are not in the enabled list
......
......@@ -40,12 +40,12 @@ var _ admission.MutationInterface = alwaysAdmit{}
var _ admission.ValidationInterface = alwaysAdmit{}
// Admit makes an admission decision based on the request attributes
func (alwaysAdmit) Admit(a admission.Attributes) (err error) {
func (alwaysAdmit) Admit(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
return nil
}
// Validate makes an admission decision based on the request attributes. It is NOT allowed to mutate.
func (alwaysAdmit) Validate(a admission.Attributes) (err error) {
func (alwaysAdmit) Validate(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
return nil
}
......
......@@ -25,7 +25,7 @@ import (
func TestAdmissionNonNilAttribute(t *testing.T) {
handler := NewAlwaysAdmit()
err := handler.(*alwaysAdmit).Admit(admission.NewAttributesRecord(nil, nil, api.Kind("kind").WithVersion("version"), "namespace", "name", api.Resource("resource").WithVersion("version"), "subresource", admission.Create, false, nil))
err := handler.(*alwaysAdmit).Admit(admission.NewAttributesRecord(nil, nil, api.Kind("kind").WithVersion("version"), "namespace", "name", api.Resource("resource").WithVersion("version"), "subresource", admission.Create, false, nil), nil)
if err != nil {
t.Errorf("Unexpected error returned from admission handler")
}
......@@ -33,7 +33,7 @@ func TestAdmissionNonNilAttribute(t *testing.T) {
func TestAdmissionNilAttribute(t *testing.T) {
handler := NewAlwaysAdmit()
err := handler.(*alwaysAdmit).Admit(nil)
err := handler.(*alwaysAdmit).Admit(nil, nil)
if err != nil {
t.Errorf("Unexpected error returned from admission handler")
}
......
......@@ -53,7 +53,7 @@ var _ admission.MutationInterface = &AlwaysPullImages{}
var _ admission.ValidationInterface = &AlwaysPullImages{}
// Admit makes an admission decision based on the request attributes
func (a *AlwaysPullImages) Admit(attributes admission.Attributes) (err error) {
func (a *AlwaysPullImages) Admit(attributes admission.Attributes, o admission.ObjectInterfaces) (err error) {
// Ignore all calls to subresources or resources other than pods.
if shouldIgnore(attributes) {
return nil
......@@ -75,7 +75,7 @@ func (a *AlwaysPullImages) Admit(attributes admission.Attributes) (err error) {
}
// Validate makes sure that all containers are set to always pull images
func (*AlwaysPullImages) Validate(attributes admission.Attributes) (err error) {
func (*AlwaysPullImages) Validate(attributes admission.Attributes, o admission.ObjectInterfaces) (err error) {
if shouldIgnore(attributes) {
return nil
}
......
......@@ -47,7 +47,7 @@ func TestAdmission(t *testing.T) {
},
},
}
err := handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil))
err := handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil), nil)
if err != nil {
t.Errorf("Unexpected error returned from admission handler")
}
......@@ -84,7 +84,7 @@ func TestValidate(t *testing.T) {
},
}
expectedError := `pods "123" is forbidden: spec.initContainers[0].imagePullPolicy: Unsupported value: "": supported values: "Always"`
err := handler.Validate(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil))
err := handler.Validate(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil), nil)
if err == nil {
t.Fatal("missing expected error")
}
......@@ -139,7 +139,7 @@ func TestOtherResources(t *testing.T) {
for _, tc := range tests {
handler := &AlwaysPullImages{}
err := handler.Admit(admission.NewAttributesRecord(tc.object, nil, api.Kind(tc.kind).WithVersion("version"), namespace, name, api.Resource(tc.resource).WithVersion("version"), tc.subresource, admission.Create, false, nil))
err := handler.Admit(admission.NewAttributesRecord(tc.object, nil, api.Kind(tc.kind).WithVersion("version"), namespace, name, api.Resource(tc.resource).WithVersion("version"), tc.subresource, admission.Create, false, nil), nil)
if tc.expectError {
if err == nil {
......
......@@ -51,7 +51,7 @@ func NewInterPodAntiAffinity() *Plugin {
// Validate will deny any pod that defines AntiAffinity topology key other than v1.LabelHostname i.e. "kubernetes.io/hostname"
// in requiredDuringSchedulingRequiredDuringExecution and requiredDuringSchedulingIgnoredDuringExecution.
func (p *Plugin) Validate(attributes admission.Attributes) (err error) {
func (p *Plugin) Validate(attributes admission.Attributes, o admission.ObjectInterfaces) (err error) {
// Ignore all calls to subresources or resources other than pods.
if len(attributes.GetSubresource()) != 0 || attributes.GetResource().GroupResource() != api.Resource("pods") {
return nil
......
......@@ -199,7 +199,7 @@ func TestInterPodAffinityAdmission(t *testing.T) {
}
for _, test := range tests {
pod.Spec.Affinity = test.affinity
err := handler.Validate(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", false, nil))
err := handler.Validate(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", false, nil), nil)
if test.errorExpected && err == nil {
t.Errorf("Expected error for Anti Affinity %+v but did not get an error", test.affinity)
......@@ -267,7 +267,7 @@ func TestOtherResources(t *testing.T) {
for _, tc := range tests {
handler := &Plugin{}
err := handler.Validate(admission.NewAttributesRecord(tc.object, nil, api.Kind(tc.kind).WithVersion("version"), namespace, name, api.Resource(tc.resource).WithVersion("version"), tc.subresource, admission.Create, false, nil))
err := handler.Validate(admission.NewAttributesRecord(tc.object, nil, api.Kind(tc.kind).WithVersion("version"), namespace, name, api.Resource(tc.resource).WithVersion("version"), tc.subresource, admission.Create, false, nil), nil)
if tc.expectError {
if err == nil {
......
......@@ -81,7 +81,7 @@ func NewDefaultTolerationSeconds() *Plugin {
}
// Admit makes an admission decision based on the request attributes
func (p *Plugin) Admit(attributes admission.Attributes) (err error) {
func (p *Plugin) Admit(attributes admission.Attributes, o admission.ObjectInterfaces) (err error) {
if attributes.GetResource().GroupResource() != api.Resource("pods") {
return nil
}
......
......@@ -263,7 +263,7 @@ func TestForgivenessAdmission(t *testing.T) {
}
for _, test := range tests {
err := handler.Admit(admission.NewAttributesRecord(&test.requestedPod, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", false, nil))
err := handler.Admit(admission.NewAttributesRecord(&test.requestedPod, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", false, nil), nil)
if err != nil {
t.Errorf("[%s]: unexpected error %v for pod %+v", test.description, err, test.requestedPod)
}
......
......@@ -42,12 +42,12 @@ var _ admission.MutationInterface = alwaysDeny{}
var _ admission.ValidationInterface = alwaysDeny{}
// Admit makes an admission decision based on the request attributes.
func (alwaysDeny) Admit(a admission.Attributes) (err error) {
func (alwaysDeny) Admit(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
return admission.NewForbidden(a, errors.New("admission control is denying all modifications"))
}
// Validate makes an admission decision based on the request attributes. It is NOT allowed to mutate.
func (alwaysDeny) Validate(a admission.Attributes) (err error) {
func (alwaysDeny) Validate(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
return admission.NewForbidden(a, errors.New("admission control is denying all modifications"))
}
......
......@@ -25,7 +25,7 @@ import (
func TestAdmission(t *testing.T) {
handler := NewAlwaysDeny()
err := handler.(*alwaysDeny).Admit(admission.NewAttributesRecord(nil, nil, api.Kind("kind").WithVersion("version"), "namespace", "name", api.Resource("resource").WithVersion("version"), "subresource", admission.Create, false, nil))
err := handler.(*alwaysDeny).Admit(admission.NewAttributesRecord(nil, nil, api.Kind("kind").WithVersion("version"), "namespace", "name", api.Resource("resource").WithVersion("version"), "subresource", admission.Create, false, nil), nil)
if err == nil {
t.Error("Expected error returned from admission handler")
}
......
......@@ -81,7 +81,7 @@ func newEventRateLimit(config *eventratelimitapi.Configuration, clock flowcontro
}
// Validate makes admission decisions while enforcing event rate limits
func (a *Plugin) Validate(attr admission.Attributes) (err error) {
func (a *Plugin) Validate(attr admission.Attributes, o admission.ObjectInterfaces) (err error) {
// ignore all operations that do not correspond to an Event kind
if attr.GetKind().GroupKind() != api.Kind("Event") {
return nil
......
......@@ -504,7 +504,7 @@ func TestEventRateLimiting(t *testing.T) {
clock.Step(rq.delay)
}
attributes := attributesForRequest(rq)
err = eventratelimit.Validate(attributes)
err = eventratelimit.Validate(attributes, nil)
if rq.accepted != (err == nil) {
expectedAction := "admitted"
if !rq.accepted {
......
......@@ -111,7 +111,7 @@ func (d *DenyExec) ValidateInitialization() error {
}
// Validate makes an admission decision based on the request attributes
func (d *DenyExec) Validate(a admission.Attributes) (err error) {
func (d *DenyExec) Validate(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
path := a.GetResource().Resource
if subresource := a.GetSubresource(); subresource != "" {
path = path + "/" + subresource
......
......@@ -120,7 +120,7 @@ func testAdmission(t *testing.T, pod *corev1.Pod, handler *DenyExec, shouldAccep
// pods/exec
{
err := handler.Validate(admission.NewAttributesRecord(nil, nil, api.Kind("Pod").WithVersion("version"), "test", pod.Name, api.Resource("pods").WithVersion("version"), "exec", admission.Connect, false, nil))
err := handler.Validate(admission.NewAttributesRecord(nil, nil, api.Kind("Pod").WithVersion("version"), "test", pod.Name, api.Resource("pods").WithVersion("version"), "exec", admission.Connect, false, nil), nil)
if shouldAccept && err != nil {
t.Errorf("Unexpected error returned from admission handler: %v", err)
}
......@@ -131,7 +131,7 @@ func testAdmission(t *testing.T, pod *corev1.Pod, handler *DenyExec, shouldAccep
// pods/attach
{
err := handler.Validate(admission.NewAttributesRecord(nil, nil, api.Kind("Pod").WithVersion("version"), "test", pod.Name, api.Resource("pods").WithVersion("version"), "attach", admission.Connect, false, nil))
err := handler.Validate(admission.NewAttributesRecord(nil, nil, api.Kind("Pod").WithVersion("version"), "test", pod.Name, api.Resource("pods").WithVersion("version"), "attach", admission.Connect, false, nil), nil)
if shouldAccept && err != nil {
t.Errorf("Unexpected error returned from admission handler: %v", err)
}
......
......@@ -56,7 +56,7 @@ type plugin struct {
// a toleration with key "example.com/device", operator "Exists" and effect "NoSchedule".
// The rationale for this is described in:
// https://github.com/kubernetes/kubernetes/issues/55080
func (p *plugin) Admit(attributes admission.Attributes) error {
func (p *plugin) Admit(attributes admission.Attributes, o admission.ObjectInterfaces) error {
// Ignore all calls to subresources or resources other than pods.
if len(attributes.GetSubresource()) != 0 || attributes.GetResource().GroupResource() != core.Resource("pods") {
return nil
......
......@@ -354,7 +354,7 @@ func TestAdmit(t *testing.T) {
},
}
for i, test := range tests {
err := plugin.Admit(admission.NewAttributesRecord(&test.requestedPod, nil, core.Kind("Pod").WithVersion("version"), "foo", "name", core.Resource("pods").WithVersion("version"), "", "ignored", false, nil))
err := plugin.Admit(admission.NewAttributesRecord(&test.requestedPod, nil, core.Kind("Pod").WithVersion("version"), "foo", "name", core.Resource("pods").WithVersion("version"), "", "ignored", false, nil), nil)
if err != nil {
t.Errorf("[%d: %s] unexpected error %v for pod %+v", i, test.description, err, test.requestedPod)
}
......
......@@ -84,7 +84,7 @@ func (a *gcPermissionsEnforcement) isWhiteListed(groupResource schema.GroupResou
return false
}
func (a *gcPermissionsEnforcement) Validate(attributes admission.Attributes) (err error) {
func (a *gcPermissionsEnforcement) Validate(attributes admission.Attributes, o admission.ObjectInterfaces) (err error) {
// // if the request is in the whitelist, we skip mutation checks for this resource.
if a.isWhiteListed(attributes.GetResource().GroupResource(), attributes.GetSubresource()) {
return nil
......
......@@ -100,7 +100,7 @@ func newGCPermissionsEnforcement() (*gcPermissionsEnforcement, error) {
whiteList: whiteList,
}
genericPluginInitializer := initializer.New(nil, nil, fakeAuthorizer{}, nil)
genericPluginInitializer := initializer.New(nil, nil, fakeAuthorizer{})
fakeDiscoveryClient := &fakediscovery.FakeDiscovery{Fake: &coretesting.Fake{}}
fakeDiscoveryClient.Resources = []*metav1.APIResourceList{
{
......@@ -308,7 +308,7 @@ func TestGCAdmission(t *testing.T) {
user := &user.DefaultInfo{Name: tc.username}
attributes := admission.NewAttributesRecord(tc.newObj, tc.oldObj, schema.GroupVersionKind{}, metav1.NamespaceDefault, "foo", tc.resource, tc.subresource, operation, false, user)
err = gcAdmit.Validate(attributes)
err = gcAdmit.Validate(attributes, nil)
if !tc.checkError(err) {
t.Errorf("unexpected err: %v", err)
}
......@@ -611,7 +611,7 @@ func TestBlockOwnerDeletionAdmission(t *testing.T) {
user := &user.DefaultInfo{Name: tc.username}
attributes := admission.NewAttributesRecord(tc.newObj, tc.oldObj, schema.GroupVersionKind{}, metav1.NamespaceDefault, "foo", tc.resource, tc.subresource, operation, false, user)
err := gcAdmit.Validate(attributes)
err := gcAdmit.Validate(attributes, nil)
if !tc.checkError(err) {
t.Errorf("%v: unexpected err: %v", tc.name, err)
}
......
......@@ -131,7 +131,7 @@ func (a *Plugin) webhookError(pod *api.Pod, attributes admission.Attributes, err
}
// Validate makes an admission decision based on the request attributes
func (a *Plugin) Validate(attributes admission.Attributes) (err error) {
func (a *Plugin) Validate(attributes admission.Attributes, o admission.ObjectInterfaces) (err error) {
// Ignore all calls to subresources or resources other than pods.
if attributes.GetSubresource() != "" || attributes.GetResource().GroupResource() != api.Resource("pods") {
return nil
......
......@@ -487,7 +487,7 @@ func TestTLSConfig(t *testing.T) {
// Allow all and see if we get an error.
service.Allow()
err = wh.Validate(attr)
err = wh.Validate(attr, nil)
if tt.wantAllowed {
if err != nil {
t.Errorf("expected successful admission")
......@@ -509,7 +509,7 @@ func TestTLSConfig(t *testing.T) {
}
service.Deny()
if err := wh.Validate(attr); err == nil {
if err := wh.Validate(attr, nil); err == nil {
t.Errorf("%s: incorrectly admitted with DenyAll policy", tt.test)
}
})
......@@ -526,7 +526,7 @@ type webhookCacheTestCase struct {
func testWebhookCacheCases(t *testing.T, serv *mockService, wh *Plugin, attr admission.Attributes, tests []webhookCacheTestCase) {
for _, test := range tests {
serv.statusCode = test.statusCode
err := wh.Validate(attr)
err := wh.Validate(attr, nil)
authorized := err == nil
if test.expectedErr && err == nil {
......@@ -759,7 +759,7 @@ func TestContainerCombinations(t *testing.T) {
attr := admission.NewAttributesRecord(tt.pod, nil, api.Kind("Pod").WithVersion("version"), "namespace", "", api.Resource("pods").WithVersion("version"), "", admission.Create, false, &user.DefaultInfo{})
err = wh.Validate(attr)
err = wh.Validate(attr, nil)
if tt.wantAllowed {
if err != nil {
t.Errorf("expected successful admission: %s", tt.test)
......@@ -855,7 +855,7 @@ func TestDefaultAllow(t *testing.T) {
annotations := make(map[string]string)
attr = &fakeAttributes{attr, annotations}
err = wh.Validate(attr)
err = wh.Validate(attr, nil)
if tt.wantAllowed {
if err != nil {
t.Errorf("expected successful admission")
......@@ -963,7 +963,7 @@ func TestAnnotationFiltering(t *testing.T) {
attr := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "namespace", "", api.Resource("pods").WithVersion("version"), "", admission.Create, false, &user.DefaultInfo{})
err = wh.Validate(attr)
err = wh.Validate(attr, nil)
if err != nil {
t.Errorf("expected successful admission")
}
......@@ -1055,7 +1055,7 @@ func TestReturnedAnnotationAdd(t *testing.T) {
annotations := make(map[string]string)
attr = &fakeAttributes{attr, annotations}
err = wh.Validate(attr)
err = wh.Validate(attr, nil)
if !reflect.DeepEqual(annotations, tt.expectedAnnotations) {
t.Errorf("got audit annotations: %v; want: %v", annotations, tt.expectedAnnotations)
}
......
......@@ -99,12 +99,12 @@ func (l *LimitRanger) ValidateInitialization() error {
}
// Admit admits resources into cluster that do not violate any defined LimitRange in the namespace
func (l *LimitRanger) Admit(a admission.Attributes) (err error) {
func (l *LimitRanger) Admit(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
return l.runLimitFunc(a, l.actions.MutateLimit)
}
// Validate admits resources into cluster that do not violate any defined LimitRange in the namespace
func (l *LimitRanger) Validate(a admission.Attributes) (err error) {
func (l *LimitRanger) Validate(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
return l.runLimitFunc(a, l.actions.ValidateLimit)
}
......
......@@ -705,20 +705,20 @@ func TestLimitRangerIgnoresSubresource(t *testing.T) {
informerFactory.Start(wait.NeverStop)
testPod := validPod("testPod", 1, api.ResourceRequirements{})
err = handler.Admit(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil))
err = handler.Admit(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil), nil)
if err != nil {
t.Fatal(err)
}
err = handler.Validate(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil))
err = handler.Validate(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil), nil)
if err == nil {
t.Errorf("Expected an error since the pod did not specify resource limits in its create call")
}
err = handler.Validate(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Update, false, nil))
err = handler.Validate(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Update, false, nil), nil)
if err != nil {
t.Errorf("Expected not to call limitranger actions on pod updates")
}
err = handler.Validate(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "status", admission.Update, false, nil))
err = handler.Validate(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "status", admission.Update, false, nil), nil)
if err != nil {
t.Errorf("Should have ignored calls to any subresource of pod %v", err)
}
......@@ -735,20 +735,20 @@ func TestLimitRangerAdmitPod(t *testing.T) {
informerFactory.Start(wait.NeverStop)
testPod := validPod("testPod", 1, api.ResourceRequirements{})
err = handler.Admit(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil))
err = handler.Admit(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil), nil)
if err != nil {
t.Fatal(err)
}
err = handler.Validate(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil))
err = handler.Validate(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil), nil)
if err == nil {
t.Errorf("Expected an error since the pod did not specify resource limits in its create call")
}
err = handler.Validate(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Update, false, nil))
err = handler.Validate(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Update, false, nil), nil)
if err != nil {
t.Errorf("Expected not to call limitranger actions on pod updates")
}
err = handler.Validate(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "status", admission.Update, false, nil))
err = handler.Validate(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "status", admission.Update, false, nil), nil)
if err != nil {
t.Errorf("Should have ignored calls to any subresource of pod %v", err)
}
......@@ -757,7 +757,7 @@ func TestLimitRangerAdmitPod(t *testing.T) {
terminatingPod := validPod("terminatingPod", 1, api.ResourceRequirements{})
now := metav1.Now()
terminatingPod.DeletionTimestamp = &now
err = handler.Validate(admission.NewAttributesRecord(&terminatingPod, &terminatingPod, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "terminatingPod", api.Resource("pods").WithVersion("version"), "", admission.Update, false, nil))
err = handler.Validate(admission.NewAttributesRecord(&terminatingPod, &terminatingPod, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "terminatingPod", api.Resource("pods").WithVersion("version"), "", admission.Update, false, nil), nil)
if err != nil {
t.Errorf("LimitRange should ignore a pod marked for termination")
}
......@@ -788,7 +788,7 @@ func newHandlerForTest(c clientset.Interface) (*LimitRanger, informers.SharedInf
if err != nil {
return nil, f, err
}
pluginInitializer := genericadmissioninitializer.New(c, f, nil, nil)
pluginInitializer := genericadmissioninitializer.New(c, f, nil)
pluginInitializer.Initialize(handler)
err = admission.ValidateInitialization(handler)
return handler, f, err
......
......@@ -55,7 +55,7 @@ var _ = genericadmissioninitializer.WantsExternalKubeInformerFactory(&Provision{
var _ = genericadmissioninitializer.WantsExternalKubeClientSet(&Provision{})
// Admit makes an admission decision based on the request attributes
func (p *Provision) Admit(a admission.Attributes) error {
func (p *Provision) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
// Don't create a namespace if the request is for a dry-run.
if a.IsDryRun() {
return nil
......
......@@ -39,7 +39,7 @@ import (
func newHandlerForTest(c clientset.Interface) (admission.MutationInterface, informers.SharedInformerFactory, error) {
f := informers.NewSharedInformerFactory(c, 5*time.Minute)
handler := NewProvision()
pluginInitializer := genericadmissioninitializer.New(c, f, nil, nil)
pluginInitializer := genericadmissioninitializer.New(c, f, nil)
pluginInitializer.Initialize(handler)
err := admission.ValidateInitialization(handler)
return handler, f, err
......@@ -99,7 +99,7 @@ func TestAdmission(t *testing.T) {
informerFactory.Start(wait.NeverStop)
pod := newPod(namespace)
err = handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil))
err = handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil), nil)
if err != nil {
t.Errorf("unexpected error returned from admission handler")
}
......@@ -119,7 +119,7 @@ func TestAdmissionNamespaceExists(t *testing.T) {
informerFactory.Start(wait.NeverStop)
pod := newPod(namespace)
err = handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil))
err = handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil), nil)
if err != nil {
t.Errorf("unexpected error returned from admission handler")
}
......@@ -139,7 +139,7 @@ func TestAdmissionDryRun(t *testing.T) {
informerFactory.Start(wait.NeverStop)
pod := newPod(namespace)
err = handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, true, nil))
err = handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, true, nil), nil)
if err != nil {
t.Errorf("unexpected error returned from admission handler")
}
......@@ -160,7 +160,7 @@ func TestIgnoreAdmission(t *testing.T) {
chainHandler := admission.NewChainHandler(handler)
pod := newPod(namespace)
err = chainHandler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Update, false, nil))
err = chainHandler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Update, false, nil), nil)
if err != nil {
t.Errorf("unexpected error returned from admission handler")
}
......@@ -182,7 +182,7 @@ func TestAdmissionWithLatentCache(t *testing.T) {
informerFactory.Start(wait.NeverStop)
pod := newPod(namespace)
err = handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil))
err = handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil), nil)
if err != nil {
t.Errorf("unexpected error returned from admission handler")
}
......
......@@ -54,7 +54,7 @@ var _ = genericadmissioninitializer.WantsExternalKubeInformerFactory(&Exists{})
var _ = genericadmissioninitializer.WantsExternalKubeClientSet(&Exists{})
// Validate makes an admission decision based on the request attributes
func (e *Exists) Validate(a admission.Attributes) error {
func (e *Exists) Validate(a admission.Attributes, o admission.ObjectInterfaces) 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 the API server has found a route, which means that if we have a non-empty namespace
// its a namespaced resource.
......
......@@ -38,7 +38,7 @@ import (
func newHandlerForTest(c kubernetes.Interface) (admission.ValidationInterface, informers.SharedInformerFactory, error) {
f := informers.NewSharedInformerFactory(c, 5*time.Minute)
handler := NewExists()
pluginInitializer := genericadmissioninitializer.New(c, f, nil, nil)
pluginInitializer := genericadmissioninitializer.New(c, f, nil)
pluginInitializer.Initialize(handler)
err := admission.ValidateInitialization(handler)
return handler, f, err
......@@ -88,7 +88,7 @@ func TestAdmissionNamespaceExists(t *testing.T) {
informerFactory.Start(wait.NeverStop)
pod := newPod(namespace)
err = handler.Validate(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil))
err = handler.Validate(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil), nil)
if err != nil {
t.Errorf("unexpected error returned from admission handler")
}
......@@ -108,7 +108,7 @@ func TestAdmissionNamespaceDoesNotExist(t *testing.T) {
informerFactory.Start(wait.NeverStop)
pod := newPod(namespace)
err = handler.Validate(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil))
err = handler.Validate(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil), nil)
if err == nil {
actions := ""
for _, action := range mockClient.Actions() {
......
......@@ -102,7 +102,7 @@ var (
csiNodeInfoResource = csiv1alpha1.Resource("csinodeinfos")
)
func (c *nodePlugin) Admit(a admission.Attributes) error {
func (c *nodePlugin) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
nodeName, isNode := c.nodeIdentifier.NodeIdentity(a.GetUserInfo())
// Our job is just to restrict nodes
......
......@@ -1234,7 +1234,7 @@ func Test_nodePlugin_Admit(t *testing.T) {
c.features = tt.features
}
c.podsGetter = tt.podsGetter
err := c.Admit(tt.attributes)
err := c.Admit(tt.attributes, nil)
if (err == nil) != (len(tt.err) == 0) {
t.Errorf("nodePlugin.Admit() error = %v, expected %v", err, tt.err)
return
......
......@@ -64,7 +64,7 @@ var (
)
// Admit is the main function that checks node identity and adds taints as needed.
func (p *Plugin) Admit(a admission.Attributes) error {
func (p *Plugin) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
// If TaintNodesByCondition is not enabled, we don't need to do anything.
if !p.features.Enabled(features.TaintNodesByCondition) {
return nil
......
......@@ -100,7 +100,7 @@ func Test_nodeTaints(t *testing.T) {
if tt.features != nil {
c.features = tt.features
}
err := c.Admit(attributes)
err := c.Admit(attributes, nil)
if err != nil {
t.Errorf("nodePlugin.Admit() error = %v", err)
}
......
......@@ -94,7 +94,7 @@ func readConfig(config io.Reader) *pluginConfig {
}
// Admit enforces that pod and its namespace node label selectors matches at least a node in the cluster.
func (p *podNodeSelector) Admit(a admission.Attributes) error {
func (p *podNodeSelector) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
if shouldIgnore(a) {
return nil
}
......@@ -117,11 +117,11 @@ func (p *podNodeSelector) Admit(a admission.Attributes) error {
// second selector wins
podNodeSelectorLabels := labels.Merge(namespaceNodeSelector, pod.Spec.NodeSelector)
pod.Spec.NodeSelector = map[string]string(podNodeSelectorLabels)
return p.Validate(a)
return p.Validate(a, o)
}
// Validate ensures that the pod node selector is allowed
func (p *podNodeSelector) Validate(a admission.Attributes) error {
func (p *podNodeSelector) Validate(a admission.Attributes, o admission.ObjectInterfaces) error {
if shouldIgnore(a) {
return nil
}
......
......@@ -161,7 +161,7 @@ func TestPodAdmission(t *testing.T) {
handler.clusterNodeSelectors[namespace.Name] = test.whitelist
pod.Spec = api.PodSpec{NodeSelector: test.podNodeSelector}
err := handler.Admit(admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "testNamespace", namespace.ObjectMeta.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil))
err := handler.Admit(admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "testNamespace", namespace.ObjectMeta.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil), nil)
if test.admit && err != nil {
t.Errorf("Test: %s, expected no error but got: %s", test.testName, err)
} else if !test.admit && err == nil {
......@@ -170,7 +170,7 @@ func TestPodAdmission(t *testing.T) {
if test.admit && !labels.Equals(test.mergedNodeSelector, labels.Set(pod.Spec.NodeSelector)) {
t.Errorf("Test: %s, expected: %s but got: %s", test.testName, test.mergedNodeSelector, pod.Spec.NodeSelector)
}
err = handler.Validate(admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "testNamespace", namespace.ObjectMeta.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil))
err = handler.Validate(admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "testNamespace", namespace.ObjectMeta.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil), nil)
if test.admit && err != nil {
t.Errorf("Test: %s, expected no error but got: %s", test.testName, err)
} else if !test.admit && err == nil {
......@@ -197,7 +197,7 @@ func TestHandles(t *testing.T) {
func newHandlerForTest(c kubernetes.Interface) (*podNodeSelector, informers.SharedInformerFactory, error) {
f := informers.NewSharedInformerFactory(c, 5*time.Minute)
handler := NewPodNodeSelector(nil)
pluginInitializer := genericadmissioninitializer.New(c, f, nil, nil)
pluginInitializer := genericadmissioninitializer.New(c, f, nil)
pluginInitializer.Initialize(handler)
err := admission.ValidateInitialization(handler)
return handler, f, err
......
......@@ -90,7 +90,7 @@ func (a *podPresetPlugin) SetExternalKubeInformerFactory(f informers.SharedInfor
}
// Admit injects a pod with the specific fields for each pod preset it matches.
func (c *podPresetPlugin) Admit(a admission.Attributes) error {
func (c *podPresetPlugin) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
// Ignore all calls to subresources or resources other than pods.
// Ignore all operations other than CREATE.
if len(a.GetSubresource()) != 0 || a.GetResource().GroupResource() != api.Resource("pods") || a.GetOperation() != admission.Create {
......
......@@ -823,7 +823,7 @@ func admitPod(pod *api.Pod, pip *settingsv1alpha1.PodPreset) error {
&user.DefaultInfo{},
)
err := plugin.Admit(attrs)
err := plugin.Admit(attrs, nil)
if err != nil {
return err
}
......
......@@ -81,7 +81,7 @@ type podTolerationsPlugin struct {
// instead if specified. Tolerations to a namespace are assigned via
// scheduler.alpha.kubernetes.io/defaultTolerations and scheduler.alpha.kubernetes.io/tolerationsWhitelist
// annotations keys.
func (p *podTolerationsPlugin) Admit(a admission.Attributes) error {
func (p *podTolerationsPlugin) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
if shouldIgnore(a) {
return nil
}
......@@ -134,9 +134,9 @@ func (p *podTolerationsPlugin) Admit(a admission.Attributes) error {
}
pod.Spec.Tolerations = finalTolerations
return p.Validate(a)
return p.Validate(a, o)
}
func (p *podTolerationsPlugin) Validate(a admission.Attributes) error {
func (p *podTolerationsPlugin) Validate(a admission.Attributes, o admission.ObjectInterfaces) error {
if shouldIgnore(a) {
return nil
}
......
......@@ -254,7 +254,7 @@ func TestPodAdmission(t *testing.T) {
pod := test.pod
pod.Spec.Tolerations = test.podTolerations
err = handler.Admit(admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "testNamespace", namespace.ObjectMeta.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil))
err = handler.Admit(admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "testNamespace", namespace.ObjectMeta.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, false, nil), nil)
if test.admit && err != nil {
t.Errorf("Test: %s, expected no error but got: %s", test.testName, err)
} else if !test.admit && err == nil {
......@@ -331,7 +331,7 @@ func TestIgnoreUpdatingInitializedPod(t *testing.T) {
}
// if the update of initialized pod is not ignored, an error will be returned because the pod's Tolerations conflicts with namespace's Tolerations.
err = handler.Admit(admission.NewAttributesRecord(pod, pod, api.Kind("Pod").WithVersion("version"), "testNamespace", pod.ObjectMeta.Name, api.Resource("pods").WithVersion("version"), "", admission.Update, false, nil))
err = handler.Admit(admission.NewAttributesRecord(pod, pod, api.Kind("Pod").WithVersion("version"), "testNamespace", pod.ObjectMeta.Name, api.Resource("pods").WithVersion("version"), "", admission.Update, false, nil), nil)
if err != nil {
t.Errorf("expected no error, got: %v", err)
}
......@@ -346,7 +346,7 @@ func newHandlerForTest(c kubernetes.Interface) (*podTolerationsPlugin, informers
return nil, nil, err
}
handler := NewPodTolerationsPlugin(pluginConfig)
pluginInitializer := genericadmissioninitializer.New(c, f, nil, nil)
pluginInitializer := genericadmissioninitializer.New(c, f, nil)
pluginInitializer.Initialize(handler)
err = admission.ValidateInitialization(handler)
return handler, f, err
......
......@@ -97,7 +97,7 @@ var (
// Admit checks Pods and admits or rejects them. It also resolves the priority of pods based on their PriorityClass.
// Note that pod validation mechanism prevents update of a pod priority.
func (p *priorityPlugin) Admit(a admission.Attributes) error {
func (p *priorityPlugin) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
if !utilfeature.DefaultFeatureGate.Enabled(features.PodPriority) {
return nil
}
......@@ -121,7 +121,7 @@ func (p *priorityPlugin) Admit(a admission.Attributes) error {
}
// Validate checks PriorityClasses and admits or rejects them.
func (p *priorityPlugin) Validate(a admission.Attributes) error {
func (p *priorityPlugin) Validate(a admission.Attributes, o admission.ObjectInterfaces) error {
operation := a.GetOperation()
// Ignore all calls to subresources
if len(a.GetSubresource()) != 0 {
......
......@@ -158,7 +158,7 @@ func TestPriorityClassAdmission(t *testing.T) {
false,
test.userInfo,
)
err := ctrl.Validate(attrs)
err := ctrl.Validate(attrs, nil)
klog.Infof("Got %v", err)
if err != nil && !test.expectError {
t.Errorf("Test %q: unexpected error received: %v", test.name, err)
......@@ -254,7 +254,7 @@ func TestDefaultPriority(t *testing.T) {
test.name, test.expectedDefaultNameBefore, test.expectedDefaultBefore, pcName, defaultPriority)
}
if test.attributes != nil {
err := ctrl.Validate(test.attributes)
err := ctrl.Validate(test.attributes, nil)
if err != nil {
t.Errorf("Test %q: unexpected error received: %v", test.name, err)
}
......@@ -603,7 +603,7 @@ func TestPodAdmission(t *testing.T) {
false,
nil,
)
err := ctrl.Admit(attrs)
err := ctrl.Admit(attrs, nil)
klog.Infof("Got %v", err)
if !test.expectError {
if err != nil {
......
......@@ -127,7 +127,7 @@ func (a *QuotaAdmission) ValidateInitialization() error {
}
// Validate makes admission decisions while enforcing quota
func (a *QuotaAdmission) Validate(attr admission.Attributes) (err error) {
func (a *QuotaAdmission) Validate(attr admission.Attributes, o admission.ObjectInterfaces) (err error) {
// ignore all operations that correspond to sub-resource actions
if attr.GetSubresource() != "" {
return nil
......
......@@ -109,7 +109,7 @@ func (a *PodSecurityPolicyPlugin) SetExternalKubeInformerFactory(f informers.Sha
// 3. Try to generate and validate a PSP with providers. If we find one then admit the pod
// with the validated PSP. If we don't find any reject the pod and give all errors from the
// failed attempts.
func (c *PodSecurityPolicyPlugin) Admit(a admission.Attributes) error {
func (c *PodSecurityPolicyPlugin) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
if ignore, err := shouldIgnore(a); err != nil {
return err
} else if ignore {
......@@ -149,7 +149,7 @@ func (c *PodSecurityPolicyPlugin) Admit(a admission.Attributes) error {
return admission.NewForbidden(a, fmt.Errorf("unable to validate against any pod security policy: %v", validationErrs))
}
func (c *PodSecurityPolicyPlugin) Validate(a admission.Attributes) error {
func (c *PodSecurityPolicyPlugin) Validate(a admission.Attributes, o admission.ObjectInterfaces) error {
if ignore, err := shouldIgnore(a); err != nil {
return err
} else if ignore {
......
......@@ -475,7 +475,7 @@ func TestFailClosedOnInvalidPod(t *testing.T) {
pod := &v1.Pod{}
attrs := kadmission.NewAttributesRecord(pod, nil, kapi.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, kapi.Resource("pods").WithVersion("version"), "", kadmission.Create, false, &user.DefaultInfo{})
err := plugin.Admit(attrs)
err := plugin.Admit(attrs, nil)
if err == nil {
t.Fatalf("expected versioned pod object to fail mutating admission")
}
......@@ -483,7 +483,7 @@ func TestFailClosedOnInvalidPod(t *testing.T) {
t.Errorf("expected type error on Admit but got: %v", err)
}
err = plugin.Validate(attrs)
err = plugin.Validate(attrs, nil)
if err == nil {
t.Fatalf("expected versioned pod object to fail validating admission")
}
......@@ -1779,7 +1779,7 @@ func testPSPAdmitAdvanced(testCaseName string, op kadmission.Operation, psps []*
attrs := kadmission.NewAttributesRecord(pod, oldPod, kapi.Kind("Pod").WithVersion("version"), pod.Namespace, "", kapi.Resource("pods").WithVersion("version"), "", op, false, userInfo)
annotations := make(map[string]string)
attrs = &fakeAttributes{attrs, annotations}
err := plugin.Admit(attrs)
err := plugin.Admit(attrs, nil)
if shouldPassAdmit && err != nil {
t.Errorf("%s: expected no errors on Admit but received %v", testCaseName, err)
......@@ -1807,7 +1807,7 @@ func testPSPAdmitAdvanced(testCaseName string, op kadmission.Operation, psps []*
t.Errorf("%s: expected errors on Admit but received none", testCaseName)
}
err = plugin.Validate(attrs)
err = plugin.Validate(attrs, nil)
psp := ""
if shouldPassAdmit && op == kadmission.Create {
psp = expectedPSP
......
......@@ -50,7 +50,7 @@ func NewSecurityContextDeny() *Plugin {
}
// Validate will deny any pod that defines SupplementalGroups, SELinuxOptions, RunAsUser or FSGroup
func (p *Plugin) Validate(a admission.Attributes) (err error) {
func (p *Plugin) Validate(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
if a.GetSubresource() != "" || a.GetResource().GroupResource() != api.Resource("pods") {
return nil
}
......
......@@ -82,7 +82,7 @@ func TestAdmission(t *testing.T) {
p.Spec.SecurityContext = tc.podSc
p.Spec.Containers[0].SecurityContext = tc.sc
err := handler.Validate(admission.NewAttributesRecord(p, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", false, nil))
err := handler.Validate(admission.NewAttributesRecord(p, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", false, nil), nil)
if err != nil && !tc.expectError {
t.Errorf("%v: unexpected error: %v", tc.name, err)
} else if err == nil && tc.expectError {
......@@ -96,7 +96,7 @@ func TestAdmission(t *testing.T) {
p.Spec.InitContainers = p.Spec.Containers
p.Spec.Containers = nil
err = handler.Validate(admission.NewAttributesRecord(p, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", false, nil))
err = handler.Validate(admission.NewAttributesRecord(p, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", false, nil), nil)
if err != nil && !tc.expectError {
t.Errorf("%v: unexpected error: %v", tc.name, err)
} else if err == nil && tc.expectError {
......@@ -140,7 +140,7 @@ func TestPodSecurityContextAdmission(t *testing.T) {
}
for _, test := range tests {
pod.Spec.SecurityContext = &test.securityContext
err := handler.Validate(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", false, nil))
err := handler.Validate(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", false, nil), nil)
if test.errorExpected && err == nil {
t.Errorf("Expected error for security context %+v but did not get an error", test.securityContext)
......
......@@ -148,7 +148,7 @@ func (a *serviceAccount) ValidateInitialization() error {
return nil
}
func (s *serviceAccount) Admit(a admission.Attributes) (err error) {
func (s *serviceAccount) Admit(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
if shouldIgnore(a) {
return nil
}
......@@ -159,7 +159,7 @@ func (s *serviceAccount) Admit(a admission.Attributes) (err error) {
// That makes the kubelet very angry and confused, and it immediately deletes the pod (because the spec doesn't match)
// That said, don't allow mirror pods to reference ServiceAccounts or SecretVolumeSources either
if _, isMirrorPod := pod.Annotations[api.MirrorPodAnnotationKey]; isMirrorPod {
return s.Validate(a)
return s.Validate(a, o)
}
// Set the default service account if needed
......@@ -186,10 +186,10 @@ func (s *serviceAccount) Admit(a admission.Attributes) (err error) {
}
}
return s.Validate(a)
return s.Validate(a, o)
}
func (s *serviceAccount) Validate(a admission.Attributes) (err error) {
func (s *serviceAccount) Validate(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
if shouldIgnore(a) {
return nil
}
......
......@@ -97,7 +97,7 @@ func nodeSelectorRequirementKeysExistInNodeSelectorTerms(reqs []api.NodeSelector
return false
}
func (l *persistentVolumeLabel) Admit(a admission.Attributes) (err error) {
func (l *persistentVolumeLabel) Admit(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
if a.GetResource().GroupResource() != api.Resource("persistentvolumes") {
return nil
}
......
......@@ -756,7 +756,7 @@ func Test_PVLAdmission(t *testing.T) {
setPVLabeler(testcase.handler, testcase.pvlabeler)
handler := admission.NewChainHandler(testcase.handler)
err := handler.Admit(admission.NewAttributesRecord(testcase.preAdmissionPV, nil, api.Kind("PersistentVolume").WithVersion("version"), testcase.preAdmissionPV.Namespace, testcase.preAdmissionPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, false, nil))
err := handler.Admit(admission.NewAttributesRecord(testcase.preAdmissionPV, nil, api.Kind("PersistentVolume").WithVersion("version"), testcase.preAdmissionPV.Namespace, testcase.preAdmissionPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, false, nil), nil)
if !reflect.DeepEqual(err, testcase.err) {
t.Logf("expected error: %q", testcase.err)
t.Logf("actual error: %q", err)
......
......@@ -71,7 +71,7 @@ func (pvcr *persistentVolumeClaimResize) ValidateInitialization() error {
return nil
}
func (pvcr *persistentVolumeClaimResize) Validate(a admission.Attributes) error {
func (pvcr *persistentVolumeClaimResize) Validate(a admission.Attributes, o admission.ObjectInterfaces) error {
if a.GetResource().GroupResource() != api.Resource("persistentvolumeclaims") {
return nil
}
......
......@@ -256,7 +256,7 @@ func TestPVCResizeAdmission(t *testing.T) {
operation := admission.Update
attributes := admission.NewAttributesRecord(tc.newObj, tc.oldObj, schema.GroupVersionKind{}, metav1.NamespaceDefault, "foo", tc.resource, tc.subresource, operation, false, nil)
err := ctrl.Validate(attributes)
err := ctrl.Validate(attributes, nil)
if !tc.checkError(err) {
t.Errorf("%v: unexpected err: %v", tc.name, err)
}
......
......@@ -85,7 +85,7 @@ func (a *claimDefaulterPlugin) ValidateInitialization() error {
// 1. Find available StorageClasses.
// 2. Figure which is the default
// 3. Write to the PVClaim
func (a *claimDefaulterPlugin) Admit(attr admission.Attributes) error {
func (a *claimDefaulterPlugin) Admit(attr admission.Attributes, o admission.ObjectInterfaces) error {
if attr.GetResource().GroupResource() != api.Resource("persistentvolumeclaims") {
return nil
}
......
......@@ -211,7 +211,7 @@ func TestAdmission(t *testing.T) {
false, // dryRun
nil, // userInfo
)
err := ctrl.Admit(attrs)
err := ctrl.Admit(attrs, nil)
klog.Infof("Got %v", err)
if err != nil && !test.expectError {
t.Errorf("Test %q: unexpected error received: %v", test.name, err)
......
......@@ -65,7 +65,7 @@ var (
//
// This prevents users from deleting a PVC that's used by a running pod.
// This also prevents admin from deleting a PV that's bound by a PVC
func (c *storageProtectionPlugin) Admit(a admission.Attributes) error {
func (c *storageProtectionPlugin) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
if !feature.DefaultFeatureGate.Enabled(features.StorageObjectInUseProtection) {
return nil
}
......
......@@ -135,7 +135,7 @@ func TestAdmit(t *testing.T) {
nil, // userInfo
)
err := ctrl.Admit(attrs)
err := ctrl.Admit(attrs, nil)
if err != nil {
t.Errorf("Test %q: got unexpected error: %v", test.name, err)
}
......
......@@ -91,7 +91,7 @@ func (o CustomResourceDefinitionsServerOptions) Config() (*apiserver.Config, err
}
serverConfig := genericapiserver.NewRecommendedConfig(apiserver.Codecs)
if err := o.RecommendedOptions.ApplyTo(serverConfig, apiserver.Scheme); err != nil {
if err := o.RecommendedOptions.ApplyTo(serverConfig); err != nil {
return nil, err
}
if err := o.APIEnablement.ApplyTo(&serverConfig.Config, apiserver.DefaultAPIResourceConfigSource(), apiserver.Scheme); err != nil {
......
......@@ -42,6 +42,7 @@ go_library(
"handler.go",
"interfaces.go",
"plugins.go",
"util.go",
],
importmap = "k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/admission",
importpath = "k8s.io/apiserver/pkg/admission",
......
......@@ -44,7 +44,7 @@ func WithAudit(i Interface, ae *auditinternal.Event) Interface {
return &auditHandler{i, ae}
}
func (handler auditHandler) Admit(a Attributes) error {
func (handler auditHandler) Admit(a Attributes, o ObjectInterfaces) error {
if !handler.Interface.Handles(a.GetOperation()) {
return nil
}
......@@ -53,13 +53,13 @@ func (handler auditHandler) Admit(a Attributes) error {
}
var err error
if mutator, ok := handler.Interface.(MutationInterface); ok {
err = mutator.Admit(a)
err = mutator.Admit(a, o)
handler.logAnnotations(a)
}
return err
}
func (handler auditHandler) Validate(a Attributes) error {
func (handler auditHandler) Validate(a Attributes, o ObjectInterfaces) error {
if !handler.Interface.Handles(a.GetOperation()) {
return nil
}
......@@ -68,7 +68,7 @@ func (handler auditHandler) Validate(a Attributes) error {
}
var err error
if validator, ok := handler.Interface.(ValidationInterface); ok {
err = validator.Validate(a)
err = validator.Validate(a, o)
handler.logAnnotations(a)
}
return err
......
......@@ -45,14 +45,14 @@ var _ Interface = &fakeHandler{}
var _ MutationInterface = &fakeHandler{}
var _ ValidationInterface = &fakeHandler{}
func (h fakeHandler) Admit(a Attributes) error {
func (h fakeHandler) Admit(a Attributes, o ObjectInterfaces) error {
for k, v := range h.admitAnnotations {
a.AddAnnotation(k, v)
}
return h.admit
}
func (h fakeHandler) Validate(a Attributes) error {
func (h fakeHandler) Validate(a Attributes, o ObjectInterfaces) error {
for k, v := range h.validateAnnotations {
a.AddAnnotation(k, v)
}
......@@ -149,13 +149,13 @@ func TestWithAudit(t *testing.T) {
require.True(t, ok)
auditMutator, ok := auditHandler.(MutationInterface)
require.True(t, ok)
assert.Equal(t, mutator.Admit(a), auditMutator.Admit(a), tcName+": WithAudit decorator should not effect the return value")
assert.Equal(t, mutator.Admit(a, nil), auditMutator.Admit(a, nil), tcName+": WithAudit decorator should not effect the return value")
validator, ok := handler.(ValidationInterface)
require.True(t, ok)
auditValidator, ok := auditHandler.(ValidationInterface)
require.True(t, ok)
assert.Equal(t, validator.Validate(a), auditValidator.Validate(a), tcName+": WithAudit decorator should not effect the return value")
assert.Equal(t, validator.Validate(a, nil), auditValidator.Validate(a, nil), tcName+": WithAudit decorator should not effect the return value")
annotations := make(map[string]string, len(tc.admitAnnotations)+len(tc.validateAnnotations))
for k, v := range tc.admitAnnotations {
......
......@@ -26,13 +26,13 @@ func NewChainHandler(handlers ...Interface) chainAdmissionHandler {
}
// Admit performs an admission control check using a chain of handlers, and returns immediately on first error
func (admissionHandler chainAdmissionHandler) Admit(a Attributes) error {
func (admissionHandler chainAdmissionHandler) Admit(a Attributes, o ObjectInterfaces) error {
for _, handler := range admissionHandler {
if !handler.Handles(a.GetOperation()) {
continue
}
if mutator, ok := handler.(MutationInterface); ok {
err := mutator.Admit(a)
err := mutator.Admit(a, o)
if err != nil {
return err
}
......@@ -42,13 +42,13 @@ func (admissionHandler chainAdmissionHandler) Admit(a Attributes) error {
}
// Validate performs an admission control check using a chain of handlers, and returns immediately on first error
func (admissionHandler chainAdmissionHandler) Validate(a Attributes) error {
func (admissionHandler chainAdmissionHandler) Validate(a Attributes, o ObjectInterfaces) error {
for _, handler := range admissionHandler {
if !handler.Handles(a.GetOperation()) {
continue
}
if validator, ok := handler.(ValidationInterface); ok {
err := validator.Validate(a)
err := validator.Validate(a, o)
if err != nil {
return err
}
......
......@@ -31,7 +31,7 @@ type FakeHandler struct {
validate, validateCalled bool
}
func (h *FakeHandler) Admit(a Attributes) (err error) {
func (h *FakeHandler) Admit(a Attributes, o ObjectInterfaces) (err error) {
h.admitCalled = true
if h.admit {
return nil
......@@ -39,7 +39,7 @@ func (h *FakeHandler) Admit(a Attributes) (err error) {
return fmt.Errorf("Don't admit")
}
func (h *FakeHandler) Validate(a Attributes) (err error) {
func (h *FakeHandler) Validate(a Attributes, o ObjectInterfaces) (err error) {
h.validateCalled = true
if h.validate {
return nil
......@@ -119,7 +119,7 @@ func TestAdmitAndValidate(t *testing.T) {
for _, test := range tests {
t.Logf("testcase = %s", test.name)
// call admit and check that validate was not called at all
err := test.chain.Admit(NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, false, nil))
err := test.chain.Admit(NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, false, nil), nil)
accepted := (err == nil)
if accepted != test.accept {
t.Errorf("unexpected result of admit call: %v", accepted)
......@@ -140,7 +140,7 @@ func TestAdmitAndValidate(t *testing.T) {
}
// call validate and check that admit was not called at all
err = test.chain.Validate(NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, false, nil))
err = test.chain.Validate(NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, false, nil), nil)
accepted = (err == nil)
if accepted != test.accept {
t.Errorf("unexpected result of validate call: %v\n", accepted)
......
......@@ -15,7 +15,6 @@ go_library(
importmap = "k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/admission/initializer",
importpath = "k8s.io/apiserver/pkg/admission/initializer",
deps = [
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/admission:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library",
"//staging/src/k8s.io/client-go/informers:go_default_library",
......@@ -28,7 +27,6 @@ go_test(
srcs = ["initializer_test.go"],
embed = [":go_default_library"],
deps = [
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/admission:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library",
"//staging/src/k8s.io/client-go/informers:go_default_library",
......
......@@ -17,7 +17,6 @@ limitations under the License.
package initializer
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/client-go/informers"
......@@ -28,7 +27,6 @@ type pluginInitializer struct {
externalClient kubernetes.Interface
externalInformers informers.SharedInformerFactory
authorizer authorizer.Authorizer
scheme *runtime.Scheme
}
// New creates an instance of admission plugins initializer.
......@@ -37,13 +35,11 @@ func New(
extClientset kubernetes.Interface,
extInformers informers.SharedInformerFactory,
authz authorizer.Authorizer,
scheme *runtime.Scheme,
) pluginInitializer {
return pluginInitializer{
externalClient: extClientset,
externalInformers: extInformers,
authorizer: authz,
scheme: scheme,
}
}
......@@ -61,10 +57,6 @@ func (i pluginInitializer) Initialize(plugin admission.Interface) {
if wants, ok := plugin.(WantsAuthorizer); ok {
wants.SetAuthorizer(i.authorizer)
}
if wants, ok := plugin.(WantsScheme); ok {
wants.SetScheme(i.scheme)
}
}
var _ admission.PluginInitializer = pluginInitializer{}
......@@ -20,7 +20,6 @@ import (
"testing"
"time"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/admission/initializer"
"k8s.io/apiserver/pkg/authorization/authorizer"
......@@ -29,22 +28,10 @@ import (
"k8s.io/client-go/kubernetes/fake"
)
// TestWantsScheme ensures that the scheme is injected when
// the WantsScheme interface is implemented by a plugin.
func TestWantsScheme(t *testing.T) {
scheme := runtime.NewScheme()
target := initializer.New(nil, nil, nil, scheme)
wantSchemeAdmission := &WantSchemeAdmission{}
target.Initialize(wantSchemeAdmission)
if wantSchemeAdmission.scheme != scheme {
t.Errorf("expected scheme to be initialized")
}
}
// TestWantsAuthorizer ensures that the authorizer is injected
// when the WantsAuthorizer interface is implemented by a plugin.
func TestWantsAuthorizer(t *testing.T) {
target := initializer.New(nil, nil, &TestAuthorizer{}, nil)
target := initializer.New(nil, nil, &TestAuthorizer{})
wantAuthorizerAdmission := &WantAuthorizerAdmission{}
target.Initialize(wantAuthorizerAdmission)
if wantAuthorizerAdmission.auth == nil {
......@@ -56,7 +43,7 @@ func TestWantsAuthorizer(t *testing.T) {
// when the WantsExternalKubeClientSet interface is implemented by a plugin.
func TestWantsExternalKubeClientSet(t *testing.T) {
cs := &fake.Clientset{}
target := initializer.New(cs, nil, &TestAuthorizer{}, nil)
target := initializer.New(cs, nil, &TestAuthorizer{})
wantExternalKubeClientSet := &WantExternalKubeClientSet{}
target.Initialize(wantExternalKubeClientSet)
if wantExternalKubeClientSet.cs != cs {
......@@ -69,7 +56,7 @@ func TestWantsExternalKubeClientSet(t *testing.T) {
func TestWantsExternalKubeInformerFactory(t *testing.T) {
cs := &fake.Clientset{}
sf := informers.NewSharedInformerFactory(cs, time.Duration(1)*time.Second)
target := initializer.New(cs, sf, &TestAuthorizer{}, nil)
target := initializer.New(cs, sf, &TestAuthorizer{})
wantExternalKubeInformerFactory := &WantExternalKubeInformerFactory{}
target.Initialize(wantExternalKubeInformerFactory)
if wantExternalKubeInformerFactory.sf != sf {
......@@ -85,7 +72,9 @@ type WantExternalKubeInformerFactory struct {
func (self *WantExternalKubeInformerFactory) SetExternalKubeInformerFactory(sf informers.SharedInformerFactory) {
self.sf = sf
}
func (self *WantExternalKubeInformerFactory) Admit(a admission.Attributes) error { return nil }
func (self *WantExternalKubeInformerFactory) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
return nil
}
func (self *WantExternalKubeInformerFactory) Handles(o admission.Operation) bool { return false }
func (self *WantExternalKubeInformerFactory) ValidateInitialization() error { return nil }
......@@ -98,9 +87,11 @@ type WantExternalKubeClientSet struct {
}
func (self *WantExternalKubeClientSet) SetExternalKubeClientSet(cs kubernetes.Interface) { self.cs = cs }
func (self *WantExternalKubeClientSet) Admit(a admission.Attributes) error { return nil }
func (self *WantExternalKubeClientSet) Handles(o admission.Operation) bool { return false }
func (self *WantExternalKubeClientSet) ValidateInitialization() error { return nil }
func (self *WantExternalKubeClientSet) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
return nil
}
func (self *WantExternalKubeClientSet) Handles(o admission.Operation) bool { return false }
func (self *WantExternalKubeClientSet) ValidateInitialization() error { return nil }
var _ admission.Interface = &WantExternalKubeClientSet{}
var _ initializer.WantsExternalKubeClientSet = &WantExternalKubeClientSet{}
......@@ -111,9 +102,11 @@ type WantAuthorizerAdmission struct {
}
func (self *WantAuthorizerAdmission) SetAuthorizer(a authorizer.Authorizer) { self.auth = a }
func (self *WantAuthorizerAdmission) Admit(a admission.Attributes) error { return nil }
func (self *WantAuthorizerAdmission) Handles(o admission.Operation) bool { return false }
func (self *WantAuthorizerAdmission) ValidateInitialization() error { return nil }
func (self *WantAuthorizerAdmission) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
return nil
}
func (self *WantAuthorizerAdmission) Handles(o admission.Operation) bool { return false }
func (self *WantAuthorizerAdmission) ValidateInitialization() error { return nil }
var _ admission.Interface = &WantAuthorizerAdmission{}
var _ initializer.WantsAuthorizer = &WantAuthorizerAdmission{}
......@@ -130,20 +123,9 @@ type clientCertWanter struct {
gotCert, gotKey []byte
}
func (s *clientCertWanter) SetClientCert(cert, key []byte) { s.gotCert, s.gotKey = cert, key }
func (s *clientCertWanter) Admit(a admission.Attributes) error { return nil }
func (s *clientCertWanter) SetClientCert(cert, key []byte) { s.gotCert, s.gotKey = cert, key }
func (s *clientCertWanter) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
return nil
}
func (s *clientCertWanter) Handles(o admission.Operation) bool { return false }
func (s *clientCertWanter) ValidateInitialization() error { return nil }
// WantSchemeAdmission is a test stub that fulfills the WantsScheme interface.
type WantSchemeAdmission struct {
scheme *runtime.Scheme
}
func (self *WantSchemeAdmission) SetScheme(s *runtime.Scheme) { self.scheme = s }
func (self *WantSchemeAdmission) Admit(a admission.Attributes) error { return nil }
func (self *WantSchemeAdmission) Handles(o admission.Operation) bool { return false }
func (self *WantSchemeAdmission) ValidateInitialization() error { return nil }
var _ admission.Interface = &WantSchemeAdmission{}
var _ initializer.WantsScheme = &WantSchemeAdmission{}
......@@ -17,7 +17,6 @@ limitations under the License.
package initializer
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/client-go/informers"
......@@ -41,9 +40,3 @@ type WantsAuthorizer interface {
SetAuthorizer(authorizer.Authorizer)
admission.InitializationValidator
}
// WantsScheme defines a function that accepts runtime.Scheme for admission plugins that need it.
type WantsScheme interface {
SetScheme(*runtime.Scheme)
admission.InitializationValidator
}
......@@ -62,6 +62,20 @@ type Attributes interface {
AddAnnotation(key, value string) error
}
// ObjectInterfaces is an interface used by AdmissionController to get object interfaces
// such as Converter or Defaulter. These interfaces are normally coming from Request Scope
// to handle special cases like CRDs.
type ObjectInterfaces interface {
// GetObjectCreater is the ObjectCreator appropriate for the requested object.
GetObjectCreater() runtime.ObjectCreater
// GetObjectTyper is the ObjectTyper appropriate for the requested object.
GetObjectTyper() runtime.ObjectTyper
// GetObjectDefaulter is the ObjectDefaulter appropriate for the requested object.
GetObjectDefaulter() runtime.ObjectDefaulter
// GetObjectConvertor is the ObjectConvertor appropriate for the requested object.
GetObjectConvertor() runtime.ObjectConvertor
}
// privateAnnotationsGetter is a private interface which allows users to get annotations from Attributes.
type privateAnnotationsGetter interface {
getAnnotations() map[string]string
......@@ -84,7 +98,7 @@ type MutationInterface interface {
Interface
// Admit makes an admission decision based on the request attributes
Admit(a Attributes) (err error)
Admit(a Attributes, o ObjectInterfaces) (err error)
}
// ValidationInterface is an abstract, pluggable interface for Admission Control decisions.
......@@ -92,7 +106,7 @@ type ValidationInterface interface {
Interface
// Validate makes an admission decision based on the request attributes. It is NOT allowed to mutate
Validate(a Attributes) (err error)
Validate(a Attributes, o ObjectInterfaces) (err error)
}
// Operation is the type of resource operation being checked for admission control
......
......@@ -75,27 +75,27 @@ type pluginHandlerWithMetrics struct {
}
// Admit performs a mutating admission control check and emit metrics.
func (p pluginHandlerWithMetrics) Admit(a admission.Attributes) error {
func (p pluginHandlerWithMetrics) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
mutatingHandler, ok := p.Interface.(admission.MutationInterface)
if !ok {
return nil
}
start := time.Now()
err := mutatingHandler.Admit(a)
err := mutatingHandler.Admit(a, o)
p.observer(time.Since(start), err != nil, a, stepAdmit, p.extraLabels...)
return err
}
// Validate performs a non-mutating admission control check and emits metrics.
func (p pluginHandlerWithMetrics) Validate(a admission.Attributes) error {
func (p pluginHandlerWithMetrics) Validate(a admission.Attributes, o admission.ObjectInterfaces) error {
validatingHandler, ok := p.Interface.(admission.ValidationInterface)
if !ok {
return nil
}
start := time.Now()
err := validatingHandler.Validate(a)
err := validatingHandler.Validate(a, o)
p.observer(time.Since(start), err != nil, a, stepValidate, p.extraLabels...)
return err
}
......
......@@ -34,8 +34,8 @@ var (
func TestObserveAdmissionStep(t *testing.T) {
Metrics.reset()
handler := WithStepMetrics(&mutatingAndValidatingFakeHandler{admission.NewHandler(admission.Create), true, true})
handler.(admission.MutationInterface).Admit(attr)
handler.(admission.ValidationInterface).Validate(attr)
handler.(admission.MutationInterface).Admit(attr, nil)
handler.(admission.ValidationInterface).Validate(attr, nil)
wantLabels := map[string]string{
"operation": string(admission.Create),
"type": "admit",
......@@ -52,8 +52,8 @@ func TestObserveAdmissionStep(t *testing.T) {
func TestObserveAdmissionController(t *testing.T) {
Metrics.reset()
handler := WithControllerMetrics(&mutatingAndValidatingFakeHandler{admission.NewHandler(admission.Create), true, true}, "a")
handler.(admission.MutationInterface).Admit(attr)
handler.(admission.ValidationInterface).Validate(attr)
handler.(admission.MutationInterface).Admit(attr, nil)
handler.(admission.ValidationInterface).Validate(attr, nil)
wantLabels := map[string]string{
"name": "a",
"operation": string(admission.Create),
......@@ -144,7 +144,7 @@ func TestWithMetrics(t *testing.T) {
h := WithMetrics(test.handler, Metrics.ObserveAdmissionController, test.name)
// test mutation
err := h.(admission.MutationInterface).Admit(admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, false, nil))
err := h.(admission.MutationInterface).Admit(admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, false, nil), nil)
if test.admit && err != nil {
t.Errorf("expected admit to succeed, but failed: %v", err)
continue
......@@ -169,7 +169,7 @@ func TestWithMetrics(t *testing.T) {
}
// test validation
err = h.(admission.ValidationInterface).Validate(admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, false, nil))
err = h.(admission.ValidationInterface).Validate(admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, false, nil), nil)
if test.validate && err != nil {
t.Errorf("expected admit to succeed, but failed: %v", err)
continue
......@@ -196,14 +196,14 @@ type mutatingAndValidatingFakeHandler struct {
validate bool
}
func (h *mutatingAndValidatingFakeHandler) Admit(a admission.Attributes) (err error) {
func (h *mutatingAndValidatingFakeHandler) Admit(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
if h.admit {
return nil
}
return fmt.Errorf("don't admit")
}
func (h *mutatingAndValidatingFakeHandler) Validate(a admission.Attributes) (err error) {
func (h *mutatingAndValidatingFakeHandler) Validate(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
if h.validate {
return nil
}
......@@ -215,7 +215,7 @@ type validatingFakeHandler struct {
validate bool
}
func (h *validatingFakeHandler) Validate(a admission.Attributes) (err error) {
func (h *validatingFakeHandler) Validate(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
if h.validate {
return nil
}
......@@ -227,7 +227,7 @@ type mutatingFakeHandler struct {
admit bool
}
func (h *mutatingFakeHandler) Admit(a admission.Attributes) (err error) {
func (h *mutatingFakeHandler) Admit(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
if h.admit {
return nil
}
......
......@@ -73,7 +73,7 @@ var _ = initializer.WantsExternalKubeInformerFactory(&Lifecycle{})
var _ = initializer.WantsExternalKubeClientSet(&Lifecycle{})
// Admit makes an admission decision based on the request attributes
func (l *Lifecycle) Admit(a admission.Attributes) error {
func (l *Lifecycle) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
// prevent deletion of immortal namespaces
if a.GetOperation() == admission.Delete && a.GetKind().GroupKind() == v1.SchemeGroupVersion.WithKind("Namespace").GroupKind() && l.immortalNamespaces.Has(a.GetName()) {
return errors.NewForbidden(a.GetResource().GroupResource(), a.GetName(), fmt.Errorf("this namespace may not be deleted"))
......
......@@ -50,6 +50,7 @@ go_test(
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/admission:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/apis/example:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/apis/example/v1:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/apis/example2/v1:go_default_library",
......
......@@ -17,39 +17,25 @@ limitations under the License.
package generic
import (
"fmt"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apiserver/pkg/admission"
)
// convertor converts objects to the desired version.
type convertor struct {
Scheme *runtime.Scheme
}
// ConvertToGVK converts object to the desired gvk.
func (c *convertor) ConvertToGVK(obj runtime.Object, gvk schema.GroupVersionKind) (runtime.Object, error) {
func ConvertToGVK(obj runtime.Object, gvk schema.GroupVersionKind, o admission.ObjectInterfaces) (runtime.Object, error) {
// Unlike other resources, custom resources do not have internal version, so
// if obj is a custom resource, it should not need conversion.
if obj.GetObjectKind().GroupVersionKind() == gvk {
return obj, nil
}
out, err := c.Scheme.New(gvk)
out, err := o.GetObjectCreater().New(gvk)
if err != nil {
return nil, err
}
err = c.Scheme.Convert(obj, out, nil)
err = o.GetObjectConvertor().Convert(obj, out, nil)
if err != nil {
return nil, err
}
return out, nil
}
// Validate checks if the conversion has a scheme.
func (c *convertor) Validate() error {
if c.Scheme == nil {
return fmt.Errorf("the convertor requires a scheme")
}
return nil
}
......@@ -26,6 +26,7 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/apis/example"
examplev1 "k8s.io/apiserver/pkg/apis/example/v1"
example2v1 "k8s.io/apiserver/pkg/apis/example2/v1"
......@@ -41,7 +42,7 @@ func initiateScheme(t *testing.T) *runtime.Scheme {
func TestConvertToGVK(t *testing.T) {
scheme := initiateScheme(t)
c := convertor{Scheme: scheme}
o := &admission.SchemeBasedObjectInterfaces{scheme}
table := map[string]struct {
obj runtime.Object
gvk schema.GroupVersionKind
......@@ -122,7 +123,7 @@ func TestConvertToGVK(t *testing.T) {
for name, test := range table {
t.Run(name, func(t *testing.T) {
actual, err := c.ConvertToGVK(test.obj, test.gvk)
actual, err := ConvertToGVK(test.obj, test.gvk, o)
if err != nil {
t.Error(err)
}
......
......@@ -41,5 +41,5 @@ type VersionedAttributes struct {
// Dispatcher dispatches webhook call to a list of webhooks with admission attributes as argument.
type Dispatcher interface {
// Dispatch a request to the webhooks using the given webhooks. A non-nil error means the request is rejected.
Dispatch(ctx context.Context, a *VersionedAttributes, hooks []*v1beta1.Webhook) error
Dispatch(ctx context.Context, a *VersionedAttributes, o admission.ObjectInterfaces, hooks []*v1beta1.Webhook) error
}
......@@ -24,7 +24,6 @@ import (
admissionv1beta1 "k8s.io/api/admission/v1beta1"
"k8s.io/api/admissionregistration/v1beta1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/admission"
genericadmissioninit "k8s.io/apiserver/pkg/admission/initializer"
"k8s.io/apiserver/pkg/admission/plugin/webhook/config"
......@@ -43,7 +42,6 @@ type Webhook struct {
hookSource Source
clientManager *webhook.ClientManager
convertor *convertor
namespaceMatcher *namespace.Matcher
dispatcher Dispatcher
}
......@@ -79,7 +77,6 @@ func NewWebhook(handler *admission.Handler, configFile io.Reader, sourceFactory
Handler: handler,
sourceFactory: sourceFactory,
clientManager: &cm,
convertor: &convertor{},
namespaceMatcher: &namespace.Matcher{},
dispatcher: dispatcherFactory(&cm),
}, nil
......@@ -98,13 +95,6 @@ func (a *Webhook) SetServiceResolver(sr webhook.ServiceResolver) {
a.clientManager.SetServiceResolver(sr)
}
// SetScheme sets a serializer(NegotiatedSerializer) which is derived from the scheme
func (a *Webhook) SetScheme(scheme *runtime.Scheme) {
if scheme != nil {
a.convertor.Scheme = scheme
}
}
// SetExternalKubeClientSet implements the WantsExternalKubeInformerFactory interface.
// It sets external ClientSet for admission plugins that need it
func (a *Webhook) SetExternalKubeClientSet(client clientset.Interface) {
......@@ -132,9 +122,6 @@ func (a *Webhook) ValidateInitialization() error {
if err := a.clientManager.Validate(); err != nil {
return fmt.Errorf("clientManager is not properly setup: %v", err)
}
if err := a.convertor.Validate(); err != nil {
return fmt.Errorf("convertor is not properly setup: %v", err)
}
return nil
}
......@@ -156,7 +143,7 @@ func (a *Webhook) ShouldCallHook(h *v1beta1.Webhook, attr admission.Attributes)
}
// Dispatch is called by the downstream Validate or Admit methods.
func (a *Webhook) Dispatch(attr admission.Attributes) error {
func (a *Webhook) Dispatch(attr admission.Attributes, o admission.ObjectInterfaces) error {
if rules.IsWebhookConfigurationResource(attr) {
return nil
}
......@@ -188,18 +175,18 @@ func (a *Webhook) Dispatch(attr admission.Attributes) error {
Attributes: attr,
}
if oldObj := attr.GetOldObject(); oldObj != nil {
out, err := a.convertor.ConvertToGVK(oldObj, attr.GetKind())
out, err := ConvertToGVK(oldObj, attr.GetKind(), o)
if err != nil {
return apierrors.NewInternalError(err)
}
versionedAttr.VersionedOldObject = out
}
if obj := attr.GetObject(); obj != nil {
out, err := a.convertor.ConvertToGVK(obj, attr.GetKind())
out, err := ConvertToGVK(obj, attr.GetKind(), o)
if err != nil {
return apierrors.NewInternalError(err)
}
versionedAttr.VersionedObject = out
}
return a.dispatcher.Dispatch(ctx, &versionedAttr, relevantHooks)
return a.dispatcher.Dispatch(ctx, &versionedAttr, o, relevantHooks)
}
......@@ -39,8 +39,6 @@ go_test(
],
embed = [":go_default_library"],
deps = [
"//staging/src/k8s.io/api/admission/v1beta1:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
......
......@@ -31,7 +31,9 @@ import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer/json"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apiserver/pkg/admission"
admissionmetrics "k8s.io/apiserver/pkg/admission/metrics"
webhookerrors "k8s.io/apiserver/pkg/admission/plugin/webhook/errors"
"k8s.io/apiserver/pkg/admission/plugin/webhook/generic"
......@@ -53,10 +55,10 @@ func newMutatingDispatcher(p *Plugin) func(cm *webhook.ClientManager) generic.Di
var _ generic.Dispatcher = &mutatingDispatcher{}
func (a *mutatingDispatcher) Dispatch(ctx context.Context, attr *generic.VersionedAttributes, relevantHooks []*v1beta1.Webhook) error {
func (a *mutatingDispatcher) Dispatch(ctx context.Context, attr *generic.VersionedAttributes, o admission.ObjectInterfaces, relevantHooks []*v1beta1.Webhook) error {
for _, hook := range relevantHooks {
t := time.Now()
err := a.callAttrMutatingHook(ctx, hook, attr)
err := a.callAttrMutatingHook(ctx, hook, attr, o)
admissionmetrics.Metrics.ObserveWebhook(time.Since(t), err != nil, attr.Attributes, "admit", hook.Name)
if err == nil {
continue
......@@ -76,13 +78,13 @@ func (a *mutatingDispatcher) Dispatch(ctx context.Context, attr *generic.Version
// convert attr.VersionedObject to the internal version in the underlying admission.Attributes
if attr.VersionedObject != nil {
return a.plugin.scheme.Convert(attr.VersionedObject, attr.Attributes.GetObject(), nil)
return o.GetObjectConvertor().Convert(attr.VersionedObject, attr.Attributes.GetObject(), nil)
}
return nil
}
// note that callAttrMutatingHook updates attr
func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, h *v1beta1.Webhook, attr *generic.VersionedAttributes) error {
func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, h *v1beta1.Webhook, attr *generic.VersionedAttributes, o admission.ObjectInterfaces) error {
if attr.IsDryRun() {
if h.SideEffects == nil {
return &webhook.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("Webhook SideEffects is nil")}
......@@ -135,7 +137,8 @@ func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, h *v1beta
return apierrors.NewInternalError(fmt.Errorf("admission webhook %q attempted to modify the object, which is not supported for this operation", h.Name))
}
objJS, err := runtime.Encode(a.plugin.jsonSerializer, attr.VersionedObject)
jsonSerializer := json.NewSerializer(json.DefaultMetaFactory, o.GetObjectCreater(), o.GetObjectTyper(), false)
objJS, err := runtime.Encode(jsonSerializer, attr.VersionedObject)
if err != nil {
return apierrors.NewInternalError(err)
}
......@@ -150,17 +153,17 @@ func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, h *v1beta
// They are represented as Unstructured.
newVersionedObject = &unstructured.Unstructured{}
} else {
newVersionedObject, err = a.plugin.scheme.New(attr.GetKind())
newVersionedObject, err = o.GetObjectCreater().New(attr.GetKind())
if err != nil {
return apierrors.NewInternalError(err)
}
}
// TODO: if we have multiple mutating webhooks, we can remember the json
// instead of encoding and decoding for each one.
if _, _, err := a.plugin.jsonSerializer.Decode(patchedJS, nil, newVersionedObject); err != nil {
if _, _, err := jsonSerializer.Decode(patchedJS, nil, newVersionedObject); err != nil {
return apierrors.NewInternalError(err)
}
attr.VersionedObject = newVersionedObject
a.plugin.scheme.Default(attr.VersionedObject)
o.GetObjectDefaulter().Default(attr.VersionedObject)
return nil
}
......@@ -49,6 +49,7 @@ func TestDispatch(t *testing.T) {
require.NoError(t, example.AddToScheme(scheme))
require.NoError(t, examplev1.AddToScheme(scheme))
require.NoError(t, example2v1.AddToScheme(scheme))
objectInterfaces := &admission.SchemeBasedObjectInterfaces{scheme}
tests := []struct {
name string
......@@ -118,16 +119,14 @@ func TestDispatch(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
a := &mutatingDispatcher{
plugin: &Plugin{
scheme: scheme,
},
plugin: &Plugin{},
}
attr := generic.VersionedAttributes{
Attributes: admission.NewAttributesRecord(test.out, nil, schema.GroupVersionKind{}, "", "", schema.GroupVersionResource{}, "", admission.Operation(""), false, nil),
VersionedOldObject: nil,
VersionedObject: test.in,
}
if err := a.Dispatch(context.TODO(), &attr, nil); err != nil {
if err := a.Dispatch(context.TODO(), &attr, objectInterfaces, nil); err != nil {
t.Fatalf("%s: unexpected error: %v", test.name, err)
}
if !reflect.DeepEqual(attr.Attributes.GetObject(), test.expectedObj) {
......
......@@ -17,11 +17,8 @@ limitations under the License.
package mutating
import (
"fmt"
"io"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer/json"
"k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/admission/configuration"
"k8s.io/apiserver/pkg/admission/plugin/webhook/generic"
......@@ -47,9 +44,6 @@ func Register(plugins *admission.Plugins) {
// Plugin is an implementation of admission.Interface.
type Plugin struct {
*generic.Webhook
scheme *runtime.Scheme
jsonSerializer *json.Serializer
}
var _ admission.MutationInterface = &Plugin{}
......@@ -67,30 +61,15 @@ func NewMutatingWebhook(configFile io.Reader) (*Plugin, error) {
return p, nil
}
// SetScheme sets a serializer(NegotiatedSerializer) which is derived from the scheme
func (a *Plugin) SetScheme(scheme *runtime.Scheme) {
a.Webhook.SetScheme(scheme)
if scheme != nil {
a.scheme = scheme
a.jsonSerializer = json.NewSerializer(json.DefaultMetaFactory, scheme, scheme, false)
}
}
// ValidateInitialization implements the InitializationValidator interface.
func (a *Plugin) ValidateInitialization() error {
if err := a.Webhook.ValidateInitialization(); err != nil {
return err
}
if a.scheme == nil {
return fmt.Errorf("scheme is not properly setup")
}
if a.jsonSerializer == nil {
return fmt.Errorf("jsonSerializer is not properly setup")
}
return nil
}
// Admit makes an admission decision based on the request attributes.
func (a *Plugin) Admit(attr admission.Attributes) error {
return a.Webhook.Dispatch(attr)
func (a *Plugin) Admit(attr admission.Attributes, o admission.ObjectInterfaces) error {
return a.Webhook.Dispatch(attr, o)
}
......@@ -23,23 +23,15 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"k8s.io/api/admission/v1beta1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/admission"
webhooktesting "k8s.io/apiserver/pkg/admission/plugin/webhook/testing"
)
// TestAdmit tests that MutatingWebhook#Admit works as expected
func TestAdmit(t *testing.T) {
scheme := runtime.NewScheme()
require.NoError(t, v1beta1.AddToScheme(scheme))
require.NoError(t, corev1.AddToScheme(scheme))
testServer := webhooktesting.NewTestServer(t)
testServer.StartTLS()
defer testServer.Close()
......@@ -48,6 +40,8 @@ func TestAdmit(t *testing.T) {
t.Fatalf("this should never happen? %v", err)
}
objectInterfaces := webhooktesting.NewObjectInterfacesForTest()
stopCh := make(chan struct{})
defer close(stopCh)
......@@ -66,7 +60,6 @@ func TestAdmit(t *testing.T) {
wh.SetAuthenticationInfoResolverWrapper(webhooktesting.Wrapper(webhooktesting.NewAuthenticationInfoResolver(new(int32))))
wh.SetServiceResolver(webhooktesting.NewServiceResolver(*serverURL))
wh.SetScheme(scheme)
wh.SetExternalKubeClientSet(client)
wh.SetExternalKubeInformerFactory(informer)
......@@ -85,7 +78,7 @@ func TestAdmit(t *testing.T) {
attr = webhooktesting.NewAttribute(ns, tt.AdditionalLabels, tt.IsDryRun)
}
err = wh.Admit(attr)
err = wh.Admit(attr, objectInterfaces)
if tt.ExpectAllow != (err == nil) {
t.Errorf("%s: expected allowed=%v, but got err=%v", tt.Name, tt.ExpectAllow, err)
}
......@@ -118,10 +111,6 @@ func TestAdmit(t *testing.T) {
// TestAdmitCachedClient tests that MutatingWebhook#Admit should cache restClient
func TestAdmitCachedClient(t *testing.T) {
scheme := runtime.NewScheme()
require.NoError(t, v1beta1.AddToScheme(scheme))
require.NoError(t, corev1.AddToScheme(scheme))
testServer := webhooktesting.NewTestServer(t)
testServer.StartTLS()
defer testServer.Close()
......@@ -130,6 +119,8 @@ func TestAdmitCachedClient(t *testing.T) {
t.Fatalf("this should never happen? %v", err)
}
objectInterfaces := webhooktesting.NewObjectInterfacesForTest()
stopCh := make(chan struct{})
defer close(stopCh)
......@@ -138,7 +129,6 @@ func TestAdmitCachedClient(t *testing.T) {
t.Fatalf("Failed to create mutating webhook: %v", err)
}
wh.SetServiceResolver(webhooktesting.NewServiceResolver(*serverURL))
wh.SetScheme(scheme)
for _, tt := range webhooktesting.NewCachedClientTestcases(serverURL) {
ns := "webhook-test"
......@@ -158,7 +148,7 @@ func TestAdmitCachedClient(t *testing.T) {
continue
}
err = wh.Admit(webhooktesting.NewAttribute(ns, nil, false))
err = wh.Admit(webhooktesting.NewAttribute(ns, nil, false), objectInterfaces)
if tt.ExpectAllow != (err == nil) {
t.Errorf("%s: expected allowed=%v, but got err=%v", tt.Name, tt.ExpectAllow, err)
}
......
......@@ -649,3 +649,10 @@ func newMatchEverythingRules() []registrationv1beta1.RuleWithOperations {
},
}}
}
// NewObjectInterfacesForTest returns an ObjectInterfaces appropriate for test cases in this file.
func NewObjectInterfacesForTest() admission.ObjectInterfaces {
scheme := runtime.NewScheme()
corev1.AddToScheme(scheme)
return &admission.SchemeBasedObjectInterfaces{scheme}
}
......@@ -32,13 +32,9 @@ go_test(
srcs = ["plugin_test.go"],
embed = [":go_default_library"],
deps = [
"//staging/src/k8s.io/api/admission/v1beta1:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/testing:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library",
"//vendor/github.com/stretchr/testify/require:go_default_library",
],
)
......
......@@ -28,6 +28,7 @@ import (
"k8s.io/api/admissionregistration/v1beta1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apiserver/pkg/admission"
admissionmetrics "k8s.io/apiserver/pkg/admission/metrics"
webhookerrors "k8s.io/apiserver/pkg/admission/plugin/webhook/errors"
"k8s.io/apiserver/pkg/admission/plugin/webhook/generic"
......@@ -46,7 +47,7 @@ func newValidatingDispatcher(cm *webhook.ClientManager) generic.Dispatcher {
var _ generic.Dispatcher = &validatingDispatcher{}
func (d *validatingDispatcher) Dispatch(ctx context.Context, attr *generic.VersionedAttributes, relevantHooks []*v1beta1.Webhook) error {
func (d *validatingDispatcher) Dispatch(ctx context.Context, attr *generic.VersionedAttributes, o admission.ObjectInterfaces, relevantHooks []*v1beta1.Webhook) error {
wg := sync.WaitGroup{}
errCh := make(chan error, len(relevantHooks))
wg.Add(len(relevantHooks))
......
......@@ -59,6 +59,6 @@ func NewValidatingAdmissionWebhook(configFile io.Reader) (*Plugin, error) {
}
// Validate makes an admission decision based on the request attributes.
func (a *Plugin) Validate(attr admission.Attributes) error {
return a.Webhook.Dispatch(attr)
func (a *Plugin) Validate(attr admission.Attributes, o admission.ObjectInterfaces) error {
return a.Webhook.Dispatch(attr, o)
}
......@@ -22,25 +22,19 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"k8s.io/api/admission/v1beta1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
webhooktesting "k8s.io/apiserver/pkg/admission/plugin/webhook/testing"
)
// TestValidate tests that ValidatingWebhook#Validate works as expected
func TestValidate(t *testing.T) {
scheme := runtime.NewScheme()
require.NoError(t, v1beta1.AddToScheme(scheme))
require.NoError(t, corev1.AddToScheme(scheme))
testServer := webhooktesting.NewTestServer(t)
testServer.StartTLS()
defer testServer.Close()
objectInterfaces := webhooktesting.NewObjectInterfacesForTest()
serverURL, err := url.ParseRequestURI(testServer.URL)
if err != nil {
t.Fatalf("this should never happen? %v", err)
......@@ -61,7 +55,6 @@ func TestValidate(t *testing.T) {
wh.SetAuthenticationInfoResolverWrapper(webhooktesting.Wrapper(webhooktesting.NewAuthenticationInfoResolver(new(int32))))
wh.SetServiceResolver(webhooktesting.NewServiceResolver(*serverURL))
wh.SetScheme(scheme)
wh.SetExternalKubeClientSet(client)
wh.SetExternalKubeInformerFactory(informer)
......@@ -74,7 +67,7 @@ func TestValidate(t *testing.T) {
}
attr := webhooktesting.NewAttribute(ns, nil, tt.IsDryRun)
err = wh.Validate(attr)
err = wh.Validate(attr, objectInterfaces)
if tt.ExpectAllow != (err == nil) {
t.Errorf("%s: expected allowed=%v, but got err=%v", tt.Name, tt.ExpectAllow, err)
}
......@@ -102,10 +95,6 @@ func TestValidate(t *testing.T) {
// TestValidateCachedClient tests that ValidatingWebhook#Validate should cache restClient
func TestValidateCachedClient(t *testing.T) {
scheme := runtime.NewScheme()
require.NoError(t, v1beta1.AddToScheme(scheme))
require.NoError(t, corev1.AddToScheme(scheme))
testServer := webhooktesting.NewTestServer(t)
testServer.StartTLS()
defer testServer.Close()
......@@ -114,6 +103,8 @@ func TestValidateCachedClient(t *testing.T) {
t.Fatalf("this should never happen? %v", err)
}
objectInterfaces := webhooktesting.NewObjectInterfacesForTest()
stopCh := make(chan struct{})
defer close(stopCh)
......@@ -122,7 +113,6 @@ func TestValidateCachedClient(t *testing.T) {
t.Fatalf("Failed to create validating webhook: %v", err)
}
wh.SetServiceResolver(webhooktesting.NewServiceResolver(*serverURL))
wh.SetScheme(scheme)
for _, tt := range webhooktesting.NewCachedClientTestcases(serverURL) {
ns := "webhook-test"
......@@ -142,7 +132,7 @@ func TestValidateCachedClient(t *testing.T) {
continue
}
err = wh.Validate(webhooktesting.NewAttribute(ns, nil, false))
err = wh.Validate(webhooktesting.NewAttribute(ns, nil, false), objectInterfaces)
if tt.ExpectAllow != (err == nil) {
t.Errorf("%s: expected allowed=%v, but got err=%v", tt.Name, tt.ExpectAllow, err)
}
......
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package admission
import "k8s.io/apimachinery/pkg/runtime"
type SchemeBasedObjectInterfaces struct {
Scheme *runtime.Scheme
}
func (r *SchemeBasedObjectInterfaces) GetObjectCreater() runtime.ObjectCreater { return r.Scheme }
func (r *SchemeBasedObjectInterfaces) GetObjectTyper() runtime.ObjectTyper { return r.Scheme }
func (r *SchemeBasedObjectInterfaces) GetObjectDefaulter() runtime.ObjectDefaulter { return r.Scheme }
func (r *SchemeBasedObjectInterfaces) GetObjectConvertor() runtime.ObjectConvertor { return r.Scheme }
......@@ -76,7 +76,7 @@ import (
type alwaysMutatingDeny struct{}
func (alwaysMutatingDeny) Admit(a admission.Attributes) (err error) {
func (alwaysMutatingDeny) Admit(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
return admission.NewForbidden(a, errors.New("Mutating admission control is denying all modifications"))
}
......@@ -86,7 +86,7 @@ func (alwaysMutatingDeny) Handles(operation admission.Operation) bool {
type alwaysValidatingDeny struct{}
func (alwaysValidatingDeny) Validate(a admission.Attributes) (err error) {
func (alwaysValidatingDeny) Validate(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
return admission.NewForbidden(a, errors.New("Validating admission control is denying all modifications"))
}
......
......@@ -127,7 +127,7 @@ func createHandler(r rest.NamedCreater, scope RequestScope, admit admission.Inte
userInfo, _ := request.UserFrom(ctx)
admissionAttributes := admission.NewAttributesRecord(obj, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, dryrun.IsDryRun(options.DryRun), userInfo)
if mutatingAdmission, ok := admit.(admission.MutationInterface); ok && mutatingAdmission.Handles(admission.Create) {
err = mutatingAdmission.Admit(admissionAttributes)
err = mutatingAdmission.Admit(admissionAttributes, &scope)
if err != nil {
scope.err(err, w, req)
return
......@@ -154,7 +154,7 @@ func createHandler(r rest.NamedCreater, scope RequestScope, admit admission.Inte
ctx,
name,
obj,
rest.AdmissionToValidateObjectFunc(admit, admissionAttributes),
rest.AdmissionToValidateObjectFunc(admit, admissionAttributes, &scope),
options,
)
})
......
......@@ -119,13 +119,13 @@ func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope RequestSco
userInfo, _ := request.UserFrom(ctx)
attrs := admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Delete, dryrun.IsDryRun(options.DryRun), userInfo)
if mutatingAdmission, ok := admit.(admission.MutationInterface); ok {
if err := mutatingAdmission.Admit(attrs); err != nil {
if err := mutatingAdmission.Admit(attrs, &scope); err != nil {
scope.err(err, w, req)
return
}
}
if validatingAdmission, ok := admit.(admission.ValidationInterface); ok {
if err := validatingAdmission.Validate(attrs); err != nil {
if err := validatingAdmission.Validate(attrs, &scope); err != nil {
scope.err(err, w, req)
return
}
......@@ -269,7 +269,7 @@ func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope RequestSco
userInfo, _ := request.UserFrom(ctx)
attrs := admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, "", scope.Resource, scope.Subresource, admission.Delete, dryrun.IsDryRun(options.DryRun), userInfo)
if mutatingAdmission, ok := admit.(admission.MutationInterface); ok {
err = mutatingAdmission.Admit(attrs)
err = mutatingAdmission.Admit(attrs, &scope)
if err != nil {
scope.err(err, w, req)
return
......@@ -277,7 +277,7 @@ func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope RequestSco
}
if validatingAdmission, ok := admit.(admission.ValidationInterface); ok {
err = validatingAdmission.Validate(attrs)
err = validatingAdmission.Validate(attrs, &scope)
if err != nil {
scope.err(err, w, req)
return
......
......@@ -191,10 +191,12 @@ func PatchResource(r rest.Patcher, scope RequestScope, admit admission.Interface
subresource: scope.Subresource,
dryRun: dryrun.IsDryRun(options.DryRun),
objectInterfaces: &scope,
hubGroupVersion: scope.HubGroupVersion,
createValidation: withAuthorization(rest.AdmissionToValidateObjectFunc(admit, staticCreateAttributes), scope.Authorizer, createAuthorizerAttributes),
updateValidation: rest.AdmissionToValidateObjectUpdateFunc(admit, staticUpdateAttributes),
createValidation: withAuthorization(rest.AdmissionToValidateObjectFunc(admit, staticCreateAttributes, &scope), scope.Authorizer, createAuthorizerAttributes),
updateValidation: rest.AdmissionToValidateObjectUpdateFunc(admit, staticUpdateAttributes, &scope),
admissionCheck: mutatingAdmission,
codec: codec,
......@@ -257,6 +259,8 @@ type patcher struct {
subresource string
dryRun bool
objectInterfaces admission.ObjectInterfaces
hubGroupVersion schema.GroupVersion
// Validation functions
......@@ -507,7 +511,7 @@ func (p *patcher) applyAdmission(ctx context.Context, patchedObject runtime.Obje
}
if p.admissionCheck != nil && p.admissionCheck.Handles(operation) {
attributes := p.admissionAttributes(ctx, patchedObject, currentObject, operation)
return patchedObject, p.admissionCheck.Admit(attributes)
return patchedObject, p.admissionCheck.Admit(attributes, p.objectInterfaces)
}
return patchedObject, nil
}
......
......@@ -103,6 +103,13 @@ func (scope *RequestScope) AllowsStreamSchema(s string) bool {
return s == "watch"
}
var _ admission.ObjectInterfaces = &RequestScope{}
func (r *RequestScope) GetObjectCreater() runtime.ObjectCreater { return r.Creater }
func (r *RequestScope) GetObjectTyper() runtime.ObjectTyper { return r.Typer }
func (r *RequestScope) GetObjectDefaulter() runtime.ObjectDefaulter { return r.Defaulter }
func (r *RequestScope) GetObjectConvertor() runtime.ObjectConvertor { return r.Convertor }
// ConnectResource returns a function that handles a connect request on a rest.Storage object.
func ConnectResource(connecter rest.Connecter, scope RequestScope, admit admission.Interface, restPath string, isSubresource bool) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
......@@ -131,14 +138,14 @@ func ConnectResource(connecter rest.Connecter, scope RequestScope, admit admissi
userInfo, _ := request.UserFrom(ctx)
// TODO: remove the mutating admission here as soon as we have ported all plugin that handle CONNECT
if mutatingAdmission, ok := admit.(admission.MutationInterface); ok {
err = mutatingAdmission.Admit(admission.NewAttributesRecord(opts, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, false, userInfo))
err = mutatingAdmission.Admit(admission.NewAttributesRecord(opts, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, false, userInfo), &scope)
if err != nil {
scope.err(err, w, req)
return
}
}
if validatingAdmission, ok := admit.(admission.ValidationInterface); ok {
err = validatingAdmission.Validate(admission.NewAttributesRecord(opts, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, false, userInfo))
err = validatingAdmission.Validate(admission.NewAttributesRecord(opts, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, false, userInfo), &scope)
if err != nil {
scope.err(err, w, req)
return
......
......@@ -365,6 +365,7 @@ func (tc *patchTestCase) Run(t *testing.T) {
creater := runtime.ObjectCreater(scheme)
defaulter := runtime.ObjectDefaulter(scheme)
convertor := runtime.UnsafeObjectConvertor(scheme)
objectInterfaces := &admission.SchemeBasedObjectInterfaces{scheme}
kind := examplev1.SchemeGroupVersion.WithKind("Pod")
resource := examplev1.SchemeGroupVersion.WithResource("pods")
schemaReferenceObj := &examplev1.Pod{}
......@@ -441,6 +442,8 @@ func (tc *patchTestCase) Run(t *testing.T) {
kind: kind,
resource: resource,
objectInterfaces: objectInterfaces,
hubGroupVersion: hubVersion,
createValidation: rest.ValidateAllObjectFunc,
......@@ -944,6 +947,6 @@ func (f mutateObjectUpdateFunc) Handles(operation admission.Operation) bool {
return true
}
func (f mutateObjectUpdateFunc) Admit(a admission.Attributes) (err error) {
func (f mutateObjectUpdateFunc) Admit(a admission.Attributes, o admission.ObjectInterfaces) (err error) {
return f(a.GetObject(), a.GetOldObject())
}
......@@ -138,11 +138,11 @@ func UpdateResource(r rest.Updater, scope RequestScope, admit admission.Interfac
return nil, fmt.Errorf("unexpected error when extracting UID from oldObj: %v", err.Error())
} else if !isNotZeroObject {
if mutatingAdmission.Handles(admission.Create) {
return newObj, mutatingAdmission.Admit(admission.NewAttributesRecord(newObj, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, dryrun.IsDryRun(options.DryRun), userInfo))
return newObj, mutatingAdmission.Admit(admission.NewAttributesRecord(newObj, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, dryrun.IsDryRun(options.DryRun), userInfo), &scope)
}
} else {
if mutatingAdmission.Handles(admission.Update) {
return newObj, mutatingAdmission.Admit(admission.NewAttributesRecord(newObj, oldObj, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, dryrun.IsDryRun(options.DryRun), userInfo))
return newObj, mutatingAdmission.Admit(admission.NewAttributesRecord(newObj, oldObj, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, dryrun.IsDryRun(options.DryRun), userInfo), &scope)
}
}
return newObj, nil
......@@ -172,11 +172,11 @@ func UpdateResource(r rest.Updater, scope RequestScope, admit admission.Interfac
rest.DefaultUpdatedObjectInfo(obj, transformers...),
withAuthorization(rest.AdmissionToValidateObjectFunc(
admit,
admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, dryrun.IsDryRun(options.DryRun), userInfo)),
admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, dryrun.IsDryRun(options.DryRun), userInfo), &scope),
scope.Authorizer, createAuthorizerAttributes),
rest.AdmissionToValidateObjectUpdateFunc(
admit,
admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, dryrun.IsDryRun(options.DryRun), userInfo)),
admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, dryrun.IsDryRun(options.DryRun), userInfo), &scope),
false,
options,
)
......
......@@ -160,7 +160,7 @@ type NamespaceScopedStrategy interface {
}
// AdmissionToValidateObjectFunc converts validating admission to a rest validate object func
func AdmissionToValidateObjectFunc(admit admission.Interface, staticAttributes admission.Attributes) ValidateObjectFunc {
func AdmissionToValidateObjectFunc(admit admission.Interface, staticAttributes admission.Attributes, o admission.ObjectInterfaces) ValidateObjectFunc {
validatingAdmission, ok := admit.(admission.ValidationInterface)
if !ok {
return func(obj runtime.Object) error { return nil }
......@@ -181,6 +181,6 @@ func AdmissionToValidateObjectFunc(admit admission.Interface, staticAttributes a
if !validatingAdmission.Handles(finalAttributes.GetOperation()) {
return nil
}
return validatingAdmission.Validate(finalAttributes)
return validatingAdmission.Validate(finalAttributes, o)
}
}
......@@ -256,7 +256,7 @@ func (i *wrappedUpdatedObjectInfo) UpdatedObject(ctx context.Context, oldObj run
}
// AdmissionToValidateObjectUpdateFunc converts validating admission to a rest validate object update func
func AdmissionToValidateObjectUpdateFunc(admit admission.Interface, staticAttributes admission.Attributes) ValidateObjectUpdateFunc {
func AdmissionToValidateObjectUpdateFunc(admit admission.Interface, staticAttributes admission.Attributes, o admission.ObjectInterfaces) ValidateObjectUpdateFunc {
validatingAdmission, ok := admit.(admission.ValidationInterface)
if !ok {
return func(obj, old runtime.Object) error { return nil }
......@@ -277,6 +277,6 @@ func AdmissionToValidateObjectUpdateFunc(admit admission.Interface, staticAttrib
if !validatingAdmission.Handles(finalAttributes.GetOperation()) {
return nil
}
return validatingAdmission.Validate(finalAttributes)
return validatingAdmission.Validate(finalAttributes, o)
}
}
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