1
16
17 package remote
18
19 import (
20 "fmt"
21 "os"
22 "os/exec"
23 "path/filepath"
24 "regexp"
25 "strings"
26 "time"
27
28 "k8s.io/klog/v2"
29
30 "k8s.io/kubernetes/test/e2e_node/builder"
31 "k8s.io/kubernetes/test/e2e_node/system"
32 "k8s.io/kubernetes/test/utils"
33 )
34
35
36 type NodeE2ERemote struct{}
37
38
39 func init() {
40 RegisterTestSuite("default", &NodeE2ERemote{})
41 }
42
43
44 func (n *NodeE2ERemote) SetupTestPackage(tardir, systemSpecName string) error {
45
46 if err := builder.BuildGo(); err != nil {
47 return fmt.Errorf("failed to build the dependencies: %w", err)
48 }
49
50
51 buildOutputDir, err := utils.GetK8sBuildOutputDir(builder.IsDockerizedBuild(), builder.GetTargetBuildArch())
52 if err != nil {
53 return fmt.Errorf("failed to locate kubernetes build output directory: %w", err)
54 }
55
56 rootDir, err := utils.GetK8sRootDir()
57 if err != nil {
58 return fmt.Errorf("failed to locate kubernetes root directory: %w", err)
59 }
60
61
62 requiredBins := []string{"kubelet", "e2e_node.test", "ginkgo", "mounter", "gcp-credential-provider"}
63 for _, bin := range requiredBins {
64 source := filepath.Join(buildOutputDir, bin)
65 klog.V(2).Infof("Copying binaries from %s", source)
66 if _, err := os.Stat(source); err != nil {
67 return fmt.Errorf("failed to locate test binary %s: %w", bin, err)
68 }
69 out, err := exec.Command("cp", source, filepath.Join(tardir, bin)).CombinedOutput()
70 if err != nil {
71 return fmt.Errorf("failed to copy %q: %v Output: %q", bin, err, out)
72 }
73 }
74
75 if systemSpecName != "" {
76
77 source := filepath.Join(rootDir, system.SystemSpecPath, systemSpecName+".yaml")
78 if _, err := os.Stat(source); err != nil {
79 return fmt.Errorf("failed to locate system spec %q: %w", source, err)
80 }
81 out, err := exec.Command("cp", source, tardir).CombinedOutput()
82 if err != nil {
83 return fmt.Errorf("failed to copy system spec %q: %v, output: %q", source, err, out)
84 }
85 }
86
87 return nil
88 }
89
90
91
92 func prependMemcgNotificationFlag(args string) string {
93 return "--kubelet-flags=--kernel-memcg-notification=true " + args
94 }
95
96
97
98 func prependCredentialProviderFlag(args, workspace string) string {
99 credentialProviderConfig := filepath.Join(workspace, "credential-provider.yaml")
100 featureGateFlag := "--kubelet-flags=--feature-gates=DisableKubeletCloudCredentialProviders=true"
101 configFlag := fmt.Sprintf("--kubelet-flags=--image-credential-provider-config=%s", credentialProviderConfig)
102 binFlag := fmt.Sprintf("--kubelet-flags=--image-credential-provider-bin-dir=%s", workspace)
103 return fmt.Sprintf("%s %s %s %s", featureGateFlag, configFlag, binFlag, args)
104 }
105
106
107 func osSpecificActions(args, host, workspace string) (string, error) {
108 output, err := getOSDistribution(host)
109 if err != nil {
110 return "", fmt.Errorf("issue detecting node's OS via node's /etc/os-release. Err: %v, Output:\n%s", err, output)
111 }
112 switch {
113 case strings.Contains(output, "fedora"), strings.Contains(output, "rhcos"),
114 strings.Contains(output, "centos"), strings.Contains(output, "rhel"):
115 return args, setKubeletSELinuxLabels(host, workspace)
116 case strings.Contains(output, "gci"), strings.Contains(output, "cos"):
117 args = prependMemcgNotificationFlag(args)
118 return prependCredentialProviderFlag(args, workspace), nil
119 case strings.Contains(output, "ubuntu"):
120 args = prependCredentialProviderFlag(args, workspace)
121 return prependMemcgNotificationFlag(args), nil
122 case strings.Contains(output, "amzn"):
123 args = prependCredentialProviderFlag(args, workspace)
124 return prependMemcgNotificationFlag(args), nil
125 }
126 return args, nil
127 }
128
129
130
131 func setKubeletSELinuxLabels(host, workspace string) error {
132 cmd := getSSHCommand(" && ",
133 fmt.Sprintf("/usr/bin/chcon -u system_u -r object_r -t kubelet_exec_t %s", filepath.Join(workspace, "kubelet")),
134 fmt.Sprintf("/usr/bin/chcon -u system_u -r object_r -t bin_t %s", filepath.Join(workspace, "e2e_node.test")),
135 fmt.Sprintf("/usr/bin/chcon -u system_u -r object_r -t bin_t %s", filepath.Join(workspace, "ginkgo")),
136 fmt.Sprintf("/usr/bin/chcon -u system_u -r object_r -t bin_t %s", filepath.Join(workspace, "mounter")),
137 fmt.Sprintf("/usr/bin/chcon -R -u system_u -r object_r -t bin_t %s", filepath.Join(workspace, "cni", "bin/")),
138 )
139 output, err := SSH(host, "sh", "-c", cmd)
140 if err != nil {
141 return fmt.Errorf("Unable to apply SELinux labels. Err: %v, Output:\n%s", err, output)
142 }
143 return nil
144 }
145
146 func getOSDistribution(host string) (string, error) {
147 output, err := SSH(host, "cat", "/etc/os-release")
148 if err != nil {
149 return "", fmt.Errorf("issue detecting node's OS via node's /etc/os-release. Err: %v, Output:\n%s", err, output)
150 }
151
152 var re = regexp.MustCompile(`(?m)^ID="?(\w+)"?`)
153 subMatch := re.FindStringSubmatch(output)
154 if len(subMatch) > 0 {
155 return subMatch[1], nil
156 }
157
158 return "", fmt.Errorf("Unable to parse os-release for the host, %s", host)
159 }
160
161
162 func (n *NodeE2ERemote) RunTest(host, workspace, results, imageDesc, junitFilePrefix, testArgs, ginkgoArgs, systemSpecName, extraEnvs, runtimeConfig string, timeout time.Duration) (string, error) {
163
164
165 if err := setupCNI(host, workspace); err != nil {
166 return "", err
167 }
168
169
170 if err := configureFirewall(host); err != nil {
171 return "", err
172 }
173
174
175 if err := configureCredentialProvider(host, workspace); err != nil {
176 return "", err
177 }
178
179
180 cleanupNodeProcesses(host)
181
182 testArgs, err := osSpecificActions(testArgs, host, workspace)
183 if err != nil {
184 return "", err
185 }
186
187 systemSpecFile := ""
188 if systemSpecName != "" {
189 systemSpecFile = systemSpecName + ".yaml"
190 }
191
192 outputGinkgoFile := filepath.Join(results, fmt.Sprintf("%s-ginkgo.log", host))
193
194
195 klog.V(2).Infof("Starting tests on %q", host)
196 cmd := getSSHCommand(" && ",
197 fmt.Sprintf("cd %s", workspace),
198
199 fmt.Sprintf("set -o pipefail; timeout -k 30s %fs ./ginkgo %s ./e2e_node.test -- --system-spec-name=%s --system-spec-file=%s --extra-envs=%s --runtime-config=%s --v 4 --node-name=%s --report-dir=%s --report-prefix=%s --image-description=\"%s\" %s 2>&1 | tee -i %s",
200 timeout.Seconds(), ginkgoArgs, systemSpecName, systemSpecFile, extraEnvs, runtimeConfig, host, results, junitFilePrefix, imageDesc, testArgs, outputGinkgoFile),
201 )
202 return SSH(host, "/bin/bash", "-c", cmd)
203 }
204
View as plain text