Unverified Commit 716344fd authored by Kubernetes Prow Robot's avatar Kubernetes Prow Robot Committed by GitHub

Merge pull request #76849 from liggitt/crd_webhook_integration_tests

Fix scale and rollback subresources with admission webhooks, add integration tests
parents dc395391 69042da9
......@@ -158,24 +158,27 @@ func (r *RollbackREST) New() runtime.Object {
return &apps.DeploymentRollback{}
}
var _ = rest.Creater(&RollbackREST{})
var _ = rest.NamedCreater(&RollbackREST{})
func (r *RollbackREST) Create(ctx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) {
func (r *RollbackREST) Create(ctx context.Context, name string, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) {
rollback, ok := obj.(*apps.DeploymentRollback)
if !ok {
return nil, errors.NewBadRequest(fmt.Sprintf("not a DeploymentRollback: %#v", obj))
}
if errs := appsvalidation.ValidateDeploymentRollback(rollback); len(errs) != 0 {
return nil, errors.NewInvalid(apps.Kind("DeploymentRollback"), rollback.Name, errs)
}
if name != rollback.Name {
return nil, errors.NewBadRequest("name in URL does not match name in DeploymentRollback object")
}
if createValidation != nil {
if err := createValidation(obj.DeepCopyObject()); err != nil {
return nil, err
}
}
if errs := appsvalidation.ValidateDeploymentRollback(rollback); len(errs) != 0 {
return nil, errors.NewInvalid(apps.Kind("DeploymentRollback"), rollback.Name, errs)
}
// Update the Deployment with information in DeploymentRollback to trigger rollback
err := r.rollbackDeployment(ctx, rollback.Name, &rollback.RollbackTo, rollback.UpdatedAnnotations, dryrun.IsDryRun(options.DryRun))
if err != nil {
......@@ -293,7 +296,15 @@ func (r *ScaleREST) Update(ctx context.Context, name string, objInfo rest.Update
deployment.Spec.Replicas = scale.Spec.Replicas
deployment.ResourceVersion = scale.ResourceVersion
obj, _, err = r.store.Update(ctx, deployment.Name, rest.DefaultUpdatedObjectInfo(deployment), createValidation, updateValidation, false, options)
obj, _, err = r.store.Update(
ctx,
deployment.Name,
rest.DefaultUpdatedObjectInfo(deployment),
toScaleCreateValidation(createValidation),
toScaleUpdateValidation(updateValidation),
false,
options,
)
if err != nil {
return nil, false, err
}
......@@ -305,6 +316,30 @@ func (r *ScaleREST) Update(ctx context.Context, name string, objInfo rest.Update
return newScale, false, nil
}
func toScaleCreateValidation(f rest.ValidateObjectFunc) rest.ValidateObjectFunc {
return func(obj runtime.Object) error {
scale, err := scaleFromDeployment(obj.(*apps.Deployment))
if err != nil {
return err
}
return f(scale)
}
}
func toScaleUpdateValidation(f rest.ValidateObjectUpdateFunc) rest.ValidateObjectUpdateFunc {
return func(obj, old runtime.Object) error {
newScale, err := scaleFromDeployment(obj.(*apps.Deployment))
if err != nil {
return err
}
oldScale, err := scaleFromDeployment(old.(*apps.Deployment))
if err != nil {
return err
}
return f(newScale, oldScale)
}
}
// scaleFromDeployment returns a scale subresource for a deployment.
func scaleFromDeployment(deployment *apps.Deployment) (*autoscaling.Scale, error) {
selector, err := metav1.LabelSelectorAsSelector(deployment.Spec.Selector)
......
......@@ -351,7 +351,7 @@ func TestEtcdCreateDeploymentRollback(t *testing.T) {
if _, err := storage.Deployment.Create(ctx, validNewDeployment(), rest.ValidateAllObjectFunc, &metav1.CreateOptions{}); err != nil {
t.Fatalf("%s: unexpected error: %v", k, err)
}
rollbackRespStatus, err := rollbackStorage.Create(ctx, &test.rollback, rest.ValidateAllObjectFunc, &metav1.CreateOptions{})
rollbackRespStatus, err := rollbackStorage.Create(ctx, test.rollback.Name, &test.rollback, rest.ValidateAllObjectFunc, &metav1.CreateOptions{})
if !test.errOK(err) {
t.Errorf("%s: unexpected error: %v", k, err)
} else if err == nil {
......@@ -392,7 +392,7 @@ func TestCreateDeploymentRollbackValidation(t *testing.T) {
validationError := fmt.Errorf("admission deny")
alwaysDenyValidationFunc := func(obj runtime.Object) error { return validationError }
_, err := rollbackStorage.Create(ctx, &rollback, alwaysDenyValidationFunc, &metav1.CreateOptions{})
_, err := rollbackStorage.Create(ctx, rollback.Name, &rollback, alwaysDenyValidationFunc, &metav1.CreateOptions{})
if err == nil || validationError != err {
t.Errorf("expected: %v, got: %v", validationError, err)
......@@ -411,7 +411,7 @@ func TestEtcdCreateDeploymentRollbackNoDeployment(t *testing.T) {
rollbackStorage := storage.Rollback
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), namespace)
_, err := rollbackStorage.Create(ctx, &apps.DeploymentRollback{
_, err := rollbackStorage.Create(ctx, name, &apps.DeploymentRollback{
Name: name,
UpdatedAnnotations: map[string]string{},
RollbackTo: apps.RollbackConfig{Revision: 1},
......
......@@ -201,7 +201,15 @@ func (r *ScaleREST) Update(ctx context.Context, name string, objInfo rest.Update
rs.Spec.Replicas = scale.Spec.Replicas
rs.ResourceVersion = scale.ResourceVersion
obj, _, err = r.store.Update(ctx, rs.Name, rest.DefaultUpdatedObjectInfo(rs), createValidation, updateValidation, false, options)
obj, _, err = r.store.Update(
ctx,
rs.Name,
rest.DefaultUpdatedObjectInfo(rs),
toScaleCreateValidation(createValidation),
toScaleUpdateValidation(updateValidation),
false,
options,
)
if err != nil {
return nil, false, err
}
......@@ -213,6 +221,30 @@ func (r *ScaleREST) Update(ctx context.Context, name string, objInfo rest.Update
return newScale, false, err
}
func toScaleCreateValidation(f rest.ValidateObjectFunc) rest.ValidateObjectFunc {
return func(obj runtime.Object) error {
scale, err := scaleFromReplicaSet(obj.(*apps.ReplicaSet))
if err != nil {
return err
}
return f(scale)
}
}
func toScaleUpdateValidation(f rest.ValidateObjectUpdateFunc) rest.ValidateObjectUpdateFunc {
return func(obj, old runtime.Object) error {
newScale, err := scaleFromReplicaSet(obj.(*apps.ReplicaSet))
if err != nil {
return err
}
oldScale, err := scaleFromReplicaSet(old.(*apps.ReplicaSet))
if err != nil {
return err
}
return f(newScale, oldScale)
}
}
// scaleFromReplicaSet returns a scale subresource for a replica set.
func scaleFromReplicaSet(rs *apps.ReplicaSet) (*autoscaling.Scale, error) {
selector, err := metav1.LabelSelectorAsSelector(rs.Spec.Selector)
......
......@@ -188,7 +188,15 @@ func (r *ScaleREST) Update(ctx context.Context, name string, objInfo rest.Update
ss.Spec.Replicas = scale.Spec.Replicas
ss.ResourceVersion = scale.ResourceVersion
obj, _, err = r.store.Update(ctx, ss.Name, rest.DefaultUpdatedObjectInfo(ss), createValidation, updateValidation, false, options)
obj, _, err = r.store.Update(
ctx,
ss.Name,
rest.DefaultUpdatedObjectInfo(ss),
toScaleCreateValidation(createValidation),
toScaleUpdateValidation(updateValidation),
false,
options,
)
if err != nil {
return nil, false, err
}
......@@ -200,6 +208,30 @@ func (r *ScaleREST) Update(ctx context.Context, name string, objInfo rest.Update
return newScale, false, err
}
func toScaleCreateValidation(f rest.ValidateObjectFunc) rest.ValidateObjectFunc {
return func(obj runtime.Object) error {
scale, err := scaleFromStatefulSet(obj.(*apps.StatefulSet))
if err != nil {
return err
}
return f(scale)
}
}
func toScaleUpdateValidation(f rest.ValidateObjectUpdateFunc) rest.ValidateObjectUpdateFunc {
return func(obj, old runtime.Object) error {
newScale, err := scaleFromStatefulSet(obj.(*apps.StatefulSet))
if err != nil {
return err
}
oldScale, err := scaleFromStatefulSet(old.(*apps.StatefulSet))
if err != nil {
return err
}
return f(newScale, oldScale)
}
}
// scaleFromStatefulSet returns a scale subresource for a statefulset.
func scaleFromStatefulSet(ss *apps.StatefulSet) (*autoscaling.Scale, error) {
selector, err := metav1.LabelSelectorAsSelector(ss.Spec.Selector)
......
......@@ -183,7 +183,15 @@ func (r *ScaleREST) Update(ctx context.Context, name string, objInfo rest.Update
rc.Spec.Replicas = scale.Spec.Replicas
rc.ResourceVersion = scale.ResourceVersion
obj, _, err = r.store.Update(ctx, rc.Name, rest.DefaultUpdatedObjectInfo(rc), createValidation, updateValidation, false, options)
obj, _, err = r.store.Update(
ctx,
rc.Name,
rest.DefaultUpdatedObjectInfo(rc),
toScaleCreateValidation(createValidation),
toScaleUpdateValidation(updateValidation),
false,
options,
)
if err != nil {
return nil, false, err
}
......@@ -191,6 +199,21 @@ func (r *ScaleREST) Update(ctx context.Context, name string, objInfo rest.Update
return scaleFromRC(rc), false, nil
}
func toScaleCreateValidation(f rest.ValidateObjectFunc) rest.ValidateObjectFunc {
return func(obj runtime.Object) error {
return f(scaleFromRC(obj.(*api.ReplicationController)))
}
}
func toScaleUpdateValidation(f rest.ValidateObjectUpdateFunc) rest.ValidateObjectUpdateFunc {
return func(obj, old runtime.Object) error {
return f(
scaleFromRC(obj.(*api.ReplicationController)),
scaleFromRC(old.(*api.ReplicationController)),
)
}
}
// scaleFromRC returns a scale subresource for a replication controller.
func scaleFromRC(rc *api.ReplicationController) *autoscaling.Scale {
return &autoscaling.Scale{
......
......@@ -95,7 +95,15 @@ func (r *ScaleREST) Update(ctx context.Context, name string, objInfo rest.Update
rc.Spec.Replicas = scale.Spec.Replicas
rc.ResourceVersion = scale.ResourceVersion
obj, _, err = r.store.Update(ctx, rc.Name, rest.DefaultUpdatedObjectInfo(rc), createValidation, updateValidation, false, options)
obj, _, err = r.store.Update(
ctx,
rc.Name,
rest.DefaultUpdatedObjectInfo(rc),
toScaleCreateValidation(createValidation),
toScaleUpdateValidation(updateValidation),
false,
options,
)
if err != nil {
return nil, false, errors.NewConflict(extensions.Resource("replicationcontrollers/scale"), scale.Name, err)
}
......@@ -103,6 +111,21 @@ func (r *ScaleREST) Update(ctx context.Context, name string, objInfo rest.Update
return scaleFromRC(rc), false, nil
}
func toScaleCreateValidation(f rest.ValidateObjectFunc) rest.ValidateObjectFunc {
return func(obj runtime.Object) error {
return f(scaleFromRC(obj.(*api.ReplicationController)))
}
}
func toScaleUpdateValidation(f rest.ValidateObjectUpdateFunc) rest.ValidateObjectUpdateFunc {
return func(obj, old runtime.Object) error {
return f(
scaleFromRC(obj.(*api.ReplicationController)),
scaleFromRC(old.(*api.ReplicationController)),
)
}
}
// scaleFromRC returns a scale subresource for a replication controller.
func scaleFromRC(rc *api.ReplicationController) *autoscaling.Scale {
return &autoscaling.Scale{
......
......@@ -190,9 +190,9 @@ func (p *PolicyData) EnsureRBACPolicy() genericapiserver.PostStartHookFunc {
case result.Protected && result.Operation != reconciliation.ReconcileNone:
klog.Warningf("skipped reconcile-protected clusterrole.%s/%s with missing permissions: %v", rbac.GroupName, clusterRole.Name, result.MissingRules)
case result.Operation == reconciliation.ReconcileUpdate:
klog.Infof("updated clusterrole.%s/%s with additional permissions: %v", rbac.GroupName, clusterRole.Name, result.MissingRules)
klog.V(2).Infof("updated clusterrole.%s/%s with additional permissions: %v", rbac.GroupName, clusterRole.Name, result.MissingRules)
case result.Operation == reconciliation.ReconcileCreate:
klog.Infof("created clusterrole.%s/%s", rbac.GroupName, clusterRole.Name)
klog.V(2).Infof("created clusterrole.%s/%s", rbac.GroupName, clusterRole.Name)
}
return nil
})
......@@ -218,11 +218,11 @@ func (p *PolicyData) EnsureRBACPolicy() genericapiserver.PostStartHookFunc {
case result.Protected && result.Operation != reconciliation.ReconcileNone:
klog.Warningf("skipped reconcile-protected clusterrolebinding.%s/%s with missing subjects: %v", rbac.GroupName, clusterRoleBinding.Name, result.MissingSubjects)
case result.Operation == reconciliation.ReconcileUpdate:
klog.Infof("updated clusterrolebinding.%s/%s with additional subjects: %v", rbac.GroupName, clusterRoleBinding.Name, result.MissingSubjects)
klog.V(2).Infof("updated clusterrolebinding.%s/%s with additional subjects: %v", rbac.GroupName, clusterRoleBinding.Name, result.MissingSubjects)
case result.Operation == reconciliation.ReconcileCreate:
klog.Infof("created clusterrolebinding.%s/%s", rbac.GroupName, clusterRoleBinding.Name)
klog.V(2).Infof("created clusterrolebinding.%s/%s", rbac.GroupName, clusterRoleBinding.Name)
case result.Operation == reconciliation.ReconcileRecreate:
klog.Infof("recreated clusterrolebinding.%s/%s", rbac.GroupName, clusterRoleBinding.Name)
klog.V(2).Infof("recreated clusterrolebinding.%s/%s", rbac.GroupName, clusterRoleBinding.Name)
}
return nil
})
......@@ -249,9 +249,9 @@ func (p *PolicyData) EnsureRBACPolicy() genericapiserver.PostStartHookFunc {
case result.Protected && result.Operation != reconciliation.ReconcileNone:
klog.Warningf("skipped reconcile-protected role.%s/%s in %v with missing permissions: %v", rbac.GroupName, role.Name, namespace, result.MissingRules)
case result.Operation == reconciliation.ReconcileUpdate:
klog.Infof("updated role.%s/%s in %v with additional permissions: %v", rbac.GroupName, role.Name, namespace, result.MissingRules)
klog.V(2).Infof("updated role.%s/%s in %v with additional permissions: %v", rbac.GroupName, role.Name, namespace, result.MissingRules)
case result.Operation == reconciliation.ReconcileCreate:
klog.Infof("created role.%s/%s in %v", rbac.GroupName, role.Name, namespace)
klog.V(2).Infof("created role.%s/%s in %v", rbac.GroupName, role.Name, namespace)
}
return nil
})
......@@ -279,11 +279,11 @@ func (p *PolicyData) EnsureRBACPolicy() genericapiserver.PostStartHookFunc {
case result.Protected && result.Operation != reconciliation.ReconcileNone:
klog.Warningf("skipped reconcile-protected rolebinding.%s/%s in %v with missing subjects: %v", rbac.GroupName, roleBinding.Name, namespace, result.MissingSubjects)
case result.Operation == reconciliation.ReconcileUpdate:
klog.Infof("updated rolebinding.%s/%s in %v with additional subjects: %v", rbac.GroupName, roleBinding.Name, namespace, result.MissingSubjects)
klog.V(2).Infof("updated rolebinding.%s/%s in %v with additional subjects: %v", rbac.GroupName, roleBinding.Name, namespace, result.MissingSubjects)
case result.Operation == reconciliation.ReconcileCreate:
klog.Infof("created rolebinding.%s/%s in %v", rbac.GroupName, roleBinding.Name, namespace)
klog.V(2).Infof("created rolebinding.%s/%s in %v", rbac.GroupName, roleBinding.Name, namespace)
case result.Operation == reconciliation.ReconcileRecreate:
klog.Infof("recreated rolebinding.%s/%s in %v", rbac.GroupName, roleBinding.Name, namespace)
klog.V(2).Infof("recreated rolebinding.%s/%s in %v", rbac.GroupName, roleBinding.Name, namespace)
}
return nil
})
......
......@@ -12,6 +12,7 @@ go_library(
importpath = "k8s.io/apiextensions-apiserver/pkg/apiserver/conversion",
visibility = ["//visibility:public"],
deps = [
"//staging/src/k8s.io/api/autoscaling/v1:go_default_library",
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions:go_default_library",
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1:go_default_library",
"//staging/src/k8s.io/apiextensions-apiserver/pkg/features:go_default_library",
......@@ -22,6 +23,7 @@ go_library(
"//staging/src/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/webhook:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/scheme:go_default_library",
"//staging/src/k8s.io/client-go/rest:go_default_library",
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
],
......
......@@ -19,6 +19,7 @@ package conversion
import (
"fmt"
autoscalingv1 "k8s.io/api/autoscaling/v1"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
apiextensionsfeatures "k8s.io/apiextensions-apiserver/pkg/features"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
......@@ -26,6 +27,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/apiserver/pkg/util/webhook"
typedscheme "k8s.io/client-go/kubernetes/scheme"
)
// CRConverterFactory is the factory for all CR converters.
......@@ -77,7 +79,20 @@ func (m *CRConverterFactory) NewConverter(crd *apiextensions.CustomResourceDefin
default:
return nil, nil, fmt.Errorf("unknown conversion strategy %q for CRD %s", crd.Spec.Conversion.Strategy, crd.Name)
}
// Determine whether we should expect to be asked to "convert" autoscaling/v1 Scale types
convertScale := false
if utilfeature.DefaultFeatureGate.Enabled(apiextensionsfeatures.CustomResourceSubresources) {
convertScale = crd.Spec.Subresources != nil && crd.Spec.Subresources.Scale != nil
for _, version := range crd.Spec.Versions {
if version.Subresources != nil && version.Subresources.Scale != nil {
convertScale = true
}
}
}
unsafe = &crConverter{
convertScale: convertScale,
validVersions: validVersions,
clusterScoped: crd.Spec.Scope == apiextensions.ClusterScoped,
converter: converter,
......@@ -96,6 +111,7 @@ type crConverterInterface interface {
// crConverter extends the delegate converter with generic CR conversion behaviour. The delegate will implement the
// user defined conversion strategy given in the CustomResourceDefinition.
type crConverter struct {
convertScale bool
converter crConverterInterface
validVersions map[schema.GroupVersion]bool
clusterScoped bool
......@@ -114,14 +130,23 @@ func (c *crConverter) ConvertFieldLabel(gvk schema.GroupVersionKind, label, valu
}
func (c *crConverter) Convert(in, out, context interface{}) error {
// Special-case typed scale conversion if this custom resource supports a scale endpoint
if c.convertScale {
_, isInScale := in.(*autoscalingv1.Scale)
_, isOutScale := out.(*autoscalingv1.Scale)
if isInScale || isOutScale {
return typedscheme.Scheme.Convert(in, out, context)
}
}
unstructIn, ok := in.(*unstructured.Unstructured)
if !ok {
return fmt.Errorf("input type %T in not valid for unstructured conversion", in)
return fmt.Errorf("input type %T in not valid for unstructured conversion to %T", in, out)
}
unstructOut, ok := out.(*unstructured.Unstructured)
if !ok {
return fmt.Errorf("output type %T in not valid for unstructured conversion", out)
return fmt.Errorf("output type %T in not valid for unstructured conversion from %T", out, in)
}
outGVK := unstructOut.GroupVersionKind()
......
......@@ -268,7 +268,15 @@ func (r *ScaleREST) Update(ctx context.Context, name string, objInfo rest.Update
}
cr.SetResourceVersion(scale.ResourceVersion)
obj, _, err = r.store.Update(ctx, cr.GetName(), rest.DefaultUpdatedObjectInfo(cr), createValidation, updateValidation, false, options)
obj, _, err = r.store.Update(
ctx,
cr.GetName(),
rest.DefaultUpdatedObjectInfo(cr),
toScaleCreateValidation(createValidation, r.specReplicasPath, r.statusReplicasPath, r.labelSelectorPath),
toScaleUpdateValidation(updateValidation, r.specReplicasPath, r.statusReplicasPath, r.labelSelectorPath),
false,
options,
)
if err != nil {
return nil, false, err
}
......@@ -281,6 +289,30 @@ func (r *ScaleREST) Update(ctx context.Context, name string, objInfo rest.Update
return newScale, false, err
}
func toScaleCreateValidation(f rest.ValidateObjectFunc, specReplicasPath, statusReplicasPath, labelSelectorPath string) rest.ValidateObjectFunc {
return func(obj runtime.Object) error {
scale, _, err := scaleFromCustomResource(obj.(*unstructured.Unstructured), specReplicasPath, statusReplicasPath, labelSelectorPath)
if err != nil {
return err
}
return f(scale)
}
}
func toScaleUpdateValidation(f rest.ValidateObjectUpdateFunc, specReplicasPath, statusReplicasPath, labelSelectorPath string) rest.ValidateObjectUpdateFunc {
return func(obj, old runtime.Object) error {
newScale, _, err := scaleFromCustomResource(obj.(*unstructured.Unstructured), specReplicasPath, statusReplicasPath, labelSelectorPath)
if err != nil {
return err
}
oldScale, _, err := scaleFromCustomResource(old.(*unstructured.Unstructured), specReplicasPath, statusReplicasPath, labelSelectorPath)
if err != nil {
return err
}
return f(newScale, oldScale)
}
}
// scaleFromCustomResource returns a scale subresource for a customresource and a bool signalling wether
// the specReplicas value was found.
func scaleFromCustomResource(cr *unstructured.Unstructured, specReplicasPath, statusReplicasPath, labelSelectorPath string) (*autoscalingv1.Scale, bool, error) {
......@@ -310,6 +342,11 @@ func scaleFromCustomResource(cr *unstructured.Unstructured, specReplicasPath, st
}
scale := &autoscalingv1.Scale{
// Populate apiVersion and kind so conversion recognizes we are already in the desired GVK and doesn't try to convert
TypeMeta: metav1.TypeMeta{
APIVersion: "autoscaling/v1",
Kind: "Scale",
},
ObjectMeta: metav1.ObjectMeta{
Name: cr.GetName(),
Namespace: cr.GetNamespace(),
......
......@@ -381,6 +381,10 @@ func TestScaleGet(t *testing.T) {
}
want := &autoscalingv1.Scale{
TypeMeta: metav1.TypeMeta{
Kind: "Scale",
APIVersion: "autoscaling/v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: cr.GetName(),
Namespace: metav1.NamespaceDefault,
......
......@@ -6,6 +6,10 @@ go_test(
"main_test.go",
"watch_restart_test.go",
],
tags = [
"etcd",
"integration",
],
deps = [
"//pkg/api/testapi:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
......
......@@ -83,6 +83,7 @@ filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//test/integration/apiserver/admissionwebhook:all-srcs",
"//test/integration/apiserver/apply:all-srcs",
],
tags = ["automanaged"],
......
load("@io_bazel_rules_go//go:def.bzl", "go_test")
go_test(
name = "go_default_test",
srcs = [
"admission_test.go",
"main_test.go",
],
tags = [
"etcd",
"integration",
],
deps = [
"//cmd/kube-apiserver/app/options:go_default_library",
"//staging/src/k8s.io/api/admission/v1beta1:go_default_library",
"//staging/src/k8s.io/api/admissionregistration/v1beta1:go_default_library",
"//staging/src/k8s.io/api/apps/v1beta1:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/api/extensions/v1beta1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//staging/src/k8s.io/client-go/dynamic:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
"//staging/src/k8s.io/client-go/util/retry:go_default_library",
"//test/integration/etcd:go_default_library",
"//test/integration/framework:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package admissionwebhook
import (
"testing"
"k8s.io/kubernetes/test/integration/framework"
)
func TestMain(m *testing.M) {
framework.EtcdMain(m.Run)
}
......@@ -139,13 +139,19 @@ func StartRealMasterOrDie(t *testing.T, configFuncs ...func(*options.ServerRunOp
}()
lastHealth := ""
attempt := 0
if err := wait.PollImmediate(time.Second, time.Minute, func() (done bool, err error) {
// wait for the server to be healthy
result := kubeClient.RESTClient().Get().AbsPath("/healthz").Do()
content, _ := result.Raw()
lastHealth = string(content)
if errResult := result.Error(); errResult != nil {
t.Log(errResult)
attempt++
if attempt < 10 {
t.Log("waiting for server to be healthy")
} else {
t.Log(errResult)
}
return false, nil
}
var status int
......
......@@ -78,8 +78,10 @@ go_library(
"//staging/src/k8s.io/client-go/util/cert:go_default_library",
"//test/e2e/framework:go_default_library",
"//test/utils:go_default_library",
"//vendor/github.com/coreos/etcd/clientv3:go_default_library",
"//vendor/github.com/go-openapi/spec:go_default_library",
"//vendor/github.com/pborman/uuid:go_default_library",
"//vendor/google.golang.org/grpc/grpclog:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/kube-openapi/pkg/common:go_default_library",
],
......
......@@ -27,6 +27,8 @@ import (
"runtime"
"strings"
"github.com/coreos/etcd/clientv3"
"google.golang.org/grpc/grpclog"
"k8s.io/klog"
"k8s.io/kubernetes/pkg/util/env"
......@@ -109,7 +111,7 @@ func startEtcd() (func(), error) {
"--listen-peer-urls",
"http://127.0.0.1:0",
"--log-package-levels",
"*=DEBUG",
"*=NOTICE", // set to INFO or DEBUG for more logs
)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
......@@ -123,6 +125,10 @@ func startEtcd() (func(), error) {
}
}
// Quiet etcd logs for integration tests
// Comment out to get verbose logs if desired
clientv3.SetLogger(grpclog.NewLoggerV2(ioutil.Discard, ioutil.Discard, os.Stderr))
if err := cmd.Start(); err != nil {
return nil, fmt.Errorf("failed to run etcd: %v", err)
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment