Merge pull request #55127 from caesarxuchao/webhook-do-conversion

Automatic merge from submit-queue (batch tested with PRs 54005, 55127, 53850, 55486, 53440). 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>.

Validation webhook plugin converts objects to the external version before sending to webhooks

**What this PR does / why we need it**:


**Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*:

https://github.com/kubernetes/features/issues/492

**Special notes for your reviewer**:

**Release note**:

```release-note
The apiserver sends external versioned object to the admission webhooks now. Please update the webhooks to expect admissionReview.spec.object.raw to be serialized external versions of objects. 
```
pull/6/head
Kubernetes Submit Queue 2017-11-13 16:45:22 -08:00 committed by GitHub
commit cba5aa0590
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 2161 additions and 70 deletions

View File

@ -552,6 +552,8 @@ staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1
staging/src/k8s.io/apiserver/pkg/apis/audit/validation
staging/src/k8s.io/apiserver/pkg/apis/example
staging/src/k8s.io/apiserver/pkg/apis/example/v1
staging/src/k8s.io/apiserver/pkg/apis/example2
staging/src/k8s.io/apiserver/pkg/apis/example2/v1
staging/src/k8s.io/apiserver/pkg/audit
staging/src/k8s.io/apiserver/pkg/audit/policy
staging/src/k8s.io/apiserver/pkg/authentication/authenticatorfactory

View File

@ -419,7 +419,7 @@ function start_apiserver {
fi
# Admission Controllers to invoke prior to persisting objects in cluster
ADMISSION_CONTROL=Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount${security_admission},DefaultStorageClass,DefaultTolerationSeconds,ResourceQuota,GenericAdmissionWebhook
ADMISSION_CONTROL=Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount${security_admission},DefaultStorageClass,DefaultTolerationSeconds,GenericAdmissionWebhook,ResourceQuota
# This is the default dir and filename where the apiserver will generate a self-signed cert
# which should be able to be used as the CA to verify itself

View File

@ -77,6 +77,7 @@ PACKAGES=(
k8s.io/metrics/pkg/apis/custom_metrics/v1beta1
k8s.io/apiserver/pkg/apis/audit/v1alpha1
k8s.io/apiserver/pkg/apis/audit/v1beta1
k8s.io/apiserver/pkg/apis/example2/v1
)
# requires the 'proto' tag to build (will remove when ready)

View File

@ -59,6 +59,7 @@ openapi_library(
"k8s.io/apiserver/pkg/apis/audit/v1alpha1",
"k8s.io/apiserver/pkg/apis/audit/v1beta1",
"k8s.io/apiserver/pkg/apis/example/v1",
"k8s.io/apiserver/pkg/apis/example2/v1",
"k8s.io/client-go/pkg/version",
"k8s.io/kube-aggregator/pkg/apis/apiregistration/v1beta1",
"k8s.io/metrics/pkg/apis/custom_metrics/v1beta1",

View File

@ -96,6 +96,7 @@ filegroup(
"//staging/src/k8s.io/apiserver/pkg/apis/apiserver:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/apis/audit:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/apis/example:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/apis/example2:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/audit:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/authentication/authenticatorfactory:all-srcs",

View File

@ -146,7 +146,11 @@ func NewCurletInstance(namespace, name string) *unstructured.Unstructured {
}
}
func CreateNewCustomResourceDefinition(crd *apiextensionsv1beta1.CustomResourceDefinition, apiExtensionsClient clientset.Interface, clientPool dynamic.ClientPool) (dynamic.Interface, error) {
// CreateNewCustomResourceDefinitionWatchUnsafe creates the CRD and makes sure
// the apiextension apiserver has installed the CRD. But it's not safe to watch
// the created CR. Please call CreateNewCustomResourceDefinition if you need to
// watch the CR.
func CreateNewCustomResourceDefinitionWatchUnsafe(crd *apiextensionsv1beta1.CustomResourceDefinition, apiExtensionsClient clientset.Interface, clientPool dynamic.ClientPool) (dynamic.Interface, error) {
_, err := apiExtensionsClient.Apiextensions().CustomResourceDefinitions().Create(crd)
if err != nil {
return nil, err
@ -169,7 +173,11 @@ func CreateNewCustomResourceDefinition(crd *apiextensionsv1beta1.CustomResourceD
return nil, err
}
dynamicClient, err := clientPool.ClientForGroupVersionResource(schema.GroupVersionResource{Group: crd.Spec.Group, Version: crd.Spec.Version, Resource: crd.Spec.Names.Plural})
return clientPool.ClientForGroupVersionResource(schema.GroupVersionResource{Group: crd.Spec.Group, Version: crd.Spec.Version, Resource: crd.Spec.Names.Plural})
}
func CreateNewCustomResourceDefinition(crd *apiextensionsv1beta1.CustomResourceDefinition, apiExtensionsClient clientset.Interface, clientPool dynamic.ClientPool) (dynamic.Interface, error) {
dynamicClient, err := CreateNewCustomResourceDefinitionWatchUnsafe(crd, apiExtensionsClient, clientPool)
if err != nil {
return nil, err
}

View File

@ -24,6 +24,7 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
@ -46,6 +47,7 @@ go_test(
"admission_test.go",
"authentication_test.go",
"certs_test.go",
"conversion_test.go",
"rules_test.go",
"serviceresolver_test.go",
],
@ -58,11 +60,15 @@ go_test(
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
"//vendor/k8s.io/apiserver/pkg/admission:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/example:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/example/v1:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/example2/v1:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authentication/user:go_default_library",
"//vendor/k8s.io/client-go/rest:go_default_library",
"//vendor/k8s.io/client-go/tools/clientcmd/api:go_default_library",

View File

@ -37,6 +37,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
@ -134,6 +135,8 @@ type GenericAdmissionWebhook struct {
negotiatedSerializer runtime.NegotiatedSerializer
namespaceLister corelisters.NamespaceLister
client clientset.Interface
convertor runtime.ObjectConvertor
creator runtime.ObjectCreater
authInfoResolver AuthenticationInfoResolver
cache *lru.Cache
@ -169,6 +172,8 @@ func (a *GenericAdmissionWebhook) SetScheme(scheme *runtime.Scheme) {
a.negotiatedSerializer = serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{
Serializer: serializer.NewCodecFactory(scheme).LegacyCodec(admissionv1alpha1.SchemeGroupVersion),
})
a.convertor = scheme
a.creator = scheme
}
}
@ -219,6 +224,37 @@ func (a *GenericAdmissionWebhook) loadConfiguration(attr admission.Attributes) (
return hookConfig, nil
}
type versionedAttributes struct {
admission.Attributes
oldObject runtime.Object
object runtime.Object
}
func (v versionedAttributes) GetObject() runtime.Object {
return v.object
}
func (v versionedAttributes) GetOldObject() runtime.Object {
return v.oldObject
}
func (a *GenericAdmissionWebhook) convertToGVK(obj runtime.Object, gvk schema.GroupVersionKind) (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 := a.creator.New(gvk)
if err != nil {
return nil, err
}
err = a.convertor.Convert(obj, out, nil)
if err != nil {
return nil, err
}
return out, nil
}
// Admit makes an admission decision based on the request attributes.
func (a *GenericAdmissionWebhook) Admit(attr admission.Attributes) error {
hookConfig, err := a.loadConfiguration(attr)
@ -228,14 +264,49 @@ func (a *GenericAdmissionWebhook) Admit(attr admission.Attributes) error {
hooks := hookConfig.Webhooks
ctx := context.TODO()
errCh := make(chan error, len(hooks))
wg := sync.WaitGroup{}
wg.Add(len(hooks))
var relevantHooks []*v1alpha1.Webhook
for i := range hooks {
call, err := a.shouldCallHook(&hooks[i], attr)
if err != nil {
return err
}
if call {
relevantHooks = append(relevantHooks, &hooks[i])
}
}
if len(relevantHooks) == 0 {
// no matching hooks
return nil
}
// convert the object to the external version before sending it to the webhook
versionedAttr := versionedAttributes{
Attributes: attr,
}
if oldObj := attr.GetOldObject(); oldObj != nil {
out, err := a.convertToGVK(oldObj, attr.GetKind())
if err != nil {
return apierrors.NewInternalError(err)
}
versionedAttr.oldObject = out
}
if obj := attr.GetObject(); obj != nil {
out, err := a.convertToGVK(obj, attr.GetKind())
if err != nil {
return apierrors.NewInternalError(err)
}
versionedAttr.object = out
}
wg := sync.WaitGroup{}
errCh := make(chan error, len(relevantHooks))
wg.Add(len(relevantHooks))
for i := range relevantHooks {
go func(hook *v1alpha1.Webhook) {
defer wg.Done()
err := a.callHook(ctx, hook, attr)
err := a.callHook(ctx, hook, versionedAttr)
if err == nil {
return
}
@ -256,7 +327,7 @@ func (a *GenericAdmissionWebhook) Admit(attr admission.Attributes) error {
glog.Warningf("rejected by webhook %q: %#v", hook.Name, err)
errCh <- err
}(&hooks[i])
}(relevantHooks[i])
}
wg.Wait()
close(errCh)
@ -313,7 +384,7 @@ func (a *GenericAdmissionWebhook) getNamespaceLabels(attr admission.Attributes)
// whether the request is exempted by the webhook because of the
// namespaceSelector of the webhook.
func (a *GenericAdmissionWebhook) exemptedByNamespaceSelector(h *v1alpha1.Webhook, attr admission.Attributes) (bool, error) {
func (a *GenericAdmissionWebhook) exemptedByNamespaceSelector(h *v1alpha1.Webhook, attr admission.Attributes) (bool, *apierrors.StatusError) {
namespaceName := attr.GetNamespace()
if len(namespaceName) == 0 && attr.GetResource().Resource != "namespaces" {
// If the request is about a cluster scoped resource, and it is not a
@ -323,8 +394,14 @@ func (a *GenericAdmissionWebhook) exemptedByNamespaceSelector(h *v1alpha1.Webhoo
return true, nil
}
namespaceLabels, err := a.getNamespaceLabels(attr)
// this means the namespace is not found, for backwards compatibility,
// return a 404
if apierrors.IsNotFound(err) {
return false, err
status, ok := err.(apierrors.APIStatus)
if !ok {
return false, apierrors.NewInternalError(err)
}
return false, &apierrors.StatusError{status.Status()}
}
if err != nil {
return false, apierrors.NewInternalError(err)
@ -337,15 +414,8 @@ func (a *GenericAdmissionWebhook) exemptedByNamespaceSelector(h *v1alpha1.Webhoo
return !selector.Matches(labels.Set(namespaceLabels)), nil
}
func (a *GenericAdmissionWebhook) callHook(ctx context.Context, h *v1alpha1.Webhook, attr admission.Attributes) error {
excluded, err := a.exemptedByNamespaceSelector(h, attr)
if err != nil {
return err
}
if excluded {
return nil
}
matches := false
func (a *GenericAdmissionWebhook) shouldCallHook(h *v1alpha1.Webhook, attr admission.Attributes) (bool, *apierrors.StatusError) {
var matches bool
for _, r := range h.Rules {
m := RuleMatcher{Rule: r, Attr: attr}
if m.Matches() {
@ -354,9 +424,17 @@ func (a *GenericAdmissionWebhook) callHook(ctx context.Context, h *v1alpha1.Webh
}
}
if !matches {
return nil
return false, nil
}
excluded, err := a.exemptedByNamespaceSelector(h, attr)
if err != nil {
return false, err
}
return !excluded, nil
}
func (a *GenericAdmissionWebhook) callHook(ctx context.Context, h *v1alpha1.Webhook, attr admission.Attributes) error {
// Make the webhook request
request := createAdmissionReview(attr)
client, err := a.hookClient(h)

View File

@ -0,0 +1,135 @@
/*
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
import (
"reflect"
"testing"
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/schema"
"k8s.io/apiserver/pkg/apis/example"
examplev1 "k8s.io/apiserver/pkg/apis/example/v1"
example2v1 "k8s.io/apiserver/pkg/apis/example2/v1"
)
func initiateScheme() *runtime.Scheme {
s := runtime.NewScheme()
example.AddToScheme(s)
examplev1.AddToScheme(s)
example2v1.AddToScheme(s)
return s
}
func TestConvertToGVK(t *testing.T) {
scheme := initiateScheme()
w := GenericAdmissionWebhook{
convertor: scheme,
creator: scheme,
}
table := map[string]struct {
obj runtime.Object
gvk schema.GroupVersionKind
expectedObj runtime.Object
}{
"convert example#Pod to example/v1#Pod": {
obj: &example.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod1",
Labels: map[string]string{
"key": "value",
},
},
Spec: example.PodSpec{
RestartPolicy: example.RestartPolicy("never"),
},
},
gvk: examplev1.SchemeGroupVersion.WithKind("Pod"),
expectedObj: &examplev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod1",
Labels: map[string]string{
"key": "value",
},
},
Spec: examplev1.PodSpec{
RestartPolicy: examplev1.RestartPolicy("never"),
},
},
},
"convert example#replicaset to example2/v1#replicaset": {
obj: &example.ReplicaSet{
ObjectMeta: metav1.ObjectMeta{
Name: "rs1",
Labels: map[string]string{
"key": "value",
},
},
Spec: example.ReplicaSetSpec{
Replicas: 1,
},
},
gvk: example2v1.SchemeGroupVersion.WithKind("ReplicaSet"),
expectedObj: &example2v1.ReplicaSet{
ObjectMeta: metav1.ObjectMeta{
Name: "rs1",
Labels: map[string]string{
"key": "value",
},
},
Spec: example2v1.ReplicaSetSpec{
Replicas: func() *int32 { var i int32; i = 1; return &i }(),
},
},
},
"no conversion for Unstructured object whose gvk matches the desired gvk": {
obj: &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "mygroup.k8s.io/v1",
"kind": "Flunder",
"data": map[string]interface{}{
"Key": "Value",
},
},
},
gvk: schema.GroupVersionKind{Group: "mygroup.k8s.io", Version: "v1", Kind: "Flunder"},
expectedObj: &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "mygroup.k8s.io/v1",
"kind": "Flunder",
"data": map[string]interface{}{
"Key": "Value",
},
},
},
},
}
for name, test := range table {
t.Run(name, func(t *testing.T) {
actual, err := w.convertToGVK(test.obj, test.gvk)
if err != nil {
t.Error(err)
}
if !reflect.DeepEqual(actual, test.expectedObj) {
t.Errorf("\nexpected:\n%#v\ngot:\n %#v\n", test.expectedObj, actual)
}
})
}
}

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// Package install installs the certificates API group, making it available as
// Package install installs the example API group, making it available as
// an option to all of the API encoding/decoding machinery.
package install

View File

@ -46,6 +46,7 @@ func Resource(resource string) schema.GroupResource {
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&Pod{},
&ReplicaSet{},
)
return nil
}

View File

@ -136,3 +136,35 @@ type PodList struct {
Items []Pod
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// ReplicaSet ensures that a specified number of pod replicas are running at any given time.
type ReplicaSet struct {
metav1.TypeMeta
// +optional
metav1.ObjectMeta
// Spec defines the desired behavior of this ReplicaSet.
// +optional
Spec ReplicaSetSpec
// Status is the current status of this ReplicaSet. This data may be
// out of date by some window of time.
// +optional
Status ReplicaSetStatus
}
// ReplicaSetSpec is the specification of a ReplicaSet.
// As the internal representation of a ReplicaSet, it must have
// a Template set.
type ReplicaSetSpec struct {
// Replicas is the number of desired replicas.
Replicas int32
}
// ReplicaSetStatus represents the current status of a ReplicaSet.
type ReplicaSetStatus struct {
// Replicas is the number of actual replicas.
Replicas int32
}

View File

@ -178,3 +178,64 @@ func (in *PodStatus) DeepCopy() *PodStatus {
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ReplicaSet) DeepCopyInto(out *ReplicaSet) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
out.Spec = in.Spec
out.Status = in.Status
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReplicaSet.
func (in *ReplicaSet) DeepCopy() *ReplicaSet {
if in == nil {
return nil
}
out := new(ReplicaSet)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *ReplicaSet) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
} else {
return nil
}
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ReplicaSetSpec) DeepCopyInto(out *ReplicaSetSpec) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReplicaSetSpec.
func (in *ReplicaSetSpec) DeepCopy() *ReplicaSetSpec {
if in == nil {
return nil
}
out := new(ReplicaSetSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ReplicaSetStatus) DeepCopyInto(out *ReplicaSetStatus) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReplicaSetStatus.
func (in *ReplicaSetStatus) DeepCopy() *ReplicaSetStatus {
if in == nil {
return nil
}
out := new(ReplicaSetStatus)
in.DeepCopyInto(out)
return out
}

View File

@ -0,0 +1,38 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"doc.go",
"register.go",
"zz_generated.deepcopy.go",
],
importpath = "k8s.io/apiserver/pkg/apis/example2",
deps = [
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/example:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//staging/src/k8s.io/apiserver/pkg/apis/example2/install:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/apis/example2/v1:all-srcs",
],
tags = ["automanaged"],
)

View File

@ -0,0 +1,24 @@
/*
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.
*/
// +k8s:deepcopy-gen=package
// +groupName=example2.k8s.io
//
// package example2 contains an example API whose internal version is defined in
// another group ("example"). This happens if a type is moved to a different
// group. It's not recommended to move types across groups, though Kubernetes
// have a few cases due to historical reasons. This package is for tests.
package example2 // import "k8s.io/apiserver/pkg/apis/example2"

View File

@ -0,0 +1,45 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = ["install.go"],
importpath = "k8s.io/apiserver/pkg/apis/example2/install",
deps = [
"//vendor/k8s.io/apimachinery/pkg/apimachinery/announced:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apimachinery/registered:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/example:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/example2:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/example2/v1:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["roundtrip_test.go"],
importpath = "k8s.io/apiserver/pkg/apis/example2/install",
library = ":go_default_library",
deps = [
"//vendor/k8s.io/apimachinery/pkg/api/testing/roundtrip:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/example/fuzzer:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -0,0 +1,44 @@
/*
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 install installs the example2 API group, making it available as
// an option to all of the API encoding/decoding machinery.
package install
import (
"k8s.io/apimachinery/pkg/apimachinery/announced"
"k8s.io/apimachinery/pkg/apimachinery/registered"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/apis/example"
"k8s.io/apiserver/pkg/apis/example2"
example2v1 "k8s.io/apiserver/pkg/apis/example2/v1"
)
// Install registers the API group and adds types to a scheme
func Install(groupFactoryRegistry announced.APIGroupFactoryRegistry, registry *registered.APIRegistrationManager, scheme *runtime.Scheme) {
if err := announced.NewGroupMetaFactory(
&announced.GroupMetaFactoryArgs{
GroupName: example2.GroupName,
VersionPreferenceOrder: []string{example2v1.SchemeGroupVersion.Version},
AddInternalObjectsToScheme: example.AddToScheme,
},
announced.VersionToSchemeFunc{
example2v1.SchemeGroupVersion.Version: example2v1.AddToScheme,
},
).Announce(groupFactoryRegistry).RegisterAndEnable(registry, scheme); err != nil {
panic(err)
}
}

View File

@ -0,0 +1,28 @@
/*
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 install
import (
"testing"
"k8s.io/apimachinery/pkg/api/testing/roundtrip"
examplefuzzer "k8s.io/apiserver/pkg/apis/example/fuzzer"
)
func TestRoundTrip(t *testing.T) {
roundtrip.RoundTripTestForAPIGroup(t, Install, examplefuzzer.Funcs)
}

View File

@ -0,0 +1,52 @@
/*
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 example2
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apiserver/pkg/apis/example"
)
var (
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
AddToScheme = SchemeBuilder.AddToScheme
)
// GroupName is the group name use in this package
const GroupName = "example2.apiserver.k8s.io"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
// Kind takes an unqualified kind and returns a Group qualified GroupKind
func Kind(kind string) schema.GroupKind {
return SchemeGroupVersion.WithKind(kind).GroupKind()
}
// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
// Adds the list of known types to the given scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&example.ReplicaSet{},
)
return nil
}

View File

@ -0,0 +1,50 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"conversion.go",
"defaults.go",
"doc.go",
"generated.pb.go",
"register.go",
"types.go",
"types_swagger_doc_generated.go",
"zz_generated.conversion.go",
"zz_generated.deepcopy.go",
"zz_generated.defaults.go",
],
importpath = "k8s.io/apiserver/pkg/apis/example2/v1",
deps = [
"//vendor/github.com/gogo/protobuf/proto:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/example:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)
filegroup(
name = "go_default_library_protos",
srcs = ["generated.proto"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,51 @@
/*
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 v1
import (
conversion "k8s.io/apimachinery/pkg/conversion"
"k8s.io/apimachinery/pkg/runtime"
example "k8s.io/apiserver/pkg/apis/example"
)
func addConversionFuncs(scheme *runtime.Scheme) error {
// Add non-generated conversion functions to handle the *int32 -> int32
// conversion. A pointer is useful in the versioned type so we can default
// it, but a plain int32 is more convenient in the internal type. These
// functions are the same as the autogenerated ones in every other way.
err := scheme.AddConversionFuncs(
Convert_example_ReplicaSetSpec_To_v1_ReplicaSetSpec,
Convert_v1_ReplicaSetSpec_To_example_ReplicaSetSpec,
)
if err != nil {
return err
}
return nil
}
func Convert_example_ReplicaSetSpec_To_v1_ReplicaSetSpec(in *example.ReplicaSetSpec, out *ReplicaSetSpec, s conversion.Scope) error {
out.Replicas = new(int32)
*out.Replicas = int32(in.Replicas)
return nil
}
func Convert_v1_ReplicaSetSpec_To_example_ReplicaSetSpec(in *ReplicaSetSpec, out *example.ReplicaSetSpec, s conversion.Scope) error {
if in.Replicas != nil {
out.Replicas = *in.Replicas
}
return nil
}

View File

@ -0,0 +1,26 @@
/*
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 v1
import (
"k8s.io/apimachinery/pkg/runtime"
)
func addDefaultingFuncs(scheme *runtime.Scheme) error {
// return RegisterDefaults(scheme)
return nil
}

View File

@ -0,0 +1,24 @@
/*
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.
*/
// +k8s:deepcopy-gen=package
// +k8s:conversion-gen=k8s.io/apiserver/pkg/apis/example2
// +k8s:conversion-gen=k8s.io/apiserver/pkg/apis/example
// +k8s:openapi-gen=false
// +k8s:defaulter-gen=TypeMeta
// +groupName=example2.apiserver.k8s.io
package v1 // import "k8s.io/apiserver/pkg/apis/example2/v1"

View File

@ -0,0 +1,682 @@
/*
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.
*/
// Code generated by protoc-gen-gogo.
// source: k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/apis/example2/v1/generated.proto
// DO NOT EDIT!
/*
Package v1 is a generated protocol buffer package.
It is generated from these files:
k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/apis/example2/v1/generated.proto
It has these top-level messages:
ReplicaSet
ReplicaSetSpec
ReplicaSetStatus
*/
package v1
import proto "github.com/gogo/protobuf/proto"
import fmt "fmt"
import math "math"
import strings "strings"
import reflect "reflect"
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
func (m *ReplicaSet) Reset() { *m = ReplicaSet{} }
func (*ReplicaSet) ProtoMessage() {}
func (*ReplicaSet) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{0} }
func (m *ReplicaSetSpec) Reset() { *m = ReplicaSetSpec{} }
func (*ReplicaSetSpec) ProtoMessage() {}
func (*ReplicaSetSpec) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{1} }
func (m *ReplicaSetStatus) Reset() { *m = ReplicaSetStatus{} }
func (*ReplicaSetStatus) ProtoMessage() {}
func (*ReplicaSetStatus) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{2} }
func init() {
proto.RegisterType((*ReplicaSet)(nil), "k8s.io.apiserver.pkg.apis.example2.v1.ReplicaSet")
proto.RegisterType((*ReplicaSetSpec)(nil), "k8s.io.apiserver.pkg.apis.example2.v1.ReplicaSetSpec")
proto.RegisterType((*ReplicaSetStatus)(nil), "k8s.io.apiserver.pkg.apis.example2.v1.ReplicaSetStatus")
}
func (m *ReplicaSet) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *ReplicaSet) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
dAtA[i] = 0xa
i++
i = encodeVarintGenerated(dAtA, i, uint64(m.ObjectMeta.Size()))
n1, err := m.ObjectMeta.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n1
dAtA[i] = 0x12
i++
i = encodeVarintGenerated(dAtA, i, uint64(m.Spec.Size()))
n2, err := m.Spec.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n2
dAtA[i] = 0x1a
i++
i = encodeVarintGenerated(dAtA, i, uint64(m.Status.Size()))
n3, err := m.Status.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n3
return i, nil
}
func (m *ReplicaSetSpec) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *ReplicaSetSpec) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if m.Replicas != nil {
dAtA[i] = 0x8
i++
i = encodeVarintGenerated(dAtA, i, uint64(*m.Replicas))
}
return i, nil
}
func (m *ReplicaSetStatus) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *ReplicaSetStatus) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
dAtA[i] = 0x8
i++
i = encodeVarintGenerated(dAtA, i, uint64(m.Replicas))
return i, nil
}
func encodeFixed64Generated(dAtA []byte, offset int, v uint64) int {
dAtA[offset] = uint8(v)
dAtA[offset+1] = uint8(v >> 8)
dAtA[offset+2] = uint8(v >> 16)
dAtA[offset+3] = uint8(v >> 24)
dAtA[offset+4] = uint8(v >> 32)
dAtA[offset+5] = uint8(v >> 40)
dAtA[offset+6] = uint8(v >> 48)
dAtA[offset+7] = uint8(v >> 56)
return offset + 8
}
func encodeFixed32Generated(dAtA []byte, offset int, v uint32) int {
dAtA[offset] = uint8(v)
dAtA[offset+1] = uint8(v >> 8)
dAtA[offset+2] = uint8(v >> 16)
dAtA[offset+3] = uint8(v >> 24)
return offset + 4
}
func encodeVarintGenerated(dAtA []byte, offset int, v uint64) int {
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return offset + 1
}
func (m *ReplicaSet) Size() (n int) {
var l int
_ = l
l = m.ObjectMeta.Size()
n += 1 + l + sovGenerated(uint64(l))
l = m.Spec.Size()
n += 1 + l + sovGenerated(uint64(l))
l = m.Status.Size()
n += 1 + l + sovGenerated(uint64(l))
return n
}
func (m *ReplicaSetSpec) Size() (n int) {
var l int
_ = l
if m.Replicas != nil {
n += 1 + sovGenerated(uint64(*m.Replicas))
}
return n
}
func (m *ReplicaSetStatus) Size() (n int) {
var l int
_ = l
n += 1 + sovGenerated(uint64(m.Replicas))
return n
}
func sovGenerated(x uint64) (n int) {
for {
n++
x >>= 7
if x == 0 {
break
}
}
return n
}
func sozGenerated(x uint64) (n int) {
return sovGenerated(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (this *ReplicaSet) String() string {
if this == nil {
return "nil"
}
s := strings.Join([]string{`&ReplicaSet{`,
`ObjectMeta:` + strings.Replace(strings.Replace(this.ObjectMeta.String(), "ObjectMeta", "k8s_io_apimachinery_pkg_apis_meta_v1.ObjectMeta", 1), `&`, ``, 1) + `,`,
`Spec:` + strings.Replace(strings.Replace(this.Spec.String(), "ReplicaSetSpec", "ReplicaSetSpec", 1), `&`, ``, 1) + `,`,
`Status:` + strings.Replace(strings.Replace(this.Status.String(), "ReplicaSetStatus", "ReplicaSetStatus", 1), `&`, ``, 1) + `,`,
`}`,
}, "")
return s
}
func (this *ReplicaSetSpec) String() string {
if this == nil {
return "nil"
}
s := strings.Join([]string{`&ReplicaSetSpec{`,
`Replicas:` + valueToStringGenerated(this.Replicas) + `,`,
`}`,
}, "")
return s
}
func (this *ReplicaSetStatus) String() string {
if this == nil {
return "nil"
}
s := strings.Join([]string{`&ReplicaSetStatus{`,
`Replicas:` + fmt.Sprintf("%v", this.Replicas) + `,`,
`}`,
}, "")
return s
}
func valueToStringGenerated(v interface{}) string {
rv := reflect.ValueOf(v)
if rv.IsNil() {
return "nil"
}
pv := reflect.Indirect(rv).Interface()
return fmt.Sprintf("*%v", pv)
}
func (m *ReplicaSet) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: ReplicaSet: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: ReplicaSet: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ObjectMeta", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGenerated
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := m.ObjectMeta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Spec", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGenerated
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := m.Spec.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGenerated
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := m.Status.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthGenerated
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *ReplicaSetSpec) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: ReplicaSetSpec: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: ReplicaSetSpec: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Replicas", wireType)
}
var v int32
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
m.Replicas = &v
default:
iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthGenerated
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *ReplicaSetStatus) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: ReplicaSetStatus: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: ReplicaSetStatus: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Replicas", wireType)
}
m.Replicas = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Replicas |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthGenerated
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipGenerated(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGenerated
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGenerated
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
return iNdEx, nil
case 1:
iNdEx += 8
return iNdEx, nil
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGenerated
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
iNdEx += length
if length < 0 {
return 0, ErrInvalidLengthGenerated
}
return iNdEx, nil
case 3:
for {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGenerated
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
innerWire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
innerWireType := int(innerWire & 0x7)
if innerWireType == 4 {
break
}
next, err := skipGenerated(dAtA[start:])
if err != nil {
return 0, err
}
iNdEx = start + next
}
return iNdEx, nil
case 4:
return iNdEx, nil
case 5:
iNdEx += 4
return iNdEx, nil
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
}
panic("unreachable")
}
var (
ErrInvalidLengthGenerated = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowGenerated = fmt.Errorf("proto: integer overflow")
)
func init() {
proto.RegisterFile("k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/apis/example2/v1/generated.proto", fileDescriptorGenerated)
}
var fileDescriptorGenerated = []byte{
// 421 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x91, 0xcf, 0x8e, 0xd3, 0x30,
0x10, 0x87, 0x93, 0xb2, 0xac, 0x2a, 0xb3, 0x5a, 0xad, 0x72, 0xaa, 0x7a, 0x70, 0x51, 0x24, 0xa4,
0x1e, 0xc0, 0x26, 0xcb, 0x5f, 0x71, 0x42, 0xb9, 0x03, 0x52, 0xf6, 0x80, 0xc4, 0x05, 0x1c, 0x77,
0x48, 0x4d, 0x9a, 0xd8, 0xb2, 0x9d, 0x08, 0x6e, 0x3c, 0x02, 0x8f, 0xc1, 0xa3, 0xf4, 0xb8, 0xc7,
0x3d, 0x55, 0x34, 0xbc, 0x08, 0xaa, 0x13, 0x12, 0xb1, 0xed, 0x0a, 0xb8, 0xe5, 0x67, 0xcf, 0xf7,
0xcd, 0x64, 0x8c, 0x5e, 0xe7, 0xcf, 0x0d, 0x11, 0x92, 0xe6, 0x55, 0x0a, 0xba, 0x04, 0x0b, 0x86,
0xd6, 0x50, 0x2e, 0xa4, 0xa6, 0xdd, 0x05, 0x53, 0xc2, 0x80, 0xae, 0x41, 0x53, 0x95, 0x67, 0x2e,
0x51, 0xf8, 0xcc, 0x0a, 0xb5, 0x82, 0x73, 0x5a, 0x47, 0x34, 0x83, 0x12, 0x34, 0xb3, 0xb0, 0x20,
0x4a, 0x4b, 0x2b, 0x83, 0x7b, 0x2d, 0x46, 0x7a, 0x8c, 0xa8, 0x3c, 0x73, 0x89, 0xfc, 0xc6, 0x48,
0x1d, 0x4d, 0x1f, 0x64, 0xc2, 0x2e, 0xab, 0x94, 0x70, 0x59, 0xd0, 0x4c, 0x66, 0x92, 0x3a, 0x3a,
0xad, 0x3e, 0xba, 0xe4, 0x82, 0xfb, 0x6a, 0xad, 0xd3, 0x70, 0x18, 0x86, 0x72, 0xa9, 0xe1, 0x40,
0xe7, 0xe9, 0xe3, 0xa1, 0xa6, 0x60, 0x7c, 0x29, 0x4a, 0xd0, 0x5f, 0x86, 0x99, 0x0b, 0xb0, 0xec,
0x10, 0x45, 0x6f, 0xa2, 0x74, 0x55, 0x5a, 0x51, 0xc0, 0x1e, 0xf0, 0xf4, 0x6f, 0x80, 0xe1, 0x4b,
0x28, 0xd8, 0x1e, 0xf7, 0xe8, 0x26, 0xae, 0xb2, 0x62, 0x45, 0x45, 0x69, 0x8d, 0xd5, 0xd7, 0xa1,
0xf0, 0xfb, 0x08, 0xa1, 0x04, 0xd4, 0x4a, 0x70, 0x76, 0x01, 0x36, 0xf8, 0x80, 0xc6, 0xbb, 0xff,
0x58, 0x30, 0xcb, 0x26, 0xfe, 0x5d, 0x7f, 0x7e, 0xe7, 0xfc, 0x21, 0x19, 0xf6, 0xdd, 0x6b, 0x87,
0x95, 0xef, 0xaa, 0x49, 0x1d, 0x91, 0x37, 0xe9, 0x27, 0xe0, 0xf6, 0x15, 0x58, 0x16, 0x07, 0xeb,
0xcd, 0xcc, 0x6b, 0x36, 0x33, 0x34, 0x9c, 0x25, 0xbd, 0x35, 0x78, 0x8b, 0x8e, 0x8c, 0x02, 0x3e,
0x19, 0x39, 0xfb, 0x13, 0xf2, 0x4f, 0xaf, 0x49, 0x86, 0x11, 0x2f, 0x14, 0xf0, 0xf8, 0xa4, 0x6b,
0x71, 0xb4, 0x4b, 0x89, 0x13, 0x06, 0xef, 0xd1, 0xb1, 0xb1, 0xcc, 0x56, 0x66, 0x72, 0xcb, 0xa9,
0x9f, 0xfd, 0xbf, 0xda, 0xe1, 0xf1, 0x69, 0x27, 0x3f, 0x6e, 0x73, 0xd2, 0x69, 0xc3, 0x17, 0xe8,
0xf4, 0xcf, 0x31, 0x82, 0x39, 0x1a, 0xeb, 0xf6, 0xc4, 0xb8, 0x6d, 0xdd, 0x8e, 0x4f, 0x9a, 0xcd,
0x6c, 0xdc, 0x55, 0x99, 0xa4, 0xbf, 0x0d, 0x5f, 0xa2, 0xb3, 0xeb, 0x7d, 0x82, 0xfb, 0x7b, 0xf4,
0x59, 0xd7, 0xf9, 0x80, 0x21, 0x9e, 0xaf, 0xb7, 0xd8, 0xbb, 0xdc, 0x62, 0xef, 0x6a, 0x8b, 0xbd,
0xaf, 0x0d, 0xf6, 0xd7, 0x0d, 0xf6, 0x2f, 0x1b, 0xec, 0x5f, 0x35, 0xd8, 0xff, 0xd1, 0x60, 0xff,
0xdb, 0x4f, 0xec, 0xbd, 0x1b, 0xd5, 0xd1, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x69, 0x4a, 0x84,
0xe4, 0x71, 0x03, 0x00, 0x00,
}

View File

@ -0,0 +1,71 @@
/*
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.
*/
// This file was autogenerated by go-to-protobuf. Do not edit it manually!
syntax = 'proto2';
package k8s.io.apiserver.pkg.apis.example2.v1;
import "k8s.io/api/core/v1/generated.proto";
import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto";
import "k8s.io/apimachinery/pkg/runtime/generated.proto";
import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto";
import "k8s.io/apimachinery/pkg/util/intstr/generated.proto";
// Package-wide variables from generator "generated".
option go_package = "v1";
// ReplicaSet ensures that a specified number of pod replicas are running at any given time.
message ReplicaSet {
// If the Labels of a ReplicaSet are empty, they are defaulted to
// be the same as the Pod(s) that the ReplicaSet manages.
// Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
// +optional
optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1;
// Spec defines the specification of the desired behavior of the ReplicaSet.
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
// +optional
optional ReplicaSetSpec spec = 2;
// Status is the most recently observed status of the ReplicaSet.
// This data may be out of date by some window of time.
// Populated by the system.
// Read-only.
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
// +optional
optional ReplicaSetStatus status = 3;
}
// ReplicaSetSpec is the specification of a ReplicaSet.
message ReplicaSetSpec {
// Replicas is the number of desired replicas.
// This is a pointer to distinguish between explicit zero and unspecified.
// Defaults to 1.
// More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller/#what-is-a-replicationcontroller
// +optional
optional int32 replicas = 1;
}
// ReplicaSetStatus represents the current status of a ReplicaSet.
message ReplicaSetStatus {
// Replicas is the most recently oberved number of replicas.
// More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller/#what-is-a-replicationcontroller
optional int32 replicas = 1;
}

View File

@ -0,0 +1,63 @@
/*
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 v1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// GroupName is the group name use in this package
const GroupName = "example2.apiserver.k8s.io"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"}
// Kind takes an unqualified kind and returns a Group qualified GroupKind
func Kind(kind string) schema.GroupKind {
return SchemeGroupVersion.WithKind(kind).GroupKind()
}
// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
var (
// TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api.
// localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes.
SchemeBuilder runtime.SchemeBuilder
localSchemeBuilder = &SchemeBuilder
AddToScheme = localSchemeBuilder.AddToScheme
)
func init() {
// We only register manually written functions here. The registration of the
// generated functions takes place in the generated files. The separation
// makes the code compile even when the generated files are missing.
localSchemeBuilder.Register(addKnownTypes, addConversionFuncs, addDefaultingFuncs)
}
// Adds the list of known types to the given scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&ReplicaSet{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
}

View File

@ -0,0 +1,64 @@
/*
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 v1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// ReplicaSet ensures that a specified number of pod replicas are running at any given time.
type ReplicaSet struct {
metav1.TypeMeta `json:",inline"`
// If the Labels of a ReplicaSet are empty, they are defaulted to
// be the same as the Pod(s) that the ReplicaSet manages.
// Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
// +optional
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
// Spec defines the specification of the desired behavior of the ReplicaSet.
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
// +optional
Spec ReplicaSetSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
// Status is the most recently observed status of the ReplicaSet.
// This data may be out of date by some window of time.
// Populated by the system.
// Read-only.
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
// +optional
Status ReplicaSetStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}
// ReplicaSetSpec is the specification of a ReplicaSet.
type ReplicaSetSpec struct {
// Replicas is the number of desired replicas.
// This is a pointer to distinguish between explicit zero and unspecified.
// Defaults to 1.
// More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller/#what-is-a-replicationcontroller
// +optional
Replicas *int32 `json:"replicas,omitempty" protobuf:"varint,1,opt,name=replicas"`
}
// ReplicaSetStatus represents the current status of a ReplicaSet.
type ReplicaSetStatus struct {
// Replicas is the most recently oberved number of replicas.
// More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller/#what-is-a-replicationcontroller
Replicas int32 `json:"replicas" protobuf:"varint,1,opt,name=replicas"`
}

View File

@ -0,0 +1,17 @@
/*
Copyright 2016 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 v1

View File

@ -0,0 +1,111 @@
// +build !ignore_autogenerated
/*
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.
*/
// This file was autogenerated by conversion-gen. Do not edit it manually!
package v1
import (
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime"
example "k8s.io/apiserver/pkg/apis/example"
)
func init() {
localSchemeBuilder.Register(RegisterConversions)
}
// RegisterConversions adds conversion functions to the given scheme.
// Public to allow building arbitrary schemes.
func RegisterConversions(scheme *runtime.Scheme) error {
return scheme.AddGeneratedConversionFuncs(
Convert_v1_ReplicaSet_To_example_ReplicaSet,
Convert_example_ReplicaSet_To_v1_ReplicaSet,
Convert_v1_ReplicaSetSpec_To_example_ReplicaSetSpec,
Convert_example_ReplicaSetSpec_To_v1_ReplicaSetSpec,
Convert_v1_ReplicaSetStatus_To_example_ReplicaSetStatus,
Convert_example_ReplicaSetStatus_To_v1_ReplicaSetStatus,
)
}
func autoConvert_v1_ReplicaSet_To_example_ReplicaSet(in *ReplicaSet, out *example.ReplicaSet, s conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
if err := Convert_v1_ReplicaSetSpec_To_example_ReplicaSetSpec(&in.Spec, &out.Spec, s); err != nil {
return err
}
if err := Convert_v1_ReplicaSetStatus_To_example_ReplicaSetStatus(&in.Status, &out.Status, s); err != nil {
return err
}
return nil
}
// Convert_v1_ReplicaSet_To_example_ReplicaSet is an autogenerated conversion function.
func Convert_v1_ReplicaSet_To_example_ReplicaSet(in *ReplicaSet, out *example.ReplicaSet, s conversion.Scope) error {
return autoConvert_v1_ReplicaSet_To_example_ReplicaSet(in, out, s)
}
func autoConvert_example_ReplicaSet_To_v1_ReplicaSet(in *example.ReplicaSet, out *ReplicaSet, s conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
if err := Convert_example_ReplicaSetSpec_To_v1_ReplicaSetSpec(&in.Spec, &out.Spec, s); err != nil {
return err
}
if err := Convert_example_ReplicaSetStatus_To_v1_ReplicaSetStatus(&in.Status, &out.Status, s); err != nil {
return err
}
return nil
}
// Convert_example_ReplicaSet_To_v1_ReplicaSet is an autogenerated conversion function.
func Convert_example_ReplicaSet_To_v1_ReplicaSet(in *example.ReplicaSet, out *ReplicaSet, s conversion.Scope) error {
return autoConvert_example_ReplicaSet_To_v1_ReplicaSet(in, out, s)
}
func autoConvert_v1_ReplicaSetSpec_To_example_ReplicaSetSpec(in *ReplicaSetSpec, out *example.ReplicaSetSpec, s conversion.Scope) error {
if err := meta_v1.Convert_Pointer_int32_To_int32(&in.Replicas, &out.Replicas, s); err != nil {
return err
}
return nil
}
func autoConvert_example_ReplicaSetSpec_To_v1_ReplicaSetSpec(in *example.ReplicaSetSpec, out *ReplicaSetSpec, s conversion.Scope) error {
if err := meta_v1.Convert_int32_To_Pointer_int32(&in.Replicas, &out.Replicas, s); err != nil {
return err
}
return nil
}
func autoConvert_v1_ReplicaSetStatus_To_example_ReplicaSetStatus(in *ReplicaSetStatus, out *example.ReplicaSetStatus, s conversion.Scope) error {
out.Replicas = in.Replicas
return nil
}
// Convert_v1_ReplicaSetStatus_To_example_ReplicaSetStatus is an autogenerated conversion function.
func Convert_v1_ReplicaSetStatus_To_example_ReplicaSetStatus(in *ReplicaSetStatus, out *example.ReplicaSetStatus, s conversion.Scope) error {
return autoConvert_v1_ReplicaSetStatus_To_example_ReplicaSetStatus(in, out, s)
}
func autoConvert_example_ReplicaSetStatus_To_v1_ReplicaSetStatus(in *example.ReplicaSetStatus, out *ReplicaSetStatus, s conversion.Scope) error {
out.Replicas = in.Replicas
return nil
}
// Convert_example_ReplicaSetStatus_To_v1_ReplicaSetStatus is an autogenerated conversion function.
func Convert_example_ReplicaSetStatus_To_v1_ReplicaSetStatus(in *example.ReplicaSetStatus, out *ReplicaSetStatus, s conversion.Scope) error {
return autoConvert_example_ReplicaSetStatus_To_v1_ReplicaSetStatus(in, out, s)
}

View File

@ -0,0 +1,95 @@
// +build !ignore_autogenerated
/*
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.
*/
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
package v1
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ReplicaSet) DeepCopyInto(out *ReplicaSet) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
out.Status = in.Status
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReplicaSet.
func (in *ReplicaSet) DeepCopy() *ReplicaSet {
if in == nil {
return nil
}
out := new(ReplicaSet)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *ReplicaSet) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
} else {
return nil
}
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ReplicaSetSpec) DeepCopyInto(out *ReplicaSetSpec) {
*out = *in
if in.Replicas != nil {
in, out := &in.Replicas, &out.Replicas
if *in == nil {
*out = nil
} else {
*out = new(int32)
**out = **in
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReplicaSetSpec.
func (in *ReplicaSetSpec) DeepCopy() *ReplicaSetSpec {
if in == nil {
return nil
}
out := new(ReplicaSetSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ReplicaSetStatus) DeepCopyInto(out *ReplicaSetStatus) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReplicaSetStatus.
func (in *ReplicaSetStatus) DeepCopy() *ReplicaSetStatus {
if in == nil {
return nil
}
out := new(ReplicaSetStatus)
in.DeepCopyInto(out)
return out
}

View File

@ -0,0 +1,32 @@
// +build !ignore_autogenerated
/*
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.
*/
// This file was autogenerated by defaulter-gen. Do not edit it manually!
package v1
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// RegisterDefaults adds defaulters functions to the given scheme.
// Public to allow building arbitrary schemes.
// All generated defaulters are covering - they call all nested defaulters.
func RegisterDefaults(scheme *runtime.Scheme) error {
return nil
}

View File

@ -0,0 +1,21 @@
// +build !ignore_autogenerated
/*
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.
*/
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
package example2

View File

@ -60,6 +60,7 @@ go_library(
"//vendor/k8s.io/apiserver/pkg/authentication/user:go_default_library",
"//vendor/k8s.io/apiserver/pkg/storage/names:go_default_library",
"//vendor/k8s.io/client-go/discovery:go_default_library",
"//vendor/k8s.io/client-go/dynamic:go_default_library",
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
"//vendor/k8s.io/client-go/util/cert:go_default_library",
"//vendor/k8s.io/client-go/util/retry:go_default_library",

View File

@ -24,10 +24,15 @@ import (
"k8s.io/api/core/v1"
extensions "k8s.io/api/extensions/v1beta1"
rbacv1beta1 "k8s.io/api/rbac/v1beta1"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
crdclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
"k8s.io/apiextensions-apiserver/test/integration/testserver"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/dynamic"
utilversion "k8s.io/kubernetes/pkg/util/version"
"k8s.io/kubernetes/test/e2e/framework"
@ -47,6 +52,11 @@ const (
skippedNamespaceName = "exempted-namesapce"
disallowedPodName = "disallowed-pod"
disallowedConfigMapName = "disallowed-configmap"
crdName = "e2e-test-webhook-crd"
crdKind = "E2e-test-webhook-crd"
crdWebhookConfigName = "e2e-test-webhook-config-crd"
crdAPIGroup = "webhook-crd-test.k8s.io"
crdAPIVersion = "v1"
)
var serverWebhookVersion = utilversion.MustParseSemantic("v1.8.0")
@ -60,7 +70,7 @@ var _ = SIGDescribe("AdmissionWebhook", func() {
It("Should be able to deny pod and configmap creation", func() {
// Make sure the relevant provider supports admission webhook
framework.SkipUnlessServerVersionGTE(serverWebhookVersion, f.ClientSet.Discovery())
framework.SkipUnlessProviderIs("gce", "gke")
framework.SkipUnlessProviderIs("gce", "gke", "local")
_, err := f.ClientSet.AdmissionregistrationV1alpha1().ValidatingWebhookConfigurations().List(metav1.ListOptions{})
if errors.IsNotFound(err) {
@ -74,10 +84,29 @@ var _ = SIGDescribe("AdmissionWebhook", func() {
// Note that in 1.9 we will have backwards incompatible change to
// admission webhooks, so the image will be updated to 1.9 sometime in
// the development 1.9 cycle.
deployWebhookAndService(f, "gcr.io/kubernetes-e2e-test-images/k8s-sample-admission-webhook-amd64:1.8v2", context)
deployWebhookAndService(f, "gcr.io/kubernetes-e2e-test-images/k8s-sample-admission-webhook-amd64:1.8v3", context)
registerWebhook(f, context)
testWebhook(f)
})
It("Should be able to deny custom resource creation", func() {
// Make sure the relevant provider supports admission webhook
framework.SkipUnlessServerVersionGTE(serverWebhookVersion, f.ClientSet.Discovery())
framework.SkipUnlessProviderIs("gce", "gke", "local")
_, err := f.ClientSet.AdmissionregistrationV1alpha1().ValidatingWebhookConfigurations().List(metav1.ListOptions{})
if errors.IsNotFound(err) {
framework.Skipf("dynamic configuration of webhooks requires the alpha admissionregistration.k8s.io group to be enabled")
}
By("Setting up server cert")
namespaceName := f.Namespace.Name
context := setupServerCert(namespaceName, serviceName)
createAuthReaderRoleBinding(f, namespaceName)
deployWebhookAndService(f, "gcr.io/kubernetes-e2e-test-images/k8s-sample-admission-webhook-amd64:1.8v3", context)
crdCleanup, dynamicClient := createCRD(f)
defer crdCleanup()
registerWebhookForCRD(f, context)
testCRDWebhook(f, dynamicClient)
})
})
func createAuthReaderRoleBinding(f *framework.Framework, namespace string) {
@ -105,12 +134,15 @@ func createAuthReaderRoleBinding(f *framework.Framework, namespace string) {
},
},
})
framework.ExpectNoError(err, "creating role binding %s:webhook to access configMap", namespace)
if err != nil && errors.IsAlreadyExists(err) {
framework.Logf("role binding %s already exists", roleBindingName)
} else {
framework.ExpectNoError(err, "creating role binding %s:webhook to access configMap", namespace)
}
}
func deployWebhookAndService(f *framework.Framework, image string, context *certContext) {
By("Deploying the webhook pod")
client := f.ClientSet
// Creating the secret that contains the webhook's cert.
@ -283,7 +315,7 @@ func registerWebhook(f *framework.Framework, context *certContext) {
framework.ExpectNoError(err, "registering webhook config %s with namespace %s", webhookConfigName, namespace)
// The webhook configuration is honored in 1s.
time.Sleep(2 * time.Second)
time.Sleep(10 * time.Second)
}
func testWebhook(f *framework.Framework) {
@ -293,20 +325,21 @@ func testWebhook(f *framework.Framework) {
pod := nonCompliantPod(f)
_, err := client.CoreV1().Pods(f.Namespace.Name).Create(pod)
Expect(err).NotTo(BeNil())
expectedErrMsg := "the pod contains unwanted container name"
if !strings.Contains(err.Error(), expectedErrMsg) {
framework.Failf("expect error contains %q, got %q", expectedErrMsg, err.Error())
expectedErrMsg1 := "the pod contains unwanted container name"
if !strings.Contains(err.Error(), expectedErrMsg1) {
framework.Failf("expect error contains %q, got %q", expectedErrMsg1, err.Error())
}
expectedErrMsg2 := "the pod contains unwanted label"
if !strings.Contains(err.Error(), expectedErrMsg2) {
framework.Failf("expect error contains %q, got %q", expectedErrMsg2, err.Error())
}
// TODO: Test if webhook can detect pod with non-compliant metadata.
// Currently metadata is lost because webhook uses the external version of
// the objects, and the apiserver sends the internal objects.
By("create a configmap that should be denied by the webhook")
// Creating the configmap, the request should be rejected
configmap := nonCompliantConfigMap(f)
_, err = client.CoreV1().ConfigMaps(f.Namespace.Name).Create(configmap)
Expect(err).NotTo(BeNil())
expectedErrMsg = "the configmap contains unwanted key and value"
expectedErrMsg := "the configmap contains unwanted key and value"
if !strings.Contains(err.Error(), expectedErrMsg) {
framework.Failf("expect error contains %q, got %q", expectedErrMsg, err.Error())
}
@ -340,7 +373,7 @@ func nonCompliantPod(f *framework.Framework) *v1.Pod {
ObjectMeta: metav1.ObjectMeta{
Name: disallowedPodName,
Labels: map[string]string{
"webhook-e2e-test": "disallow",
"webhook-e2e-test": "webhook-disallow",
},
},
Spec: v1.PodSpec{
@ -368,6 +401,7 @@ func nonCompliantConfigMap(f *framework.Framework) *v1.ConfigMap {
func cleanWebhookTest(f *framework.Framework) {
client := f.ClientSet
_ = client.AdmissionregistrationV1alpha1().ValidatingWebhookConfigurations().Delete(webhookConfigName, nil)
_ = client.AdmissionregistrationV1alpha1().ValidatingWebhookConfigurations().Delete(crdWebhookConfigName, nil)
namespaceName := f.Namespace.Name
_ = client.CoreV1().Services(namespaceName).Delete(serviceName, nil)
_ = client.ExtensionsV1beta1().Deployments(namespaceName).Delete(deploymentName, nil)
@ -376,3 +410,114 @@ func cleanWebhookTest(f *framework.Framework) {
_ = client.CoreV1().ConfigMaps(skippedNamespaceName).Delete(disallowedConfigMapName, nil)
_ = client.CoreV1().Namespaces().Delete(skippedNamespaceName, nil)
}
// newCRDForAdmissionWebhookTest generates a CRD
func newCRDForAdmissionWebhookTest() *apiextensionsv1beta1.CustomResourceDefinition {
return &apiextensionsv1beta1.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: crdName + "s." + crdAPIGroup},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: crdAPIGroup,
Version: crdAPIVersion,
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Plural: crdName + "s",
Singular: crdName,
Kind: crdKind,
ListKind: crdName + "List",
},
Scope: apiextensionsv1beta1.NamespaceScoped,
},
}
}
func createCRD(f *framework.Framework) (func(), dynamic.ResourceInterface) {
config, err := framework.LoadConfig()
if err != nil {
framework.Failf("failed to load config: %v", err)
}
apiExtensionClient, err := crdclientset.NewForConfig(config)
if err != nil {
framework.Failf("failed to initialize apiExtensionClient: %v", err)
}
crd := newCRDForAdmissionWebhookTest()
//create CRD and waits for the resource to be recognized and available.
dynamicClient, err := testserver.CreateNewCustomResourceDefinitionWatchUnsafe(crd, apiExtensionClient, f.ClientPool)
if err != nil {
framework.Failf("failed to create CustomResourceDefinition: %v", err)
}
resourceClient := dynamicClient.Resource(&metav1.APIResource{
Name: crd.Spec.Names.Plural,
Namespaced: true,
}, f.Namespace.Name)
return func() {
err = testserver.DeleteCustomResourceDefinition(crd, apiExtensionClient)
if err != nil {
framework.Failf("failed to delete CustomResourceDefinition: %v", err)
}
}, resourceClient
}
func registerWebhookForCRD(f *framework.Framework, context *certContext) {
client := f.ClientSet
By("Registering the crd webhook via the AdmissionRegistration API")
namespace := f.Namespace.Name
_, err := client.AdmissionregistrationV1alpha1().ValidatingWebhookConfigurations().Create(&v1alpha1.ValidatingWebhookConfiguration{
ObjectMeta: metav1.ObjectMeta{
Name: crdWebhookConfigName,
},
Webhooks: []v1alpha1.Webhook{
{
Name: "deny-unwanted-crd-data.k8s.io",
Rules: []v1alpha1.RuleWithOperations{{
Operations: []v1alpha1.OperationType{v1alpha1.Create},
Rule: v1alpha1.Rule{
APIGroups: []string{crdAPIGroup},
APIVersions: []string{crdAPIVersion},
Resources: []string{crdName + "s"},
},
}},
ClientConfig: v1alpha1.WebhookClientConfig{
Service: &v1alpha1.ServiceReference{
Namespace: namespace,
Name: serviceName,
Path: strPtr("/crd"),
},
CABundle: context.signingCert,
},
},
},
})
framework.ExpectNoError(err, "registering crd webhook config %s with namespace %s", webhookConfigName, namespace)
// The webhook configuration is honored in 1s.
time.Sleep(10 * time.Second)
}
func testCRDWebhook(f *framework.Framework, crdClient dynamic.ResourceInterface) {
By("Creating a custom resource that should be denied by the webhook")
crd := newCRDForAdmissionWebhookTest()
crInstance := &unstructured.Unstructured{
Object: map[string]interface{}{
"kind": crd.Spec.Names.Kind,
"apiVersion": crd.Spec.Group + "/" + crd.Spec.Version,
"metadata": map[string]interface{}{
"name": "cr-instance-1",
"namespace": f.Namespace.Name,
},
"data": map[string]interface{}{
"webhook-e2e-test": "webhook-disallow",
},
},
}
_, err := crdClient.Create(crInstance)
Expect(err).NotTo(BeNil())
expectedErrMsg := "the custom resource contains unwanted data"
if !strings.Contains(err.Error(), expectedErrMsg) {
framework.Failf("expect error contains %q, got %q", expectedErrMsg, err.Error())
}
}

View File

@ -5,14 +5,18 @@ go_library(
srcs = [
"config.go",
"main.go",
"scheme.go",
],
importpath = "k8s.io/kubernetes/test/images/webhook",
visibility = ["//visibility:private"],
deps = [
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/api/admission/v1alpha1:go_default_library",
"//vendor/k8s.io/api/admissionregistration/v1alpha1:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
"//vendor/k8s.io/client-go/rest:go_default_library",
],

View File

@ -14,6 +14,7 @@
build:
CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o webhook .
docker build --no-cache -t gcr.io/kubernetes-e2e-test-images/k8s-sample-admission-webhook-amd64:1.8v2 .
docker build --no-cache -t gcr.io/kubernetes-e2e-test-images/k8s-sample-admission-webhook-amd64:1.8v3 .
rm -rf webhook
push:
gcloud docker -- push gcr.io/kubernetes-e2e-test-images/k8s-sample-admission-webhook-amd64:1.8v2
gcloud docker -- push gcr.io/kubernetes-e2e-test-images/k8s-sample-admission-webhook-amd64:1.8v3

View File

@ -19,13 +19,14 @@ package main
import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"net/http"
"strings"
"github.com/golang/glog"
"k8s.io/api/admission/v1alpha1"
"k8s.io/api/core/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@ -43,58 +44,56 @@ func (c *Config) addFlags() {
"File containing the default x509 private key matching --tls-cert-file.")
}
// only allow pods to pull images from specific registry.
func admitPods(data []byte) *v1alpha1.AdmissionReviewStatus {
glog.V(2).Info("admitting pods")
ar := v1alpha1.AdmissionReview{}
if err := json.Unmarshal(data, &ar); err != nil {
glog.Error(err)
return nil
func toAdmissionReviewStatus(err error) *v1alpha1.AdmissionReviewStatus {
return &v1alpha1.AdmissionReviewStatus{
Result: &metav1.Status{
Message: err.Error(),
},
}
}
// only allow pods to pull images from specific registry.
func admitPods(ar v1alpha1.AdmissionReview) *v1alpha1.AdmissionReviewStatus {
glog.V(2).Info("admitting pods")
podResource := metav1.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}
if ar.Spec.Resource != podResource {
glog.Errorf("expect resource to be %s", podResource)
return nil
err := fmt.Errorf("expect resource to be %s", podResource)
glog.Error(err)
return toAdmissionReviewStatus(err)
}
raw := ar.Spec.Object.Raw
pod := v1.Pod{}
if err := json.Unmarshal(raw, &pod); err != nil {
pod := corev1.Pod{}
deserializer := codecs.UniversalDeserializer()
if _, _, err := deserializer.Decode(raw, nil, &pod); err != nil {
glog.Error(err)
return nil
return toAdmissionReviewStatus(err)
}
reviewStatus := v1alpha1.AdmissionReviewStatus{}
reviewStatus.Allowed = true
// Note: the apiserver encodes the api.Pod. Decoding it as a v1.Pod will
// lose the metadata. So the following check on labels will not work
// until we let the apiserver encodes the versioned object.
var msg string
for k, v := range pod.Labels {
if k == "webhook-e2e-test" && v == "webhook-disallow" {
reviewStatus.Allowed = false
reviewStatus.Result = &metav1.Status{
Reason: "the pod contains unwanted label",
}
msg = msg + "the pod contains unwanted label; "
}
}
for _, container := range pod.Spec.Containers {
if strings.Contains(container.Name, "webhook-disallow") {
reviewStatus.Allowed = false
reviewStatus.Result = &metav1.Status{
Message: "the pod contains unwanted container name",
}
msg = msg + "the pod contains unwanted container name; "
}
}
if !reviewStatus.Allowed {
reviewStatus.Result = &metav1.Status{Message: strings.TrimSpace(msg)}
}
return &reviewStatus
}
// deny configmaps with specific key-value pair.
func admitConfigMaps(data []byte) *v1alpha1.AdmissionReviewStatus {
func admitConfigMaps(ar v1alpha1.AdmissionReview) *v1alpha1.AdmissionReviewStatus {
glog.V(2).Info("admitting configmaps")
ar := v1alpha1.AdmissionReview{}
if err := json.Unmarshal(data, &ar); err != nil {
glog.Error(err)
return nil
}
configMapResource := metav1.GroupVersionResource{Group: "", Version: "v1", Resource: "configmaps"}
if ar.Spec.Resource != configMapResource {
glog.Errorf("expect resource to be %s", configMapResource)
@ -102,10 +101,11 @@ func admitConfigMaps(data []byte) *v1alpha1.AdmissionReviewStatus {
}
raw := ar.Spec.Object.Raw
configmap := v1.ConfigMap{}
if err := json.Unmarshal(raw, &configmap); err != nil {
configmap := corev1.ConfigMap{}
deserializer := codecs.UniversalDeserializer()
if _, _, err := deserializer.Decode(raw, nil, &configmap); err != nil {
glog.Error(err)
return nil
return toAdmissionReviewStatus(err)
}
reviewStatus := v1alpha1.AdmissionReviewStatus{}
reviewStatus.Allowed = true
@ -120,7 +120,34 @@ func admitConfigMaps(data []byte) *v1alpha1.AdmissionReviewStatus {
return &reviewStatus
}
type admitFunc func(data []byte) *v1alpha1.AdmissionReviewStatus
func admitCRD(ar v1alpha1.AdmissionReview) *v1alpha1.AdmissionReviewStatus {
glog.V(2).Info("admitting crd")
cr := struct {
metav1.ObjectMeta
Data map[string]string
}{}
raw := ar.Spec.Object.Raw
err := json.Unmarshal(raw, &cr)
if err != nil {
glog.Error(err)
return toAdmissionReviewStatus(err)
}
reviewStatus := v1alpha1.AdmissionReviewStatus{}
reviewStatus.Allowed = true
for k, v := range cr.Data {
if k == "webhook-e2e-test" && v == "webhook-disallow" {
reviewStatus.Allowed = false
reviewStatus.Result = &metav1.Status{
Reason: "the custom resource contains unwanted data",
}
}
}
return &reviewStatus
}
type admitFunc func(v1alpha1.AdmissionReview) *v1alpha1.AdmissionReviewStatus
func serve(w http.ResponseWriter, r *http.Request, admit admitFunc) {
var body []byte
@ -137,9 +164,16 @@ func serve(w http.ResponseWriter, r *http.Request, admit admitFunc) {
return
}
reviewStatus := admit(body)
var reviewStatus *v1alpha1.AdmissionReviewStatus
ar := v1alpha1.AdmissionReview{}
deserializer := codecs.UniversalDeserializer()
if _, _, err := deserializer.Decode(body, nil, &ar); err != nil {
glog.Error(err)
reviewStatus = toAdmissionReviewStatus(err)
} else {
reviewStatus = admit(ar)
}
if reviewStatus != nil {
ar.Status = *reviewStatus
}
@ -156,10 +190,15 @@ func serve(w http.ResponseWriter, r *http.Request, admit admitFunc) {
func servePods(w http.ResponseWriter, r *http.Request) {
serve(w, r, admitPods)
}
func serveConfigmaps(w http.ResponseWriter, r *http.Request) {
serve(w, r, admitConfigMaps)
}
func serveCRD(w http.ResponseWriter, r *http.Request) {
serve(w, r, admitCRD)
}
func main() {
var config Config
config.addFlags()
@ -167,6 +206,7 @@ func main() {
http.HandleFunc("/pods", servePods)
http.HandleFunc("/configmaps", serveConfigmaps)
http.HandleFunc("/crd", serveCRD)
clientset := getClient()
server := &http.Server{
Addr: ":443",

View File

@ -0,0 +1,36 @@
/*
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 main
import (
admissionregistrationv1alpha1 "k8s.io/api/admissionregistration/v1alpha1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
)
var scheme = runtime.NewScheme()
var codecs = serializer.NewCodecFactory(scheme)
func init() {
addToScheme(scheme)
}
func addToScheme(scheme *runtime.Scheme) {
corev1.AddToScheme(scheme)
admissionregistrationv1alpha1.AddToScheme(scheme)
}