Skip to content

Commit

Permalink
Adding e2e tests for new plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
Shawn Hurley committed Apr 25, 2022
1 parent 105943c commit e7c42ef
Show file tree
Hide file tree
Showing 8 changed files with 658 additions and 149 deletions.
4 changes: 2 additions & 2 deletions pkg/admission/mutatingwebhook/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,11 @@ func Register(plugins *admission.Plugins) {
}

func (a *Plugin) Admit(ctx context.Context, attr admission.Attributes, o admission.ObjectInterfaces) error {
return a.Dispatch(ctx, attr, o)
return a.WebhookDispatcher.Dispatch(ctx, attr, o)
}

// SetExternalKubeInformerFactory implements the WantsExternalKubeInformerFactory interface.
func (p *Plugin) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) {
p.WebhookDispatcher.SetExternalKubeInformerFactory(f)
p.WebhookDispatcher.SetHookSource(configuration.NewMutatingWebhookConfigurationManager(f))
p.Plugin.SetExternalKubeInformerFactory(f)
}
17 changes: 9 additions & 8 deletions pkg/admission/plugins.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle"
"k8s.io/apiserver/pkg/admission/plugin/resourcequota"
mutatingwebhook "k8s.io/apiserver/pkg/admission/plugin/webhook/mutating"
validatingwebhook "k8s.io/apiserver/pkg/admission/plugin/webhook/validating"
kubeapiserveroptions "k8s.io/kubernetes/pkg/kubeapiserver/options"
certapproval "k8s.io/kubernetes/plugin/pkg/admission/certificates/approval"
certsigning "k8s.io/kubernetes/plugin/pkg/admission/certificates/signing"
Expand Down Expand Up @@ -110,14 +111,14 @@ var defaultOnPluginsInKcp = sets.NewString(
// new plugins got added upstream and to react (enable or disable by default). We
// have a unit test in place to avoid drift.
var defaultOnKubePluginsInKube = sets.NewString(
lifecycle.PluginName, // NamespaceLifecycle
limitranger.PluginName, // LimitRanger
serviceaccount.PluginName, // ServiceAccount
setdefault.PluginName, // DefaultStorageClass
resize.PluginName, // PersistentVolumeClaimResize
defaulttolerationseconds.PluginName, // DefaultTolerationSeconds
//mutatingwebhook.PluginName, // MutatingAdmissionWebhook
//validatingwebhook.PluginName, // ValidatingAdmissionWebhook
lifecycle.PluginName, // NamespaceLifecycle
limitranger.PluginName, // LimitRanger
serviceaccount.PluginName, // ServiceAccount
setdefault.PluginName, // DefaultStorageClass
resize.PluginName, // PersistentVolumeClaimResize
defaulttolerationseconds.PluginName, // DefaultTolerationSeconds
mutatingwebhook.PluginName, // MutatingAdmissionWebhook
validatingwebhook.PluginName, // ValidatingAdmissionWebhook
resourcequota.PluginName, // ResourceQuota
storageobjectinuseprotection.PluginName, // StorageObjectInUseProtection
podpriority.PluginName, // PodPriority
Expand Down
2 changes: 1 addition & 1 deletion pkg/admission/validatingwebhook/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,6 @@ func (a *Plugin) Validate(ctx context.Context, attr admission.Attributes, o admi

// SetExternalKubeInformerFactory implements the WantsExternalKubeInformerFactory interface.
func (p *Plugin) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) {
p.WebhookDispatcher.SetExternalKubeInformerFactory(f)
p.WebhookDispatcher.SetHookSource(configuration.NewValidatingWebhookConfigurationManager(f))
p.Plugin.SetExternalKubeInformerFactory(f)
}
20 changes: 14 additions & 6 deletions pkg/admission/webhook/generic_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,10 @@ import (

"k8s.io/apimachinery/pkg/labels"
"k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/admission/configuration"
"k8s.io/apiserver/pkg/admission/plugin/webhook"
"k8s.io/apiserver/pkg/admission/plugin/webhook/generic"
"k8s.io/apiserver/pkg/admission/plugin/webhook/rules"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/client-go/informers"
)

type WebhookDispatcher struct {
Expand Down Expand Up @@ -70,7 +68,9 @@ func (p *WebhookDispatcher) Dispatch(ctx context.Context, attr admission.Attribu
// Determine the type of request, is it api binding or not.
if workspace, isAPIBinding := p.getAPIBindingWorkspace(attr, lcluster); isAPIBinding {
whAccessor = p.restrictToLogicalCluster(hooks, workspace)
fmt.Printf("\n\nworkspace: %v\nwhAccessor: %v\nhooks:%v", workspace, whAccessor, hooks)
} else {
fmt.Printf("here")
whAccessor = p.restrictToLogicalCluster(hooks, lcluster)
}

Expand All @@ -80,18 +80,27 @@ func (p *WebhookDispatcher) Dispatch(ctx context.Context, attr admission.Attribu
func (p *WebhookDispatcher) getAPIBindingWorkspace(attr admission.Attributes, lc logicalcluster.LogicalCluster) (logicalcluster.LogicalCluster, bool) {
l, err := p.apiBinding.List(labels.Everything())
if err != nil {
fmt.Printf("here1")
return logicalcluster.New(""), false
}
for _, apiBinding := range l {
if apiBinding.GetClusterName() != lc.String() {
fmt.Printf("apiBinding: %v lc: %v", apiBinding.GetClusterName(), lc.String())
continue
}
for _, br := range apiBinding.Status.BoundResources {
if br.Group == attr.GetResource().Group && br.Resource == attr.GetResource().Resource {
return logicalcluster.New(apiBinding.Status.BoundAPIExport.Workspace.WorkspaceName), true
p, hasParent := logicalcluster.From(apiBinding).Parent()
if !hasParent {
fmt.Printf("here3")
return logicalcluster.New(""), false
}
fmt.Printf("here4")
return p.Join(apiBinding.Status.BoundAPIExport.Workspace.WorkspaceName), true
}
}
}
fmt.Printf("here5")
return logicalcluster.New(""), false
}

Expand All @@ -107,9 +116,8 @@ func (p *WebhookDispatcher) restrictToLogicalCluster(hooks []webhook.WebhookAcce
return wh
}

// SetExternalKubeInformerFactory implements the WantsExternalKubeInformerFactory interface.
func (p *WebhookDispatcher) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) {
p.hookSource = configuration.NewValidatingWebhookConfigurationManager(f)
func (p *WebhookDispatcher) SetHookSource(s generic.Source) {
p.hookSource = s
}

// SetExternalKubeInformerFactory implements the WantsExternalKubeInformerFactory interface.
Expand Down
45 changes: 25 additions & 20 deletions pkg/admission/webhook/generic_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,18 +57,23 @@ type validatingDispatcher struct {
}

func (d *validatingDispatcher) Dispatch(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces, hooks []webhook.WebhookAccessor) error {
fmt.Printf("\nexpected: %v", d.hooks)
fmt.Printf("\ngot: %v", hooks)
if len(hooks) != len(d.hooks) {
return fmt.Errorf("invalid number of hooks sent to dispatcher")
}
uidMatches := map[string]*struct{}{}
for _, h := range hooks {
fmt.Printf("\n%v", h.GetUID())
for _, expectedHook := range d.hooks {
fmt.Printf("\n%v", expectedHook.GetUID())
if h.GetUID() == expectedHook.GetUID() {
uidMatches[h.GetUID()] = &struct{}{}
}
}
}
if len(uidMatches) != len(d.hooks) {
fmt.Printf("%#v", uidMatches)
return fmt.Errorf("hooks UID did not match expected")
}
return nil
Expand Down Expand Up @@ -127,18 +132,18 @@ func TestDispatch(t *testing.T) {
"cowboys",
admission.Create,
),
cluster: "dest-cluster",
cluster: "root:org:dest-cluster",
expectedHooks: []webhook.WebhookAccessor{
webhook.NewValidatingWebhookAccessor("1", "api-registration-hook", logicalcluster.New("source-cluster"), nil),
webhook.NewValidatingWebhookAccessor("1", "api-registration-hook", logicalcluster.New("root:org:source-cluster"), nil),
},
hooksInSource: []webhook.WebhookAccessor{
webhook.NewValidatingWebhookAccessor("1", "api-registration-hook", logicalcluster.New("source-cluster"), nil),
webhook.NewValidatingWebhookAccessor("2", "secrets", logicalcluster.New("dest-cluster"), nil),
webhook.NewValidatingWebhookAccessor("1", "api-registration-hook", logicalcluster.New("root:org:source-cluster"), nil),
webhook.NewValidatingWebhookAccessor("2", "secrets", logicalcluster.New("root:org:dest-cluster"), nil),
},
apiBindings: []*v1alpha1.APIBinding{
{
ObjectMeta: metav1.ObjectMeta{
ClusterName: "dest-cluster",
ClusterName: "root:org:dest-cluster",
},
Status: v1alpha1.APIBindingStatus{
BoundResources: []v1alpha1.BoundAPIResource{
Expand All @@ -164,14 +169,14 @@ func TestDispatch(t *testing.T) {
"cowboys",
admission.Create,
),
cluster: "dest-cluster",
cluster: "root:org:dest-cluster",
expectedHooks: []webhook.WebhookAccessor{
webhook.NewValidatingWebhookAccessor("3", "secrets", logicalcluster.New("dest-cluster"), nil),
webhook.NewValidatingWebhookAccessor("3", "secrets", logicalcluster.New("root:org:dest-cluster"), nil),
},
hooksInSource: []webhook.WebhookAccessor{
webhook.NewValidatingWebhookAccessor("1", "cowboy-hook", logicalcluster.New("source-cluster"), nil),
webhook.NewValidatingWebhookAccessor("2", "secrets", logicalcluster.New("source-cluster"), nil),
webhook.NewValidatingWebhookAccessor("3", "secrets", logicalcluster.New("dest-cluster"), nil),
webhook.NewValidatingWebhookAccessor("1", "cowboy-hook", logicalcluster.New("root:org:source-cluster"), nil),
webhook.NewValidatingWebhookAccessor("2", "secrets", logicalcluster.New("root:org:source-cluster"), nil),
webhook.NewValidatingWebhookAccessor("3", "secrets", logicalcluster.New("root:org:dest-cluster"), nil),
},
},
{
Expand All @@ -182,19 +187,19 @@ func TestDispatch(t *testing.T) {
"cowboys",
admission.Create,
),
cluster: "dest-cluster",
cluster: "root:org:dest-cluster",
expectedHooks: []webhook.WebhookAccessor{
webhook.NewValidatingWebhookAccessor("3", "secrets", logicalcluster.New("dest-cluster"), nil),
webhook.NewValidatingWebhookAccessor("3", "secrets", logicalcluster.New("root:org:dest-cluster"), nil),
},
hooksInSource: []webhook.WebhookAccessor{
webhook.NewValidatingWebhookAccessor("1", "cowboy-hook", logicalcluster.New("source-cluster"), nil),
webhook.NewValidatingWebhookAccessor("2", "secrets", logicalcluster.New("source-cluster"), nil),
webhook.NewValidatingWebhookAccessor("3", "secrets", logicalcluster.New("dest-cluster"), nil),
webhook.NewValidatingWebhookAccessor("1", "cowboy-hook", logicalcluster.New("root:org:source-cluster"), nil),
webhook.NewValidatingWebhookAccessor("2", "secrets", logicalcluster.New("root:org:source-cluster"), nil),
webhook.NewValidatingWebhookAccessor("3", "secrets", logicalcluster.New("root:org:dest-cluster"), nil),
},
apiBindings: []*v1alpha1.APIBinding{
{
ObjectMeta: metav1.ObjectMeta{
ClusterName: "dest-cluster",
ClusterName: "root:org:dest-cluster",
},
Status: v1alpha1.APIBindingStatus{
BoundResources: []v1alpha1.BoundAPIResource{
Expand All @@ -212,7 +217,7 @@ func TestDispatch(t *testing.T) {
},
{
ObjectMeta: metav1.ObjectMeta{
ClusterName: "dest-cluster-2",
ClusterName: "root:org:dest-cluster-2",
},
Status: v1alpha1.APIBindingStatus{
BoundResources: []v1alpha1.BoundAPIResource{
Expand All @@ -238,7 +243,7 @@ func TestDispatch(t *testing.T) {
"cowboys",
admission.Create,
),
cluster: "dest-cluster",
cluster: "root:org:dest-cluster",
apiBindingsSynced: func() bool {
return false
},
Expand All @@ -252,7 +257,7 @@ func TestDispatch(t *testing.T) {
"cowboys",
admission.Create,
),
cluster: "dest-cluster",
cluster: "root:org:dest-cluster",
hookSourceNotSynced: true,
wantErr: true,
},
Expand All @@ -278,7 +283,7 @@ func TestDispatch(t *testing.T) {
ctx := request.WithCluster(context.Background(), request.Cluster{Name: logicalcluster.New(tc.cluster)})

if err := o.Dispatch(ctx, tc.attr, nil); (err != nil) != tc.wantErr {
t.Fatalf("Validate() error = %v, wantErr %v", err, tc.wantErr)
t.Fatalf("Dispatch() error = %v, wantErr %v", err, tc.wantErr)
}
})
}
Expand Down
Loading

0 comments on commit e7c42ef

Please sign in to comment.