diff --git a/cluster/gce/config-default.sh b/cluster/gce/config-default.sh index 26a3ce816b..fc9cbd916f 100755 --- a/cluster/gce/config-default.sh +++ b/cluster/gce/config-default.sh @@ -413,6 +413,14 @@ if [[ -n "${LOGROTATE_MAX_SIZE:-}" ]]; then PROVIDER_VARS="${PROVIDER_VARS:-} LOGROTATE_MAX_SIZE" fi +if [[ -n "${POD_LOG_MAX_FILE:-}" ]]; then + PROVIDER_VARS="${PROVIDER_VARS:-} POD_LOG_MAX_FILE" +fi + +if [[ -n "${POD_LOG_MAX_SIZE:-}" ]]; then + PROVIDER_VARS="${PROVIDER_VARS:-} POD_LOG_MAX_SIZE" +fi + # Fluentd requirements # YAML exists to trigger a configuration refresh when changes are made. FLUENTD_GCP_YAML_VERSION="v3.2.0" diff --git a/cluster/gce/config-test.sh b/cluster/gce/config-test.sh index 61d0a29967..ce49207513 100755 --- a/cluster/gce/config-test.sh +++ b/cluster/gce/config-test.sh @@ -432,6 +432,14 @@ if [[ -n "${LOGROTATE_MAX_SIZE:-}" ]]; then PROVIDER_VARS="${PROVIDER_VARS:-} LOGROTATE_MAX_SIZE" fi +if [[ -n "${POD_LOG_MAX_FILE:-}" ]]; then + PROVIDER_VARS="${PROVIDER_VARS:-} POD_LOG_MAX_FILE" +fi + +if [[ -n "${POD_LOG_MAX_SIZE:-}" ]]; then + PROVIDER_VARS="${PROVIDER_VARS:-} POD_LOG_MAX_SIZE" +fi + # Fluentd requirements # YAML exists to trigger a configuration refresh when changes are made. FLUENTD_GCP_YAML_VERSION="v3.2.0" diff --git a/cluster/gce/gci/configure-helper.sh b/cluster/gce/gci/configure-helper.sh index 3c95c2afe8..f479c1ddd9 100644 --- a/cluster/gce/gci/configure-helper.sh +++ b/cluster/gce/gci/configure-helper.sh @@ -374,6 +374,21 @@ function setup-logrotate() { } EOF + # Configure log rotation for pod logs in /var/log/pods/NAMESPACE_NAME_UID. + cat > /etc/logrotate.d/allpodlogs < tuple. +// WARNING: this function is subject to change. Clients shouldn't depend on +// this function. +func StorageVersionHash(group, version, kind string) string { + gvk := group + "/" + version + "/" + kind + if gvk == "" { + return "" + } + bytes := sha256.Sum256([]byte(gvk)) + // Assuming there are N kinds in the cluster, and the hash is X-byte long, + // the chance of colliding hash P(N,X) approximates to 1-e^(-(N^2)/2^(8X+1)). + // P(10,000, 8) ~= 2.7*10^(-12), which is low enough. + // See https://en.wikipedia.org/wiki/Birthday_problem#Approximations. + return base64.StdEncoding.EncodeToString( + bytes[:8]) +} diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go b/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go index 8440624329..c48c2d61f6 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go @@ -33,6 +33,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" "k8s.io/apiserver/pkg/admission" + "k8s.io/apiserver/pkg/endpoints/discovery" "k8s.io/apiserver/pkg/endpoints/handlers" "k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager" "k8s.io/apiserver/pkg/endpoints/handlers/negotiation" @@ -133,6 +134,20 @@ func (a *APIInstaller) newWebService() *restful.WebService { return ws } +// calculate the storage gvk, the gvk objects are converted to before persisted to the etcd. +func getStorageVersionKind(storageVersioner runtime.GroupVersioner, storage rest.Storage, typer runtime.ObjectTyper) (schema.GroupVersionKind, error) { + object := storage.New() + fqKinds, _, err := typer.ObjectKinds(object) + if err != nil { + return schema.GroupVersionKind{}, err + } + gvk, ok := storageVersioner.KindForGroupVersionKinds(fqKinds) + if !ok { + return schema.GroupVersionKind{}, fmt.Errorf("cannot find the storage version kind for %v", reflect.TypeOf(object)) + } + return gvk, nil +} + // GetResourceKind returns the external group version kind registered for the given storage // object. If the storage object is a subresource and has an override supplied for it, it returns // the group version kind supplied in the override. @@ -227,6 +242,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag watcher, isWatcher := storage.(rest.Watcher) connecter, isConnecter := storage.(rest.Connecter) storageMeta, isMetadata := storage.(rest.StorageMetadata) + storageVersionProvider, isStorageVersionProvider := storage.(rest.StorageVersionProvider) if !isMetadata { storageMeta = defaultStorageMetadata{} } @@ -365,6 +381,17 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag tableProvider, _ := storage.(rest.TableConvertor) var apiResource metav1.APIResource + if utilfeature.DefaultFeatureGate.Enabled(features.StorageVersionHash) && + isStorageVersionProvider && + storageVersionProvider.StorageVersion() != nil { + versioner := storageVersionProvider.StorageVersion() + gvk, err := getStorageVersionKind(versioner, storage, a.group.Typer) + if err != nil { + return nil, err + } + apiResource.StorageVersionHash = discovery.StorageVersionHash(gvk.Group, gvk.Version, gvk.Kind) + } + // Get the list of actions for the given scope. switch { case !namespaceScoped: diff --git a/staging/src/k8s.io/apiserver/pkg/features/kube_features.go b/staging/src/k8s.io/apiserver/pkg/features/kube_features.go index e99045896f..587a6dfe54 100644 --- a/staging/src/k8s.io/apiserver/pkg/features/kube_features.go +++ b/staging/src/k8s.io/apiserver/pkg/features/kube_features.go @@ -89,6 +89,13 @@ const ( // Server-side apply. Merging happens on the server. ServerSideApply utilfeature.Feature = "ServerSideApply" + // owner: @caesarxuchao + // alpha: v1.14 + // + // Allow apiservers to expose the storage version hash in the discovery + // document. + StorageVersionHash utilfeature.Feature = "StorageVersionHash" + // owner: @ksubrmnn // alpha: v1.14 // @@ -118,6 +125,7 @@ var defaultKubernetesFeatureGates = map[utilfeature.Feature]utilfeature.FeatureS APIListChunking: {Default: true, PreRelease: utilfeature.Beta}, DryRun: {Default: true, PreRelease: utilfeature.Beta}, ServerSideApply: {Default: false, PreRelease: utilfeature.Alpha}, + StorageVersionHash: {Default: false, PreRelease: utilfeature.Alpha}, WinOverlay: {Default: false, PreRelease: utilfeature.Alpha}, WinDSR: {Default: false, PreRelease: utilfeature.Alpha}, } diff --git a/staging/src/k8s.io/apiserver/pkg/registry/generic/registry/store.go b/staging/src/k8s.io/apiserver/pkg/registry/generic/registry/store.go index 5489596e63..c84a3276c4 100644 --- a/staging/src/k8s.io/apiserver/pkg/registry/generic/registry/store.go +++ b/staging/src/k8s.io/apiserver/pkg/registry/generic/registry/store.go @@ -177,6 +177,12 @@ type Store struct { // resource. It is wrapped into a "DryRunnableStorage" that will // either pass-through or simply dry-run. Storage DryRunnableStorage + // StorageVersioner outputs the an object will be + // converted to before persisted in etcd, given a list of possible + // kinds of the object. + // If the StorageVersioner is nil, apiserver will leave the + // storageVersionHash as empty in the discovery document. + StorageVersioner runtime.GroupVersioner // Called to cleanup clients used by the underlying Storage; optional. DestroyFunc func() } @@ -1287,6 +1293,7 @@ func (e *Store) CompleteWithOptions(options *generic.StoreOptions) error { attrFunc, triggerFunc, ) + e.StorageVersioner = opts.StorageConfig.EncodeVersioner if opts.CountMetricPollPeriod > 0 { stopFunc := e.startObservingCount(opts.CountMetricPollPeriod) @@ -1327,3 +1334,7 @@ func (e *Store) ConvertToTable(ctx context.Context, object runtime.Object, table } return rest.NewDefaultTableConvertor(e.qualifiedResourceFromContext(ctx)).ConvertToTable(ctx, object, tableOptions) } + +func (e *Store) StorageVersion() runtime.GroupVersioner { + return e.StorageVersioner +} diff --git a/staging/src/k8s.io/apiserver/pkg/registry/rest/rest.go b/staging/src/k8s.io/apiserver/pkg/registry/rest/rest.go index 9fad541348..b16f7f677b 100644 --- a/staging/src/k8s.io/apiserver/pkg/registry/rest/rest.go +++ b/staging/src/k8s.io/apiserver/pkg/registry/rest/rest.go @@ -332,3 +332,12 @@ type StorageMetadata interface { // it is not nil. Only the type of the return object matters, the value will be ignored. ProducesObject(verb string) interface{} } + +// StorageVersionProvider is an optional interface that a storage object can +// implement if it wishes to disclose its storage version. +type StorageVersionProvider interface { + // StorageVersion returns a group versioner, which will outputs the gvk + // an object will be converted to before persisted in etcd, given a + // list of kinds the object might belong to. + StorageVersion() runtime.GroupVersioner +} diff --git a/staging/src/k8s.io/apiserver/pkg/server/storage/storage_codec.go b/staging/src/k8s.io/apiserver/pkg/server/storage/storage_codec.go index e2f91bf13d..96faa17122 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/storage/storage_codec.go +++ b/staging/src/k8s.io/apiserver/pkg/server/storage/storage_codec.go @@ -40,15 +40,15 @@ type StorageCodecConfig struct { // NewStorageCodec assembles a storage codec for the provided storage media type, the provided serializer, and the requested // storage and memory versions. -func NewStorageCodec(opts StorageCodecConfig) (runtime.Codec, error) { +func NewStorageCodec(opts StorageCodecConfig) (runtime.Codec, runtime.GroupVersioner, error) { mediaType, _, err := mime.ParseMediaType(opts.StorageMediaType) if err != nil { - return nil, fmt.Errorf("%q is not a valid mime-type", opts.StorageMediaType) + return nil, nil, fmt.Errorf("%q is not a valid mime-type", opts.StorageMediaType) } serializer, ok := runtime.SerializerInfoForMediaType(opts.StorageSerializer.SupportedMediaTypes(), mediaType) if !ok { - return nil, fmt.Errorf("unable to find serializer for %q", mediaType) + return nil, nil, fmt.Errorf("unable to find serializer for %q", mediaType) } s := serializer.Serializer @@ -74,14 +74,16 @@ func NewStorageCodec(opts StorageCodecConfig) (runtime.Codec, error) { decoders = opts.DecoderDecoratorFn(decoders) } + encodeVersioner := runtime.NewMultiGroupVersioner( + opts.StorageVersion, + schema.GroupKind{Group: opts.StorageVersion.Group}, + schema.GroupKind{Group: opts.MemoryVersion.Group}, + ) + // Ensure the storage receives the correct version. encoder = opts.StorageSerializer.EncoderForVersion( encoder, - runtime.NewMultiGroupVersioner( - opts.StorageVersion, - schema.GroupKind{Group: opts.StorageVersion.Group}, - schema.GroupKind{Group: opts.MemoryVersion.Group}, - ), + encodeVersioner, ) decoder := opts.StorageSerializer.DecoderToVersion( recognizer.NewDecoder(decoders...), @@ -92,5 +94,5 @@ func NewStorageCodec(opts StorageCodecConfig) (runtime.Codec, error) { ), ) - return runtime.NewCodec(encoder, decoder), nil + return runtime.NewCodec(encoder, decoder), encodeVersioner, nil } diff --git a/staging/src/k8s.io/apiserver/pkg/server/storage/storage_factory.go b/staging/src/k8s.io/apiserver/pkg/server/storage/storage_factory.go index c3bb6ecd6d..267de1370b 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/storage/storage_factory.go +++ b/staging/src/k8s.io/apiserver/pkg/server/storage/storage_factory.go @@ -86,7 +86,7 @@ type DefaultStorageFactory struct { APIResourceConfigSource APIResourceConfigSource // newStorageCodecFn exists to be overwritten for unit testing. - newStorageCodecFn func(opts StorageCodecConfig) (codec runtime.Codec, err error) + newStorageCodecFn func(opts StorageCodecConfig) (codec runtime.Codec, encodeVersioner runtime.GroupVersioner, err error) } type groupResourceOverrides struct { @@ -278,7 +278,7 @@ func (s *DefaultStorageFactory) NewConfig(groupResource schema.GroupResource) (* } codecConfig.Config = storageConfig - storageConfig.Codec, err = s.newStorageCodecFn(codecConfig) + storageConfig.Codec, storageConfig.EncodeVersioner, err = s.newStorageCodecFn(codecConfig) if err != nil { return nil, err } diff --git a/staging/src/k8s.io/apiserver/pkg/storage/storagebackend/config.go b/staging/src/k8s.io/apiserver/pkg/storage/storagebackend/config.go index c36a103942..d4bc7fb49d 100644 --- a/staging/src/k8s.io/apiserver/pkg/storage/storagebackend/config.go +++ b/staging/src/k8s.io/apiserver/pkg/storage/storagebackend/config.go @@ -57,6 +57,11 @@ type Config struct { Paging bool Codec runtime.Codec + // EncodeVersioner is the same groupVersioner used to build the + // storage encoder. Given a list of kinds the input object might belong + // to, the EncodeVersioner outputs the gvk the object will be + // converted to before persisted in etcd. + EncodeVersioner runtime.GroupVersioner // Transformer allows the value to be transformed prior to persisting into etcd. Transformer value.Transformer diff --git a/staging/src/k8s.io/client-go/tools/watch/retrywatcher.go b/staging/src/k8s.io/client-go/tools/watch/retrywatcher.go index 62c14b0784..e45d58ec15 100644 --- a/staging/src/k8s.io/client-go/tools/watch/retrywatcher.go +++ b/staging/src/k8s.io/client-go/tools/watch/retrywatcher.go @@ -184,13 +184,17 @@ func (rw *RetryWatcher) doReceive() (bool, time.Duration) { continue case watch.Error: - status, ok := event.Object.(*metav1.Status) + // This round trip allows us to handle unstructured status + errObject := apierrors.FromObject(event.Object) + statusErr, ok := errObject.(*apierrors.StatusError) if !ok { klog.Error(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object)) // Retry unknown errors return false, 0 } + status := statusErr.ErrStatus + statusDelay := time.Duration(0) if status.Details != nil { statusDelay = time.Duration(status.Details.RetryAfterSeconds) * time.Second diff --git a/staging/src/k8s.io/sample-apiserver/pkg/cmd/server/BUILD b/staging/src/k8s.io/sample-apiserver/pkg/cmd/server/BUILD index 9f704e55c1..0a71e2a768 100644 --- a/staging/src/k8s.io/sample-apiserver/pkg/cmd/server/BUILD +++ b/staging/src/k8s.io/sample-apiserver/pkg/cmd/server/BUILD @@ -11,10 +11,13 @@ go_library( importmap = "k8s.io/kubernetes/vendor/k8s.io/sample-apiserver/pkg/cmd/server", importpath = "k8s.io/sample-apiserver/pkg/cmd/server", deps = [ + "//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/util/errors:go_default_library", "//staging/src/k8s.io/apiserver/pkg/admission:go_default_library", "//staging/src/k8s.io/apiserver/pkg/server:go_default_library", "//staging/src/k8s.io/apiserver/pkg/server/options:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", "//staging/src/k8s.io/sample-apiserver/pkg/admission/plugin/banflunder:go_default_library", "//staging/src/k8s.io/sample-apiserver/pkg/admission/wardleinitializer:go_default_library", "//staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1:go_default_library", diff --git a/staging/src/k8s.io/sample-apiserver/pkg/cmd/server/start.go b/staging/src/k8s.io/sample-apiserver/pkg/cmd/server/start.go index 48aa538ba0..66409efad6 100644 --- a/staging/src/k8s.io/sample-apiserver/pkg/cmd/server/start.go +++ b/staging/src/k8s.io/sample-apiserver/pkg/cmd/server/start.go @@ -23,10 +23,13 @@ import ( "github.com/spf13/cobra" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" utilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apiserver/pkg/admission" genericapiserver "k8s.io/apiserver/pkg/server" genericoptions "k8s.io/apiserver/pkg/server/options" + utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/sample-apiserver/pkg/admission/plugin/banflunder" "k8s.io/sample-apiserver/pkg/admission/wardleinitializer" "k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1" @@ -56,7 +59,7 @@ func NewWardleServerOptions(out, errOut io.Writer) *WardleServerOptions { StdOut: out, StdErr: errOut, } - + o.RecommendedOptions.Etcd.StorageConfig.EncodeVersioner = runtime.NewMultiGroupVersioner(v1alpha1.SchemeGroupVersion, schema.GroupKind{Group: v1alpha1.GroupName}) return o } @@ -83,6 +86,7 @@ func NewCommandStartWardleServer(defaults *WardleServerOptions, stopCh <-chan st flags := cmd.Flags() o.RecommendedOptions.AddFlags(flags) + utilfeature.DefaultMutableFeatureGate.AddFlag(flags) return cmd } diff --git a/test/e2e/apimachinery/BUILD b/test/e2e/apimachinery/BUILD index 136dd18f70..e32bde872d 100644 --- a/test/e2e/apimachinery/BUILD +++ b/test/e2e/apimachinery/BUILD @@ -15,6 +15,7 @@ go_library( "crd_publish_openapi.go", "crd_watch.go", "custom_resource_definition.go", + "discovery.go", "etcd_failure.go", "framework.go", "garbage_collector.go", @@ -65,6 +66,7 @@ go_library( "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/yaml:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/endpoints/discovery:go_default_library", "//staging/src/k8s.io/apiserver/pkg/storage/names:go_default_library", "//staging/src/k8s.io/apiserver/pkg/storage/storagebackend:go_default_library", "//staging/src/k8s.io/client-go/discovery:go_default_library", diff --git a/test/e2e/apimachinery/discovery.go b/test/e2e/apimachinery/discovery.go new file mode 100644 index 0000000000..b2e42db58e --- /dev/null +++ b/test/e2e/apimachinery/discovery.go @@ -0,0 +1,78 @@ +/* +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 apimachinery + +import ( + utilversion "k8s.io/apimachinery/pkg/util/version" + "k8s.io/apiserver/pkg/endpoints/discovery" + "k8s.io/kubernetes/test/e2e/framework" + + . "github.com/onsi/ginkgo" +) + +var storageVersionServerVersion = utilversion.MustParseSemantic("v1.13.99") +var _ = SIGDescribe("Discovery", func() { + f := framework.NewDefaultFramework("discovery") + + var namespaceName string + + BeforeEach(func() { + namespaceName = f.Namespace.Name + + framework.SkipUnlessServerVersionGTE(storageVersionServerVersion, f.ClientSet.Discovery()) + + By("Setting up server cert") + setupServerCert(namespaceName, serviceName) + }) + + It("[Feature:StorageVersionHash] Custom resource should have storage version hash", func() { + testcrd, err := framework.CreateTestCRD(f) + if err != nil { + return + } + defer testcrd.CleanUp() + spec := testcrd.Crd.Spec + resources, err := testcrd.ApiExtensionClient.Discovery().ServerResourcesForGroupVersion(spec.Group + "/" + spec.Versions[0].Name) + if err != nil { + framework.Failf("failed to find the discovery doc for %v: %v", resources, err) + } + found := false + var storageVersion string + for _, v := range spec.Versions { + if v.Storage { + storageVersion = v.Name + } + } + // DISCLAIMER: the algorithm of deriving the storageVersionHash + // is an implementation detail, which shouldn't be relied on by + // the clients. The following calculation is for test purpose + // only. + expected := discovery.StorageVersionHash(spec.Group, storageVersion, spec.Names.Kind) + + for _, r := range resources.APIResources { + if r.Name == spec.Names.Plural { + found = true + if r.StorageVersionHash != expected { + framework.Failf("expected storageVersionHash of %s/%s/%s to be %s, got %s", r.Group, r.Version, r.Name, expected, r.StorageVersionHash) + } + } + } + if !found { + framework.Failf("didn't find resource %s in the discovery doc", spec.Names.Plural) + } + }) +}) diff --git a/test/e2e/common/node_lease.go b/test/e2e/common/node_lease.go index b3a113b86d..88d9833518 100644 --- a/test/e2e/common/node_lease.go +++ b/test/e2e/common/node_lease.go @@ -101,20 +101,37 @@ var _ = framework.KubeDescribe("NodeLease", func() { By("verify NodeStatus report period is longer than lease duration") // NodeStatus is reported from node to master when there is some change or // enough time has passed. So for here, keep checking the time diff - // between 2 NodeStatus report, until it is longer than lease duration ( - // the same as nodeMonitorGracePeriod). - heartbeatTime := getNextReadyConditionHeartbeatTime(f.ClientSet, nodeName, metav1.Time{}) + // between 2 NodeStatus report, until it is longer than lease duration + // (the same as nodeMonitorGracePeriod), or it doesn't change for at least leaseDuration + lastHeartbeatTime := getReadyConditionHeartbeatTime(f.ClientSet, nodeName) + lastObserved := time.Now() Eventually(func() error { - nextHeartbeatTime := getNextReadyConditionHeartbeatTime(f.ClientSet, nodeName, heartbeatTime) + currentHeartbeatTime := getReadyConditionHeartbeatTime(f.ClientSet, nodeName) + currentObserved := time.Now() - if nextHeartbeatTime.Time.After(heartbeatTime.Time.Add(leaseDuration)) { - return nil + switch { + case currentHeartbeatTime == lastHeartbeatTime: + if currentObserved.Sub(lastObserved) > 2*leaseDuration { + // heartbeat hasn't changed while watching for at least 2*leaseDuration, success! + framework.Logf("node status heartbeat is unchanged for %s, was waiting for at least %s, success!", currentObserved.Sub(lastObserved), 2*leaseDuration) + return nil + } + framework.Logf("node status heartbeat is unchanged for %s, waiting for %s", currentObserved.Sub(lastObserved), 2*leaseDuration) + return fmt.Errorf("node status heartbeat is unchanged for %s, waiting for %s", currentObserved.Sub(lastObserved), 2*leaseDuration) + + case currentHeartbeatTime != lastHeartbeatTime: + if currentHeartbeatTime.Sub(lastHeartbeatTime) > leaseDuration { + // heartbeat time changed, but the diff was greater than leaseDuration, success! + framework.Logf("node status heartbeat changed in %s, was waiting for at least %s, success!", currentHeartbeatTime.Sub(lastHeartbeatTime), leaseDuration) + return nil + } + lastHeartbeatTime = currentHeartbeatTime + lastObserved = currentObserved + framework.Logf("node status heartbeat changed in %s, waiting for %s", currentHeartbeatTime.Sub(lastHeartbeatTime), leaseDuration) + return fmt.Errorf("node status heartbeat changed in %s, waiting for %s", currentHeartbeatTime.Sub(lastHeartbeatTime), leaseDuration) } - heartbeatTime = nextHeartbeatTime - return fmt.Errorf("node status report period is shorter than lease duration") - - // Enter next round immediately. - }, 5*time.Minute, time.Nanosecond).Should(BeNil()) + return nil + }, 5*time.Minute, time.Second).Should(BeNil()) By("verify node is still in ready status even though node status report is infrequent") // This check on node status is only meaningful when this e2e test is @@ -128,22 +145,12 @@ var _ = framework.KubeDescribe("NodeLease", func() { }) }) -func getNextReadyConditionHeartbeatTime(clientSet clientset.Interface, nodeName string, prevHeartbeatTime metav1.Time) metav1.Time { - var newHeartbeatTime metav1.Time - Eventually(func() error { - node, err := clientSet.CoreV1().Nodes().Get(nodeName, metav1.GetOptions{}) - if err != nil { - return err - } - _, readyCondition := testutils.GetNodeCondition(&node.Status, corev1.NodeReady) - Expect(readyCondition.Status).To(Equal(corev1.ConditionTrue)) - newHeartbeatTime = readyCondition.LastHeartbeatTime - if prevHeartbeatTime.Before(&newHeartbeatTime) { - return nil - } - return fmt.Errorf("heartbeat has not changed yet") - }, 5*time.Minute, 5*time.Second).Should(BeNil()) - return newHeartbeatTime +func getReadyConditionHeartbeatTime(clientSet clientset.Interface, nodeName string) time.Time { + node, err := clientSet.CoreV1().Nodes().Get(nodeName, metav1.GetOptions{}) + Expect(err).To(BeNil()) + _, readyCondition := testutils.GetNodeCondition(&node.Status, corev1.NodeReady) + Expect(readyCondition.Status).To(Equal(corev1.ConditionTrue)) + return readyCondition.LastHeartbeatTime.Time } func expectLease(lease *coordv1beta1.Lease, nodeName string) error { diff --git a/test/images/audit-proxy/Dockerfile b/test/images/audit-proxy/Dockerfile index 7bbeb62b45..ef7ef7fafb 100644 --- a/test/images/audit-proxy/Dockerfile +++ b/test/images/audit-proxy/Dockerfile @@ -12,6 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -FROM scratch +FROM gcr.io/distroless/static:latest COPY audit-proxy / ENTRYPOINT ["/audit-proxy"] diff --git a/test/images/audit-proxy/VERSION b/test/images/audit-proxy/VERSION index d3827e75a5..9459d4ba2a 100644 --- a/test/images/audit-proxy/VERSION +++ b/test/images/audit-proxy/VERSION @@ -1 +1 @@ -1.0 +1.1