Merge pull request #52673 from p0lyn0mial/webhook_default_service_resolver
Automatic merge from submit-queue (batch tested with PRs 52831, 52764, 52763, 52673, 52558). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.. default service resolver for webhook admission **What this PR does / why we need it**: provides a default service resolver for webhook plugin. The rationale behind is that webhook plugins names can be resolved by a dns server working inside a cluster. **Release note**: ``` NONE ```
This commit is contained in:
		@@ -188,9 +188,6 @@ func (i *PluginInitializer) Initialize(plugin admission.Interface) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if wants, ok := plugin.(WantsServiceResolver); ok {
 | 
			
		||||
		if i.serviceResolver == nil {
 | 
			
		||||
			panic("An admission plugin wants the service resolver, but it was not provided.")
 | 
			
		||||
		}
 | 
			
		||||
		wants.SetServiceResolver(i.serviceResolver)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ go_test(
 | 
			
		||||
        "admission_test.go",
 | 
			
		||||
        "certs_test.go",
 | 
			
		||||
        "rules_test.go",
 | 
			
		||||
        "serviceresolver_test.go",
 | 
			
		||||
    ],
 | 
			
		||||
    library = ":go_default_library",
 | 
			
		||||
    deps = [
 | 
			
		||||
@@ -32,6 +33,7 @@ go_library(
 | 
			
		||||
        "admission.go",
 | 
			
		||||
        "doc.go",
 | 
			
		||||
        "rules.go",
 | 
			
		||||
        "serviceresolver.go",
 | 
			
		||||
    ],
 | 
			
		||||
    deps = [
 | 
			
		||||
        "//pkg/api:go_default_library",
 | 
			
		||||
 
 | 
			
		||||
@@ -97,6 +97,7 @@ func NewGenericAdmissionWebhook() (*GenericAdmissionWebhook, error) {
 | 
			
		||||
		negotiatedSerializer: serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{
 | 
			
		||||
			Serializer: api.Codecs.LegacyCodec(admissionv1alpha1.SchemeGroupVersion),
 | 
			
		||||
		}),
 | 
			
		||||
		serviceResolver: defaultServiceResolver{},
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -121,8 +122,12 @@ func (a *GenericAdmissionWebhook) SetProxyTransport(pt *http.Transport) {
 | 
			
		||||
	a.proxyTransport = pt
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetServiceResolver sets a service resolver for the webhook admission plugin.
 | 
			
		||||
// Passing a nil resolver does not have an effect, instead a default one will be used.
 | 
			
		||||
func (a *GenericAdmissionWebhook) SetServiceResolver(sr admissioninit.ServiceResolver) {
 | 
			
		||||
	if sr != nil {
 | 
			
		||||
		a.serviceResolver = sr
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a *GenericAdmissionWebhook) SetClientCert(cert, key []byte) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										42
									
								
								plugin/pkg/admission/webhook/serviceresolver.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								plugin/pkg/admission/webhook/serviceresolver.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2017 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 webhook checks a webhook for configured operation admission
 | 
			
		||||
package webhook
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/url"
 | 
			
		||||
 | 
			
		||||
	admissioninit "k8s.io/kubernetes/pkg/kubeapiserver/admission"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type defaultServiceResolver struct{}
 | 
			
		||||
 | 
			
		||||
var _ admissioninit.ServiceResolver = defaultServiceResolver{}
 | 
			
		||||
 | 
			
		||||
// ResolveEndpoint constructs a service URL from a given namespace and name
 | 
			
		||||
// note that the name and namespace are required and by default all created addresses use HTTPS scheme.
 | 
			
		||||
// for example:
 | 
			
		||||
//  name=ross namespace=andromeda resolves to https://ross.andromeda.svc
 | 
			
		||||
func (sr defaultServiceResolver) ResolveEndpoint(namespace, name string) (*url.URL, error) {
 | 
			
		||||
	if len(name) == 0 || len(namespace) == 0 {
 | 
			
		||||
		return &url.URL{}, errors.New("cannot resolve an empty service name or namespace")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return url.Parse(fmt.Sprintf("https://%s.%s.svc", name, namespace))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										57
									
								
								plugin/pkg/admission/webhook/serviceresolver_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								plugin/pkg/admission/webhook/serviceresolver_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2017 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 webhook checks a webhook for configured operation admission
 | 
			
		||||
package webhook
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestDefaultServiceResolver(t *testing.T) {
 | 
			
		||||
	scenarios := []struct {
 | 
			
		||||
		serviceName      string
 | 
			
		||||
		serviceNamespace string
 | 
			
		||||
		expectedOutput   string
 | 
			
		||||
		expectError      bool
 | 
			
		||||
	}{
 | 
			
		||||
		// scenario 1: a service name along with a namespace resolves
 | 
			
		||||
		{serviceName: "ross", serviceNamespace: "andromeda", expectedOutput: "https://ross.andromeda.svc"},
 | 
			
		||||
		// scenario 2: a service name without a namespace does not resolve
 | 
			
		||||
		{serviceName: "ross", expectError: true},
 | 
			
		||||
		// scenario 3: cannot resolve an empty service name
 | 
			
		||||
		{serviceNamespace: "andromeda", expectError: true},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// act
 | 
			
		||||
	for index, scenario := range scenarios {
 | 
			
		||||
		t.Run(fmt.Sprintf("scenario %d", index), func(t *testing.T) {
 | 
			
		||||
			target := defaultServiceResolver{}
 | 
			
		||||
			serviceURL, err := target.ResolveEndpoint(scenario.serviceNamespace, scenario.serviceName)
 | 
			
		||||
 | 
			
		||||
			if err != nil && !scenario.expectError {
 | 
			
		||||
				t.Errorf("unexpected error has occurred = %v", err)
 | 
			
		||||
			}
 | 
			
		||||
			if err == nil && scenario.expectError {
 | 
			
		||||
				t.Error("expected an error but got nothing")
 | 
			
		||||
			}
 | 
			
		||||
			if serviceURL.String() != scenario.expectedOutput {
 | 
			
		||||
				t.Errorf("expected = %s, got = %s", scenario.expectedOutput, serviceURL.String())
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user