Merge pull request #67406 from freehan/pod-ready

Automatic merge from submit-queue (batch tested with PRs 67031, 67406). 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>.

Pod Ready++ cont

```release-note
Turn on PodReadinessGate by default
```

ref: https://github.com/kubernetes/community/blob/master/keps/sig-network/0007-pod-ready%2B%2B.md
This commit is contained in:
Kubernetes Submit Queue 2018-08-23 11:13:58 -07:00 committed by GitHub
commit a1c3e4796e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 74 additions and 1 deletions

View File

@ -397,7 +397,7 @@ var defaultKubernetesFeatureGates = map[utilfeature.Feature]utilfeature.FeatureS
VolumeSubpath: {Default: true, PreRelease: utilfeature.GA},
BalanceAttachedNodeVolumes: {Default: false, PreRelease: utilfeature.Alpha},
DynamicProvisioningScheduling: {Default: false, PreRelease: utilfeature.Alpha},
PodReadinessGates: {Default: false, PreRelease: utilfeature.Beta},
PodReadinessGates: {Default: true, PreRelease: utilfeature.Beta},
VolumeSubpathEnvExpansion: {Default: false, PreRelease: utilfeature.Alpha},
KubeletPluginsWatcher: {Default: false, PreRelease: utilfeature.Alpha},
ResourceQuotaScopeSelectors: {Default: true, PreRelease: utilfeature.Beta},

View File

@ -52,6 +52,7 @@ go_library(
"//staging/src/k8s.io/apimachinery/pkg/labels: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/intstr:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/uuid:go_default_library",

View File

@ -39,6 +39,7 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"k8s.io/apimachinery/pkg/types"
imageutils "k8s.io/kubernetes/test/utils/image"
)
@ -46,6 +47,10 @@ var (
buildBackOffDuration = time.Minute
syncLoopFrequency = 10 * time.Second
maxBackOffTolerance = time.Duration(1.3 * float64(kubelet.MaxContainerBackOff))
// maxReadyStatusUpdateTolerance specifies the latency that allows kubelet to update pod status.
// When kubelet is under heavy load (tests may be parallelized), the delay may be longer, hence
// causing tests to be flaky.
maxReadyStatusUpdateTolerance = 10 * time.Second
)
// testHostIP tests that a pod gets a host IP
@ -694,4 +699,64 @@ var _ = framework.KubeDescribe("Pods", func() {
framework.Failf("expected %s back-off got=%s on delay2", kubelet.MaxContainerBackOff, delay2)
}
})
// TODO(freehan): label the test to be [NodeConformance] after tests are proven to be stable.
It("should support pod readiness gates [NodeFeature:PodReadinessGate]", func() {
podName := "pod-ready"
readinessGate1 := "k8s.io/test-condition1"
readinessGate2 := "k8s.io/test-condition2"
patchStatusFmt := `{"status":{"conditions":[{"type":%q, "status":%q}]}}`
pod := &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: podName,
Labels: map[string]string{"test": "pod-readiness-gate"},
},
Spec: v1.PodSpec{
Containers: []v1.Container{
{
Name: "pod-readiness-gate",
Image: imageutils.GetE2EImage(imageutils.BusyBox),
Command: []string{"/bin/sh", "-c", "echo container is alive; sleep 10000"},
},
},
ReadinessGates: []v1.PodReadinessGate{
{ConditionType: v1.PodConditionType(readinessGate1)},
{ConditionType: v1.PodConditionType(readinessGate2)},
},
},
}
validatePodReadiness := func(expectReady bool) {
Expect(wait.Poll(time.Second, maxReadyStatusUpdateTolerance, func() (bool, error) {
podReady := podClient.PodIsReady(podName)
res := expectReady == podReady
if !res {
framework.Logf("Expect the Ready condition of pod %q to be %v, but got %v", podName, expectReady, podReady)
}
return res, nil
})).NotTo(HaveOccurred())
}
By("submitting the pod to kubernetes")
podClient.CreateSync(pod)
Expect(podClient.PodIsReady(podName)).To(BeFalse(), "Expect pod's Ready condition to be false initially.")
By(fmt.Sprintf("patching pod status with condition %q to true", readinessGate1))
_, err := podClient.Patch(podName, types.StrategicMergePatchType, []byte(fmt.Sprintf(patchStatusFmt, readinessGate1, "True")), "status")
Expect(err).NotTo(HaveOccurred())
// Sleep for 10 seconds.
time.Sleep(maxReadyStatusUpdateTolerance)
Expect(podClient.PodIsReady(podName)).To(BeFalse(), "Expect pod's Ready condition to be false with only one condition in readinessGates equal to True")
By(fmt.Sprintf("patching pod status with condition %q to true", readinessGate2))
_, err = podClient.Patch(podName, types.StrategicMergePatchType, []byte(fmt.Sprintf(patchStatusFmt, readinessGate2, "True")), "status")
Expect(err).NotTo(HaveOccurred())
validatePodReadiness(true)
By(fmt.Sprintf("patching pod status with condition %q to false", readinessGate1))
_, err = podClient.Patch(podName, types.StrategicMergePatchType, []byte(fmt.Sprintf(patchStatusFmt, readinessGate1, "False")), "status")
Expect(err).NotTo(HaveOccurred())
validatePodReadiness(false)
})
})

View File

@ -30,6 +30,7 @@ import (
"k8s.io/apimachinery/pkg/util/wait"
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/kubernetes/pkg/api/legacyscheme"
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
"k8s.io/kubernetes/pkg/kubelet/events"
"k8s.io/kubernetes/pkg/kubelet/sysctl"
@ -259,3 +260,9 @@ func (c *PodClient) MatchContainerOutput(name string, containerName string, expe
}
return nil
}
func (c *PodClient) PodIsReady(name string) bool {
pod, err := c.Get(name, metav1.GetOptions{})
ExpectNoError(err)
return podutil.IsPodReady(pod)
}