1
16
17 package daemonset
18
19 import (
20 "context"
21 "fmt"
22
23 appsv1 "k8s.io/api/apps/v1"
24 v1 "k8s.io/api/core/v1"
25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26 clientset "k8s.io/client-go/kubernetes"
27 "k8s.io/kubectl/pkg/util/podutils"
28 "k8s.io/kubernetes/pkg/controller/daemon"
29 "k8s.io/kubernetes/test/e2e/framework"
30 )
31
32 func NewDaemonSet(dsName, image string, labels map[string]string, volumes []v1.Volume, mounts []v1.VolumeMount, ports []v1.ContainerPort, args ...string) *appsv1.DaemonSet {
33 return &appsv1.DaemonSet{
34 ObjectMeta: metav1.ObjectMeta{
35 Name: dsName,
36 Labels: labels,
37 },
38 Spec: appsv1.DaemonSetSpec{
39 Selector: &metav1.LabelSelector{
40 MatchLabels: labels,
41 },
42 Template: v1.PodTemplateSpec{
43 ObjectMeta: metav1.ObjectMeta{
44 Labels: labels,
45 },
46 Spec: v1.PodSpec{
47 Containers: []v1.Container{
48 {
49 Name: "app",
50 Image: image,
51 Args: args,
52 Ports: ports,
53 VolumeMounts: mounts,
54 SecurityContext: &v1.SecurityContext{},
55 },
56 },
57 SecurityContext: &v1.PodSecurityContext{},
58 Volumes: volumes,
59 },
60 },
61 },
62 }
63 }
64
65 func CheckRunningOnAllNodes(ctx context.Context, f *framework.Framework, ds *appsv1.DaemonSet) (bool, error) {
66 nodeNames := SchedulableNodes(ctx, f.ClientSet, ds)
67 return CheckDaemonPodOnNodes(f, ds, nodeNames)(ctx)
68 }
69
70
71
72 func CheckPresentOnNodes(ctx context.Context, c clientset.Interface, ds *appsv1.DaemonSet, ns string, numNodes int) (bool, error) {
73 nodeNames := SchedulableNodes(ctx, c, ds)
74 if len(nodeNames) < numNodes {
75 return false, nil
76 }
77 return checkDaemonPodStateOnNodes(ctx, c, ds, ns, nodeNames, func(pod *v1.Pod) bool {
78 return pod.Status.Phase != v1.PodPending
79 })
80 }
81
82 func SchedulableNodes(ctx context.Context, c clientset.Interface, ds *appsv1.DaemonSet) []string {
83 nodeList, err := c.CoreV1().Nodes().List(ctx, metav1.ListOptions{})
84 framework.ExpectNoError(err)
85 nodeNames := make([]string, 0)
86 for _, node := range nodeList.Items {
87 shouldRun, _ := daemon.NodeShouldRunDaemonPod(&node, ds)
88 if !shouldRun {
89 framework.Logf("DaemonSet pods can't tolerate node %s with taints %+v, skip checking this node", node.Name, node.Spec.Taints)
90 continue
91 }
92 nodeNames = append(nodeNames, node.Name)
93 }
94 return nodeNames
95 }
96
97 func CheckDaemonPodOnNodes(f *framework.Framework, ds *appsv1.DaemonSet, nodeNames []string) func(ctx context.Context) (bool, error) {
98 return func(ctx context.Context) (bool, error) {
99 return checkDaemonPodStateOnNodes(ctx, f.ClientSet, ds, f.Namespace.Name, nodeNames, func(pod *v1.Pod) bool {
100 return podutils.IsPodAvailable(pod, ds.Spec.MinReadySeconds, metav1.Now())
101 })
102 }
103 }
104
105 func checkDaemonPodStateOnNodes(ctx context.Context, c clientset.Interface, ds *appsv1.DaemonSet, ns string, nodeNames []string, stateChecker func(*v1.Pod) bool) (bool, error) {
106 podList, err := c.CoreV1().Pods(ns).List(ctx, metav1.ListOptions{})
107 if err != nil {
108 framework.Logf("could not get the pod list: %v", err)
109 return false, nil
110 }
111 pods := podList.Items
112
113 nodesToPodCount := make(map[string]int)
114 for _, pod := range pods {
115 if !metav1.IsControlledBy(&pod, ds) {
116 continue
117 }
118 if pod.DeletionTimestamp != nil {
119 continue
120 }
121 if stateChecker(&pod) {
122 nodesToPodCount[pod.Spec.NodeName]++
123 }
124 }
125 framework.Logf("Number of nodes with available pods controlled by daemonset %s: %d", ds.Name, len(nodesToPodCount))
126
127
128 for _, nodeName := range nodeNames {
129 if nodesToPodCount[nodeName] != 1 {
130 framework.Logf("Node %s is running %d daemon pod, expected 1", nodeName, nodesToPodCount[nodeName])
131 return false, nil
132 }
133 }
134
135 framework.Logf("Number of running nodes: %d, number of available pods: %d in daemonset %s", len(nodeNames), len(nodesToPodCount), ds.Name)
136
137
138
139 return len(nodesToPodCount) == len(nodeNames), nil
140 }
141
142 func CheckDaemonStatus(ctx context.Context, f *framework.Framework, dsName string) error {
143 ds, err := f.ClientSet.AppsV1().DaemonSets(f.Namespace.Name).Get(ctx, dsName, metav1.GetOptions{})
144 if err != nil {
145 return err
146 }
147 desired, scheduled, ready := ds.Status.DesiredNumberScheduled, ds.Status.CurrentNumberScheduled, ds.Status.NumberReady
148 if desired != scheduled && desired != ready {
149 return fmt.Errorf("error in daemon status. DesiredScheduled: %d, CurrentScheduled: %d, Ready: %d", desired, scheduled, ready)
150 }
151 return nil
152 }
153
View as plain text