blob: 3c1f95a15e35120217d26320ab3ed7278ce856a8 [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 (
20 "context"
21 "errors"
22 "fmt"
23 "time"
24
25 appsv1 "k8s.io/api/apps/v1"
26 corev1 "k8s.io/api/core/v1"
27 "k8s.io/apimachinery/pkg/api/resource"
28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29 "k8s.io/apimachinery/pkg/util/intstr"
30 "k8s.io/client-go/kubernetes"
31 "k8s.io/client-go/tools/clientcmd"
32
Serge Bazanski31370b02021-01-07 16:31:14 +010033 apb "source.monogon.dev/metropolis/proto/api"
Lorenz Brunfc5dbc62020-05-28 12:18:07 +020034)
35
Serge Bazanski216fe7b2021-05-21 18:36:16 +020036// GetKubeClientSet gets a Kubeconfig from the debug API and creates a K8s
37// ClientSet using it. The identity used has the system:masters group and thus
38// has RBAC access to everything.
Lorenz Bruned0503c2020-07-28 17:21:25 +020039func GetKubeClientSet(ctx context.Context, client apb.NodeDebugServiceClient, port uint16) (kubernetes.Interface, error) {
Lorenz Brunfc5dbc62020-05-28 12:18:07 +020040 var lastErr = errors.New("context canceled before any operation completed")
41 for {
Serge Bazanskiefdb6e92020-07-13 17:19:27 +020042 reqT, cancel := context.WithTimeout(ctx, 5*time.Second)
Lorenz Brun56ae5772020-07-08 18:04:48 +020043 defer cancel()
Serge Bazanskiefdb6e92020-07-13 17:19:27 +020044 res, err := client.GetDebugKubeconfig(reqT, &apb.GetDebugKubeconfigRequest{Id: "debug-user", Groups: []string{"system:masters"}})
Lorenz Brunfc5dbc62020-05-28 12:18:07 +020045 if err == nil {
46 rawClientConfig, err := clientcmd.NewClientConfigFromBytes([]byte(res.DebugKubeconfig))
47 if err != nil {
48 return nil, err // Invalid Kubeconfigs are immediately fatal
49 }
50
51 clientConfig, err := rawClientConfig.ClientConfig()
52 clientConfig.Host = fmt.Sprintf("localhost:%v", port)
53 clientSet, err := kubernetes.NewForConfig(clientConfig)
54 if err != nil {
55 return nil, err
56 }
57 return clientSet, nil
58 }
59 if err != nil && err == ctx.Err() {
60 return nil, lastErr
61 }
62 lastErr = err
63 select {
64 case <-ctx.Done():
65 return nil, lastErr
66 case <-time.After(1 * time.Second):
67 }
68 }
69}
70
Serge Bazanski216fe7b2021-05-21 18:36:16 +020071// makeTestDeploymentSpec generates a Deployment spec for a single pod running
72// NGINX with a readiness probe. This allows verifying that the control plane
73// is capable of scheduling simple pods and that kubelet works, its runtime is
74// set up well enough to run a simple container and the network to the pod can
75// pass readiness probe traffic.
Lorenz Brunfc5dbc62020-05-28 12:18:07 +020076func makeTestDeploymentSpec(name string) *appsv1.Deployment {
77 return &appsv1.Deployment{
78 ObjectMeta: metav1.ObjectMeta{Name: name},
79 Spec: appsv1.DeploymentSpec{
80 Selector: &metav1.LabelSelector{MatchLabels: map[string]string{
81 "name": name,
82 }},
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 // TODO(phab/T793): Build and preseed our own container images
94 Image: "nginx:alpine",
95 ReadinessProbe: &corev1.Probe{
96 Handler: corev1.Handler{
97 HTTPGet: &corev1.HTTPGetAction{Port: intstr.FromInt(80)},
98 },
99 },
100 },
101 },
102 },
103 },
104 },
105 }
106}
107
108// makeTestStatefulSet generates a StatefulSet spec
Lorenz Brun37050122021-03-30 14:00:27 +0200109func makeTestStatefulSet(name string, volumeMode corev1.PersistentVolumeMode) *appsv1.StatefulSet {
Lorenz Brunfc5dbc62020-05-28 12:18:07 +0200110 return &appsv1.StatefulSet{
111 ObjectMeta: metav1.ObjectMeta{Name: name},
112 Spec: appsv1.StatefulSetSpec{
113 Selector: &metav1.LabelSelector{MatchLabels: map[string]string{
114 "name": name,
115 }},
116 VolumeClaimTemplates: []corev1.PersistentVolumeClaim{
117 {
118 ObjectMeta: metav1.ObjectMeta{Name: "www"},
119 Spec: corev1.PersistentVolumeClaimSpec{
120 AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce},
121 Resources: corev1.ResourceRequirements{
122 Requests: map[corev1.ResourceName]resource.Quantity{corev1.ResourceStorage: resource.MustParse("50Mi")},
123 },
Lorenz Brun37050122021-03-30 14:00:27 +0200124 VolumeMode: &volumeMode,
Lorenz Brunfc5dbc62020-05-28 12:18:07 +0200125 },
126 },
127 },
128 Template: corev1.PodTemplateSpec{
129 ObjectMeta: metav1.ObjectMeta{
130 Labels: map[string]string{
131 "name": name,
132 },
133 },
134 Spec: corev1.PodSpec{
135 Containers: []corev1.Container{
136 {
137 Name: "test",
138 Image: "nginx:alpine",
139 ReadinessProbe: &corev1.Probe{
140 Handler: corev1.Handler{
141 HTTPGet: &corev1.HTTPGetAction{Port: intstr.FromInt(80)},
142 },
143 },
144 },
145 },
146 },
147 },
148 },
149 }
150}