mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-04 18:00:08 +00:00
Add tests for newly exposed drain code
This commit is contained in:
parent
c74f2f6a72
commit
4bba4449ae
@ -51,10 +51,14 @@ go_test(
|
|||||||
embed = [":go_default_library"],
|
embed = [":go_default_library"],
|
||||||
deps = [
|
deps = [
|
||||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||||
|
"//staging/src/k8s.io/api/policy/v1beta1:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/api/errors: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: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/runtime/schema:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||||
|
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||||
|
"//staging/src/k8s.io/client-go/testing:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -31,6 +31,7 @@ import (
|
|||||||
// RunNodeDrain shows the canonical way to drain a node.
|
// RunNodeDrain shows the canonical way to drain a node.
|
||||||
// You should first cordon the node, e.g. using RunCordonOrUncordon
|
// You should first cordon the node, e.g. using RunCordonOrUncordon
|
||||||
func RunNodeDrain(drainer *Helper, nodeName string) error {
|
func RunNodeDrain(drainer *Helper, nodeName string) error {
|
||||||
|
// TODO(justinsb): Ensure we have adequate e2e coverage of this function in library consumers
|
||||||
list, errs := drainer.GetPodsForDeletion(nodeName)
|
list, errs := drainer.GetPodsForDeletion(nodeName)
|
||||||
if errs != nil {
|
if errs != nil {
|
||||||
return utilerrors.NewAggregate(errs)
|
return utilerrors.NewAggregate(errs)
|
||||||
@ -48,6 +49,7 @@ func RunNodeDrain(drainer *Helper, nodeName string) error {
|
|||||||
|
|
||||||
// RunCordonOrUncordon demonstrates the canonical way to cordon or uncordon a Node
|
// RunCordonOrUncordon demonstrates the canonical way to cordon or uncordon a Node
|
||||||
func RunCordonOrUncordon(drainer *Helper, node *corev1.Node, desired bool) error {
|
func RunCordonOrUncordon(drainer *Helper, node *corev1.Node, desired bool) error {
|
||||||
|
// TODO(justinsb): Ensure we have adequate e2e coverage of this function in library consumers
|
||||||
c := NewCordonHelper(node)
|
c := NewCordonHelper(node)
|
||||||
|
|
||||||
if updateRequired := c.UpdateIfRequired(desired); !updateRequired {
|
if updateRequired := c.UpdateIfRequired(desired); !updateRequired {
|
||||||
|
@ -19,16 +19,23 @@ package drain
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
policyv1beta1 "k8s.io/api/policy/v1beta1"
|
||||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
|
"k8s.io/client-go/kubernetes/fake"
|
||||||
|
ktest "k8s.io/client-go/testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDeletePods(t *testing.T) {
|
func TestDeletePods(t *testing.T) {
|
||||||
@ -145,3 +152,155 @@ func createPods(ifCreateNewPods bool) (map[string]corev1.Pod, []corev1.Pod) {
|
|||||||
}
|
}
|
||||||
return podMap, podSlice
|
return podMap, podSlice
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// addEvictionSupport implements simple fake eviction support on the fake.Clientset
|
||||||
|
func addEvictionSupport(t *testing.T, k *fake.Clientset) {
|
||||||
|
podsEviction := metav1.APIResource{
|
||||||
|
Name: "pods/eviction",
|
||||||
|
Kind: "Eviction",
|
||||||
|
Group: "",
|
||||||
|
Version: "v1",
|
||||||
|
}
|
||||||
|
coreResources := &metav1.APIResourceList{
|
||||||
|
GroupVersion: "v1",
|
||||||
|
APIResources: []metav1.APIResource{podsEviction},
|
||||||
|
}
|
||||||
|
|
||||||
|
policyResources := &metav1.APIResourceList{
|
||||||
|
GroupVersion: "policy/v1",
|
||||||
|
}
|
||||||
|
k.Resources = append(k.Resources, coreResources, policyResources)
|
||||||
|
|
||||||
|
// Delete pods when evict is called
|
||||||
|
k.PrependReactor("create", "pods", func(action ktest.Action) (bool, runtime.Object, error) {
|
||||||
|
if action.GetSubresource() != "eviction" {
|
||||||
|
return false, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
eviction := *action.(ktest.CreateAction).GetObject().(*policyv1beta1.Eviction)
|
||||||
|
// Avoid the lock
|
||||||
|
go func() {
|
||||||
|
err := k.CoreV1().Pods(eviction.Namespace).Delete(eviction.Name, &metav1.DeleteOptions{})
|
||||||
|
if err != nil {
|
||||||
|
// Errorf because we can't call Fatalf from another goroutine
|
||||||
|
t.Errorf("failed to delete pod: %s/%s", eviction.Namespace, eviction.Name)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return true, nil, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCheckEvictionSupport(t *testing.T) {
|
||||||
|
for _, evictionSupported := range []bool{true, false} {
|
||||||
|
evictionSupported := evictionSupported
|
||||||
|
t.Run(fmt.Sprintf("evictionSupported=%v", evictionSupported),
|
||||||
|
func(t *testing.T) {
|
||||||
|
k := fake.NewSimpleClientset()
|
||||||
|
if evictionSupported {
|
||||||
|
addEvictionSupport(t, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
apiGroup, err := CheckEvictionSupport(k)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
expectedAPIGroup := ""
|
||||||
|
if evictionSupported {
|
||||||
|
expectedAPIGroup = "policy/v1"
|
||||||
|
}
|
||||||
|
if apiGroup != expectedAPIGroup {
|
||||||
|
t.Fatalf("expected apigroup %q, actual=%q", expectedAPIGroup, apiGroup)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteOrEvict(t *testing.T) {
|
||||||
|
for _, evictionSupported := range []bool{true, false} {
|
||||||
|
evictionSupported := evictionSupported
|
||||||
|
t.Run(fmt.Sprintf("evictionSupported=%v", evictionSupported),
|
||||||
|
func(t *testing.T) {
|
||||||
|
h := &Helper{
|
||||||
|
Out: os.Stdout,
|
||||||
|
GracePeriodSeconds: 10,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create 4 pods, and try to remove the first 2
|
||||||
|
var expectedEvictions []policyv1beta1.Eviction
|
||||||
|
var create []runtime.Object
|
||||||
|
deletePods := []corev1.Pod{}
|
||||||
|
for i := 1; i <= 4; i++ {
|
||||||
|
pod := &corev1.Pod{}
|
||||||
|
pod.Name = fmt.Sprintf("mypod-%d", i)
|
||||||
|
pod.Namespace = "default"
|
||||||
|
|
||||||
|
create = append(create, pod)
|
||||||
|
if i <= 2 {
|
||||||
|
deletePods = append(deletePods, *pod)
|
||||||
|
|
||||||
|
if evictionSupported {
|
||||||
|
eviction := policyv1beta1.Eviction{}
|
||||||
|
eviction.Kind = "Eviction"
|
||||||
|
eviction.APIVersion = "policy/v1"
|
||||||
|
eviction.Namespace = pod.Namespace
|
||||||
|
eviction.Name = pod.Name
|
||||||
|
|
||||||
|
gracePeriodSeconds := int64(h.GracePeriodSeconds)
|
||||||
|
eviction.DeleteOptions = &metav1.DeleteOptions{
|
||||||
|
GracePeriodSeconds: &gracePeriodSeconds,
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedEvictions = append(expectedEvictions, eviction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the fake client
|
||||||
|
k := fake.NewSimpleClientset(create...)
|
||||||
|
if evictionSupported {
|
||||||
|
addEvictionSupport(t, k)
|
||||||
|
}
|
||||||
|
h.Client = k
|
||||||
|
|
||||||
|
// Do the eviction
|
||||||
|
if err := h.DeleteOrEvictPods(deletePods); err != nil {
|
||||||
|
t.Fatalf("error from DeleteOrEvictPods: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that other pods are still there
|
||||||
|
var remainingPods []string
|
||||||
|
{
|
||||||
|
podList, err := k.CoreV1().Pods("").List(metav1.ListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error listing pods: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pod := range podList.Items {
|
||||||
|
remainingPods = append(remainingPods, pod.Namespace+"/"+pod.Name)
|
||||||
|
}
|
||||||
|
sort.Strings(remainingPods)
|
||||||
|
}
|
||||||
|
expected := []string{"default/mypod-3", "default/mypod-4"}
|
||||||
|
if !reflect.DeepEqual(remainingPods, expected) {
|
||||||
|
t.Errorf("unexpected remaining pods after DeleteOrEvictPods; actual %v; expected %v", remainingPods, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that pods were evicted as expected
|
||||||
|
var actualEvictions []policyv1beta1.Eviction
|
||||||
|
for _, action := range k.Actions() {
|
||||||
|
if action.GetVerb() != "create" || action.GetResource().Resource != "pods" || action.GetSubresource() != "eviction" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
eviction := *action.(ktest.CreateAction).GetObject().(*policyv1beta1.Eviction)
|
||||||
|
actualEvictions = append(actualEvictions, eviction)
|
||||||
|
}
|
||||||
|
sort.Slice(actualEvictions, func(i, j int) bool {
|
||||||
|
return actualEvictions[i].Name < actualEvictions[j].Name
|
||||||
|
})
|
||||||
|
if !reflect.DeepEqual(actualEvictions, expectedEvictions) {
|
||||||
|
t.Errorf("unexpected evictions; actual %v; expected %v", actualEvictions, expectedEvictions)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user