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