mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 20:24:09 +00:00
Example webhook implementation (used in E2E test)
This commit is contained in:
parent
c3d05c816d
commit
8235e389fb
4
test/images/crd-conversion-webhook/BASEIMAGE
Normal file
4
test/images/crd-conversion-webhook/BASEIMAGE
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
amd64=alpine:3.6
|
||||||
|
arm=arm32v6/alpine:3.6
|
||||||
|
arm64=arm64v8/alpine:3.6
|
||||||
|
ppc64le=ppc64le/alpine:3.6
|
18
test/images/crd-conversion-webhook/Dockerfile
Normal file
18
test/images/crd-conversion-webhook/Dockerfile
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Copyright 2018 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.
|
||||||
|
|
||||||
|
FROM BASEIMAGE
|
||||||
|
|
||||||
|
ADD crd_conversion_webhook /crd_conversion_webhook
|
||||||
|
ENTRYPOINT ["/crd_conversion_webhook"]
|
25
test/images/crd-conversion-webhook/Makefile
Normal file
25
test/images/crd-conversion-webhook/Makefile
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# Copyright 2018 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.
|
||||||
|
|
||||||
|
SRCS=crd_conversion_webhook
|
||||||
|
ARCH ?= amd64
|
||||||
|
TARGET ?= $(CURDIR)
|
||||||
|
GOLANG_VERSION ?= latest
|
||||||
|
SRC_DIR = $(notdir $(shell pwd))
|
||||||
|
export
|
||||||
|
|
||||||
|
bin:
|
||||||
|
../image-util.sh bin $(SRCS)
|
||||||
|
|
||||||
|
.PHONY: bin
|
11
test/images/crd-conversion-webhook/README.md
Normal file
11
test/images/crd-conversion-webhook/README.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Kubernetes External Admission Webhook Test Image
|
||||||
|
|
||||||
|
The image tests CustomResourceConversionWebhook. After deploying it to kubernetes cluster,
|
||||||
|
administrator needs to create a CustomResourceConversion.Webhook
|
||||||
|
in kubernetes cluster to use remote webhook for conversions.
|
||||||
|
|
||||||
|
## Build the code
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make build
|
||||||
|
```
|
1
test/images/crd-conversion-webhook/VERSION
Normal file
1
test/images/crd-conversion-webhook/VERSION
Normal file
@ -0,0 +1 @@
|
|||||||
|
1.13rev2
|
51
test/images/crd-conversion-webhook/config.go
Normal file
51
test/images/crd-conversion-webhook/config.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 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 main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
|
||||||
|
"k8s.io/client-go/kubernetes"
|
||||||
|
"k8s.io/client-go/rest"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Get a clientset with in-cluster config.
|
||||||
|
func getClient() *kubernetes.Clientset {
|
||||||
|
config, err := rest.InClusterConfig()
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatal(err)
|
||||||
|
}
|
||||||
|
clientset, err := kubernetes.NewForConfig(config)
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatal(err)
|
||||||
|
}
|
||||||
|
return clientset
|
||||||
|
}
|
||||||
|
|
||||||
|
func configTLS(config Config, clientset *kubernetes.Clientset) *tls.Config {
|
||||||
|
sCert, err := tls.LoadX509KeyPair(config.CertFile, config.KeyFile)
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatal(err)
|
||||||
|
}
|
||||||
|
return &tls.Config{
|
||||||
|
Certificates: []tls.Certificate{sCert},
|
||||||
|
// TODO: uses mutual tls after we agree on what cert the apiserver should use.
|
||||||
|
// ClientAuth: tls.RequireAndVerifyClientCert,
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 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 converter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestConverter(t *testing.T) {
|
||||||
|
sampleObj := `kind: ConversionReview
|
||||||
|
apiVersion: apiextensions.k8s.io/v1beta1
|
||||||
|
request:
|
||||||
|
uid: 0000-0000-0000-0000
|
||||||
|
desiredAPIVersion: stable.example.com/v2
|
||||||
|
objects:
|
||||||
|
- apiVersion: stable.example.com/v1
|
||||||
|
kind: CronTab
|
||||||
|
metadata:
|
||||||
|
name: my-new-cron-object
|
||||||
|
spec:
|
||||||
|
cronSpec: "* * * * */5"
|
||||||
|
image: my-awesome-cron-image
|
||||||
|
hostPort: "localhost:7070"
|
||||||
|
`
|
||||||
|
// First try json, it should fail as the data is taml
|
||||||
|
response := httptest.NewRecorder()
|
||||||
|
request, err := http.NewRequest("POST", "/convert", strings.NewReader(sampleObj))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
request.Header.Add("Content-Type", "application/json")
|
||||||
|
ServeExampleConvert(response, request)
|
||||||
|
convertReview := v1beta1.ConversionReview{}
|
||||||
|
scheme := runtime.NewScheme()
|
||||||
|
jsonSerializer := json.NewSerializer(json.DefaultMetaFactory, scheme, scheme, false)
|
||||||
|
if _, _, err := jsonSerializer.Decode(response.Body.Bytes(), nil, &convertReview); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if convertReview.Response.Result.Status != v1.StatusFailure {
|
||||||
|
t.Fatalf("expected the operation to fail when yaml is provided with json header")
|
||||||
|
} else if !strings.Contains(convertReview.Response.Result.Message, "json parse error") {
|
||||||
|
t.Fatalf("expected to fail on json parser, but it failed with: %v", convertReview.Response.Result.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now try yaml, and it should successfully convert
|
||||||
|
response = httptest.NewRecorder()
|
||||||
|
request, err = http.NewRequest("POST", "/convert", strings.NewReader(sampleObj))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
request.Header.Add("Content-Type", "application/yaml")
|
||||||
|
ServeExampleConvert(response, request)
|
||||||
|
convertReview = v1beta1.ConversionReview{}
|
||||||
|
yamlSerializer := json.NewYAMLSerializer(json.DefaultMetaFactory, scheme, scheme)
|
||||||
|
if _, _, err := yamlSerializer.Decode(response.Body.Bytes(), nil, &convertReview); err != nil {
|
||||||
|
t.Fatalf("cannot decode data: \n %v\n Error: %v", response.Body, err)
|
||||||
|
}
|
||||||
|
if convertReview.Response.Result.Status != v1.StatusSuccess {
|
||||||
|
t.Fatalf("cr conversion failed: %v", convertReview.Response)
|
||||||
|
}
|
||||||
|
convertedObj := unstructured.Unstructured{}
|
||||||
|
if _, _, err := yamlSerializer.Decode(convertReview.Response.ConvertedObjects[0].Raw, nil, &convertedObj); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if e, a := "stable.example.com/v2", convertedObj.GetAPIVersion(); e != a {
|
||||||
|
t.Errorf("expected= %v, actual= %v", e, a)
|
||||||
|
}
|
||||||
|
if e, a := "localhost", convertedObj.Object["host"]; e != a {
|
||||||
|
t.Errorf("expected= %v, actual= %v", e, a)
|
||||||
|
}
|
||||||
|
if e, a := "7070", convertedObj.Object["port"]; e != a {
|
||||||
|
t.Errorf("expected= %v, actual= %v", e, a)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 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 converter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
)
|
||||||
|
|
||||||
|
func convertExampleCRD(Object *unstructured.Unstructured, toVersion string) (*unstructured.Unstructured, metav1.Status) {
|
||||||
|
glog.V(2).Info("converting crd")
|
||||||
|
|
||||||
|
convertedObject := Object.DeepCopy()
|
||||||
|
fromVersion := Object.GetAPIVersion()
|
||||||
|
|
||||||
|
if toVersion == fromVersion {
|
||||||
|
return nil, statusErrorWithMessage("conversion from a version to itself should not call the webhook: %s", toVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch Object.GetAPIVersion() {
|
||||||
|
case "stable.example.com/v1":
|
||||||
|
switch toVersion {
|
||||||
|
case "stable.example.com/v2":
|
||||||
|
hostPort, ok := convertedObject.Object["hostPort"]
|
||||||
|
if ok {
|
||||||
|
delete(convertedObject.Object, "hostPort")
|
||||||
|
parts := strings.Split(hostPort.(string), ":")
|
||||||
|
if len(parts) != 2 {
|
||||||
|
return nil, statusErrorWithMessage("invalid hostPort value `%v`", hostPort)
|
||||||
|
}
|
||||||
|
convertedObject.Object["host"] = parts[0]
|
||||||
|
convertedObject.Object["port"] = parts[1]
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, statusErrorWithMessage("unexpected conversion version %q", toVersion)
|
||||||
|
}
|
||||||
|
case "stable.example.com/v2":
|
||||||
|
switch toVersion {
|
||||||
|
case "stable.example.com/v1":
|
||||||
|
host, hasHost := convertedObject.Object["host"]
|
||||||
|
port, hasPort := convertedObject.Object["port"]
|
||||||
|
if hasHost || hasPort {
|
||||||
|
if !hasHost {
|
||||||
|
host = ""
|
||||||
|
}
|
||||||
|
if !hasPort {
|
||||||
|
port = ""
|
||||||
|
}
|
||||||
|
convertedObject.Object["hostPort"] = fmt.Sprintf("%s:%s", host, port)
|
||||||
|
delete(convertedObject.Object, "host")
|
||||||
|
delete(convertedObject.Object, "port")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, statusErrorWithMessage("unexpected conversion version %q", toVersion)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, statusErrorWithMessage("unexpected conversion version %q", fromVersion)
|
||||||
|
}
|
||||||
|
return convertedObject, statusSucceed()
|
||||||
|
}
|
178
test/images/crd-conversion-webhook/converter/framework.go
Normal file
178
test/images/crd-conversion-webhook/converter/framework.go
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 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 converter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bitbucket.org/ww/goautoneg"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
|
||||||
|
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
// convertFunc is the user defined function for any conversion. The code in this file is a
|
||||||
|
// template that can be use for any CR conversion given this function.
|
||||||
|
type convertFunc func(Object *unstructured.Unstructured, version string) (*unstructured.Unstructured, metav1.Status)
|
||||||
|
|
||||||
|
// conversionResponseFailureWithMessagef is a helper function to create an AdmissionResponse
|
||||||
|
// with a formatted embedded error message.
|
||||||
|
func conversionResponseFailureWithMessagef(msg string, params ...interface{}) *v1beta1.ConversionResponse {
|
||||||
|
return &v1beta1.ConversionResponse{
|
||||||
|
Result: metav1.Status{
|
||||||
|
Message: fmt.Sprintf(msg, params...),
|
||||||
|
Status: metav1.StatusFailure,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func statusErrorWithMessage(msg string, params ...interface{}) metav1.Status {
|
||||||
|
return metav1.Status{
|
||||||
|
Message: fmt.Sprintf(msg, params...),
|
||||||
|
Status: metav1.StatusFailure,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func statusSucceed() metav1.Status {
|
||||||
|
return metav1.Status{
|
||||||
|
Status: metav1.StatusSuccess,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// doConversion converts the requested object given the conversion function and returns a conversion response.
|
||||||
|
// failures will be reported as Reason in the conversion response.
|
||||||
|
func doConversion(convertRequest *v1beta1.ConversionRequest, convert convertFunc) *v1beta1.ConversionResponse {
|
||||||
|
var convertedObjects []runtime.RawExtension
|
||||||
|
for _, obj := range convertRequest.Objects {
|
||||||
|
cr := unstructured.Unstructured{}
|
||||||
|
if err := cr.UnmarshalJSON(obj.Raw); err != nil {
|
||||||
|
glog.Error(err)
|
||||||
|
return conversionResponseFailureWithMessagef("failed to unmarshall object (%v) with error: %v", string(obj.Raw), err)
|
||||||
|
}
|
||||||
|
convertedCR, status := convert(&cr, convertRequest.DesiredAPIVersion)
|
||||||
|
if status.Status != metav1.StatusSuccess {
|
||||||
|
glog.Error(status.String())
|
||||||
|
return &v1beta1.ConversionResponse{
|
||||||
|
Result: status,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
convertedCR.SetAPIVersion(convertRequest.DesiredAPIVersion)
|
||||||
|
convertedObjects = append(convertedObjects, runtime.RawExtension{Object: convertedCR})
|
||||||
|
}
|
||||||
|
return &v1beta1.ConversionResponse{
|
||||||
|
ConvertedObjects: convertedObjects,
|
||||||
|
Result: statusSucceed(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func serve(w http.ResponseWriter, r *http.Request, convert convertFunc) {
|
||||||
|
var body []byte
|
||||||
|
if r.Body != nil {
|
||||||
|
if data, err := ioutil.ReadAll(r.Body); err == nil {
|
||||||
|
body = data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contentType := r.Header.Get("Content-Type")
|
||||||
|
serializer := getInputSerializer(contentType)
|
||||||
|
if serializer == nil {
|
||||||
|
msg := fmt.Sprintf("invalid Content-Type header `%s`", contentType)
|
||||||
|
glog.Errorf(msg)
|
||||||
|
http.Error(w, msg, http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
glog.V(2).Infof("handling request: %v", body)
|
||||||
|
convertReview := v1beta1.ConversionReview{}
|
||||||
|
if _, _, err := serializer.Decode(body, nil, &convertReview); err != nil {
|
||||||
|
glog.Error(err)
|
||||||
|
convertReview.Response = conversionResponseFailureWithMessagef("failed to deserialize body (%v) with error %v", string(body), err)
|
||||||
|
} else {
|
||||||
|
convertReview.Response = doConversion(convertReview.Request, convert)
|
||||||
|
convertReview.Response.UID = convertReview.Request.UID
|
||||||
|
}
|
||||||
|
glog.V(2).Info(fmt.Sprintf("sending response: %v", convertReview.Response))
|
||||||
|
|
||||||
|
// reset the request, it is not needed in a response.
|
||||||
|
convertReview.Request = &v1beta1.ConversionRequest{}
|
||||||
|
|
||||||
|
accept := r.Header.Get("Accept")
|
||||||
|
outSerializer := getOutputSerializer(accept)
|
||||||
|
if outSerializer == nil {
|
||||||
|
msg := fmt.Sprintf("invalid accept header `%s`", accept)
|
||||||
|
glog.Errorf(msg)
|
||||||
|
http.Error(w, msg, http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := outSerializer.Encode(&convertReview, w)
|
||||||
|
if err != nil {
|
||||||
|
glog.Error(err)
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServeExampleConvert servers endpoint for the example converter defined as convertExampleCRD function.
|
||||||
|
func ServeExampleConvert(w http.ResponseWriter, r *http.Request) {
|
||||||
|
serve(w, r, convertExampleCRD)
|
||||||
|
}
|
||||||
|
|
||||||
|
type mediaType struct {
|
||||||
|
Type, SubType string
|
||||||
|
}
|
||||||
|
|
||||||
|
var scheme = runtime.NewScheme()
|
||||||
|
var serializers = map[mediaType]runtime.Serializer{
|
||||||
|
{"application", "json"}: json.NewSerializer(json.DefaultMetaFactory, scheme, scheme, false),
|
||||||
|
{"application", "yaml"}: json.NewYAMLSerializer(json.DefaultMetaFactory, scheme, scheme),
|
||||||
|
}
|
||||||
|
|
||||||
|
func getInputSerializer(contentType string) runtime.Serializer {
|
||||||
|
parts := strings.SplitN(contentType, "/", 2)
|
||||||
|
if len(parts) != 2 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return serializers[mediaType{parts[0], parts[1]}]
|
||||||
|
}
|
||||||
|
|
||||||
|
func getOutputSerializer(accept string) runtime.Serializer {
|
||||||
|
if len(accept) == 0 {
|
||||||
|
return serializers[mediaType{"application", "json"}]
|
||||||
|
}
|
||||||
|
|
||||||
|
clauses := goautoneg.ParseAccept(accept)
|
||||||
|
for _, clause := range clauses {
|
||||||
|
for k, v := range serializers {
|
||||||
|
switch {
|
||||||
|
case clause.Type == k.Type && clause.SubType == k.SubType,
|
||||||
|
clause.Type == k.Type && clause.SubType == "*",
|
||||||
|
clause.Type == "*" && clause.SubType == "*":
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
52
test/images/crd-conversion-webhook/main.go
Normal file
52
test/images/crd-conversion-webhook/main.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 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 main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/test/images/crd-conversion-webhook/converter"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config contains the server (the webhook) cert and key.
|
||||||
|
type Config struct {
|
||||||
|
CertFile string
|
||||||
|
KeyFile string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) addFlags() {
|
||||||
|
flag.StringVar(&c.CertFile, "tls-cert-file", c.CertFile, ""+
|
||||||
|
"File containing the default x509 Certificate for HTTPS. (CA cert, if any, concatenated "+
|
||||||
|
"after server cert).")
|
||||||
|
flag.StringVar(&c.KeyFile, "tls-private-key-file", c.KeyFile, ""+
|
||||||
|
"File containing the default x509 private key matching --tls-cert-file.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var config Config
|
||||||
|
config.addFlags()
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
http.HandleFunc("/crdconvert", converter.ServeExampleConvert)
|
||||||
|
clientset := getClient()
|
||||||
|
server := &http.Server{
|
||||||
|
Addr: ":443",
|
||||||
|
TLSConfig: configTLS(config, clientset),
|
||||||
|
}
|
||||||
|
server.ListenAndServeTLS("", "")
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user