blob: 4c0ec2817353247c862442f473f454ec32ea3df2 [file] [log] [blame]
Lorenz Brunfc5dbc62020-05-28 12:18:07 +02001// Copyright 2020 The Monogon Project Authors.
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17package e2e
18
19import (
Serge Bazanski9104e382023-04-04 20:08:21 +020020 "bytes"
21 "context"
Lorenz Brunfc5dbc62020-05-28 12:18:07 +020022 "fmt"
Serge Bazanski9104e382023-04-04 20:08:21 +020023 "io"
24 "strings"
Lorenz Brunfc5dbc62020-05-28 12:18:07 +020025
26 appsv1 "k8s.io/api/apps/v1"
Serge Bazanski9104e382023-04-04 20:08:21 +020027 batchv1 "k8s.io/api/batch/v1"
Lorenz Brunfc5dbc62020-05-28 12:18:07 +020028 corev1 "k8s.io/api/core/v1"
29 "k8s.io/apimachinery/pkg/api/resource"
30 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
31 "k8s.io/apimachinery/pkg/util/intstr"
32 "k8s.io/client-go/kubernetes"
Lorenz Brunfc5dbc62020-05-28 12:18:07 +020033)
34
Serge Bazanski216fe7b2021-05-21 18:36:16 +020035// makeTestDeploymentSpec generates a Deployment spec for a single pod running
36// NGINX with a readiness probe. This allows verifying that the control plane
37// is capable of scheduling simple pods and that kubelet works, its runtime is
38// set up well enough to run a simple container and the network to the pod can
39// pass readiness probe traffic.
Lorenz Brunfc5dbc62020-05-28 12:18:07 +020040func makeTestDeploymentSpec(name string) *appsv1.Deployment {
41 return &appsv1.Deployment{
42 ObjectMeta: metav1.ObjectMeta{Name: name},
43 Spec: appsv1.DeploymentSpec{
44 Selector: &metav1.LabelSelector{MatchLabels: map[string]string{
45 "name": name,
46 }},
47 Template: corev1.PodTemplateSpec{
48 ObjectMeta: metav1.ObjectMeta{
49 Labels: map[string]string{
50 "name": name,
51 },
52 },
53 Spec: corev1.PodSpec{
54 Containers: []corev1.Container{
55 {
Serge Bazanski591d8082023-03-16 00:26:59 +010056 Name: "test",
57 ImagePullPolicy: corev1.PullNever,
58 Image: "bazel/metropolis/test/e2e/preseedtest:preseedtest_image",
Lorenz Brunfc5dbc62020-05-28 12:18:07 +020059 ReadinessProbe: &corev1.Probe{
Lorenz Brund13c1c62022-03-30 19:58:58 +020060 ProbeHandler: corev1.ProbeHandler{
Lorenz Brunfc5dbc62020-05-28 12:18:07 +020061 HTTPGet: &corev1.HTTPGetAction{Port: intstr.FromInt(80)},
62 },
63 },
64 },
65 },
66 },
67 },
68 },
69 }
70}
71
Lorenz Brun276a7462023-07-12 21:28:54 +020072// makeHTTPServerDeploymentSpec generates the deployment spec for the test HTTP
73// server.
74func makeHTTPServerDeploymentSpec(name string) *appsv1.Deployment {
75 oneVal := int32(1)
76 return &appsv1.Deployment{
77 ObjectMeta: metav1.ObjectMeta{Name: name},
78 Spec: appsv1.DeploymentSpec{
79 Selector: &metav1.LabelSelector{MatchLabels: map[string]string{
80 "name": name,
81 }},
82 Replicas: &oneVal,
83 Template: corev1.PodTemplateSpec{
84 ObjectMeta: metav1.ObjectMeta{
85 Labels: map[string]string{
86 "name": name,
87 },
88 },
89 Spec: corev1.PodSpec{
90 Containers: []corev1.Container{
91 {
92 Name: "test",
93 ImagePullPolicy: corev1.PullIfNotPresent,
94 Image: "test.monogon.internal/metropolis/test/e2e/httpserver/httpserver_image",
95 LivenessProbe: &corev1.Probe{
96 ProbeHandler: corev1.ProbeHandler{
97 HTTPGet: &corev1.HTTPGetAction{Port: intstr.FromInt(8080)},
98 },
99 },
100 },
101 },
102 },
103 },
104 },
105 }
106}
107
108// makeHTTPServerNodePortService generates the NodePort service spec
109// for testing the NodePort functionality.
110func makeHTTPServerNodePortService(name string) *corev1.Service {
111 return &corev1.Service{
112 ObjectMeta: metav1.ObjectMeta{Name: name},
113 Spec: corev1.ServiceSpec{
114 Type: corev1.ServiceTypeNodePort,
115 Selector: map[string]string{
116 "name": name,
117 },
118 Ports: []corev1.ServicePort{{
119 Name: name,
120 Protocol: corev1.ProtocolTCP,
121 Port: 80,
122 NodePort: 80,
123 TargetPort: intstr.FromInt(8080),
124 }},
125 },
126 }
127}
128
Serge Bazanski9104e382023-04-04 20:08:21 +0200129// makeSelftestSpec generates a Job spec for the E2E self-test image.
130func makeSelftestSpec(name string) *batchv1.Job {
131 one := int32(1)
132 return &batchv1.Job{
133 ObjectMeta: metav1.ObjectMeta{Name: name},
134 Spec: batchv1.JobSpec{
135 BackoffLimit: &one,
136 Template: corev1.PodTemplateSpec{
137 ObjectMeta: metav1.ObjectMeta{
138 Labels: map[string]string{
139 "job-name": name,
140 },
141 },
142 Spec: corev1.PodSpec{
143 Containers: []corev1.Container{
144 {
145 Name: "test",
Lorenz Brun150f24a2023-07-13 20:11:06 +0200146 ImagePullPolicy: corev1.PullIfNotPresent,
147 Image: "test.monogon.internal/metropolis/test/e2e/selftest/selftest_image",
Serge Bazanski9104e382023-04-04 20:08:21 +0200148 },
149 },
150 RestartPolicy: corev1.RestartPolicyOnFailure,
151 },
152 },
153 },
154 }
155}
156
Lorenz Brunfc5dbc62020-05-28 12:18:07 +0200157// makeTestStatefulSet generates a StatefulSet spec
Lorenz Brun37050122021-03-30 14:00:27 +0200158func makeTestStatefulSet(name string, volumeMode corev1.PersistentVolumeMode) *appsv1.StatefulSet {
Lorenz Brunfc5dbc62020-05-28 12:18:07 +0200159 return &appsv1.StatefulSet{
160 ObjectMeta: metav1.ObjectMeta{Name: name},
161 Spec: appsv1.StatefulSetSpec{
162 Selector: &metav1.LabelSelector{MatchLabels: map[string]string{
163 "name": name,
164 }},
165 VolumeClaimTemplates: []corev1.PersistentVolumeClaim{
166 {
167 ObjectMeta: metav1.ObjectMeta{Name: "www"},
168 Spec: corev1.PersistentVolumeClaimSpec{
169 AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce},
Tim Windelschmidtddc5e6a2024-04-23 23:44:34 +0200170 Resources: corev1.VolumeResourceRequirements{
Lorenz Brunfc5dbc62020-05-28 12:18:07 +0200171 Requests: map[corev1.ResourceName]resource.Quantity{corev1.ResourceStorage: resource.MustParse("50Mi")},
172 },
Lorenz Brun37050122021-03-30 14:00:27 +0200173 VolumeMode: &volumeMode,
Lorenz Brunfc5dbc62020-05-28 12:18:07 +0200174 },
175 },
176 },
177 Template: corev1.PodTemplateSpec{
178 ObjectMeta: metav1.ObjectMeta{
179 Labels: map[string]string{
180 "name": name,
181 },
182 },
183 Spec: corev1.PodSpec{
184 Containers: []corev1.Container{
185 {
Serge Bazanski591d8082023-03-16 00:26:59 +0100186 Name: "test",
187 ImagePullPolicy: corev1.PullNever,
188 Image: "bazel/metropolis/test/e2e/preseedtest:preseedtest_image",
Lorenz Brunfc5dbc62020-05-28 12:18:07 +0200189 ReadinessProbe: &corev1.Probe{
Lorenz Brund13c1c62022-03-30 19:58:58 +0200190 ProbeHandler: corev1.ProbeHandler{
Lorenz Brunfc5dbc62020-05-28 12:18:07 +0200191 HTTPGet: &corev1.HTTPGetAction{Port: intstr.FromInt(80)},
192 },
193 },
194 },
195 },
196 },
197 },
198 },
199 }
200}
Serge Bazanski9104e382023-04-04 20:08:21 +0200201
202func getPodLogLines(ctx context.Context, cs kubernetes.Interface, podName string, nlines int64) ([]string, error) {
203 logsR := cs.CoreV1().Pods("default").GetLogs(podName, &corev1.PodLogOptions{
204 TailLines: &nlines,
205 })
206 logs, err := logsR.Stream(ctx)
207 if err != nil {
208 return nil, fmt.Errorf("stream failed: %w", err)
209 }
210 var buf bytes.Buffer
211 _, err = io.Copy(&buf, logs)
212 if err != nil {
213 return nil, fmt.Errorf("copy failed: %w", err)
214 }
215 lineStr := strings.Trim(buf.String(), "\n")
216 lines := strings.Split(lineStr, "\n")
217 lines = lines[len(lines)-int(nlines):]
218 return lines, nil
219}