k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/test/e2e_node/environment/conformance.go (about) 1 /* 2 Copyright 2015 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 // Build the binary with `go build conformance.go`, then run the conformance binary on a node candidate. If compiled 18 // on a non-linux machine, must be cross compiled for the host. 19 package main 20 21 import ( 22 "flag" 23 "fmt" 24 "net" 25 "os/exec" 26 "regexp" 27 "strings" 28 29 "errors" 30 "os" 31 ) 32 33 const success = "\033[0;32mSUCCESS\033[0m" 34 const failed = "\033[0;31mFAILED\033[0m" 35 const notConfigured = "\033[0;34mNOT CONFIGURED\033[0m" 36 const skipped = "\033[0;34mSKIPPED\033[0m" 37 38 var checkFlag = flag.String( 39 "check", "all", "what to check for conformance. One or more of all,container-runtime,daemons,dns,firewall,kernel") 40 41 func init() { 42 // Set this to false to undo util/logs.go settings it to true. Prevents cadvisor log spam. 43 // Remove this once util/logs.go stops setting the flag to true. 44 flag.Set("logtostderr", "false") 45 } 46 47 // TODO: Should we write an e2e test for this? 48 func main() { 49 flag.Parse() 50 o := strings.Split(*checkFlag, ",") 51 errs := check(o...) 52 if len(errs) > 0 { 53 os.Exit(1) 54 } else { 55 os.Exit(0) 56 } 57 } 58 59 // check returns errors found while checking the provided components. Will prevent errors to stdout. 60 func check(options ...string) []error { 61 errs := []error{} 62 for _, c := range options { 63 switch c { 64 case "all": 65 errs = appendNotNil(errs, kernel()) 66 errs = appendNotNil(errs, daemons()) 67 errs = appendNotNil(errs, firewall()) 68 errs = appendNotNil(errs, dns()) 69 case "daemons": 70 errs = appendNotNil(errs, daemons()) 71 case "dns": 72 errs = appendNotNil(errs, dns()) 73 case "firewall": 74 errs = appendNotNil(errs, firewall()) 75 case "kernel": 76 errs = appendNotNil(errs, kernel()) 77 default: 78 fmt.Printf("Unrecognized option %s\n", c) 79 errs = append(errs, fmt.Errorf("Unrecognized option %s", c)) 80 } 81 } 82 return errs 83 } 84 85 const kubeletClusterDNSRegexStr = `\/kubelet.*--cluster-dns=(\S+) ` 86 const kubeletClusterDomainRegexStr = `\/kubelet.*--cluster-domain=(\S+)` 87 88 // dns checks that cluster dns has been properly configured and can resolve the kubernetes.default service 89 func dns() error { 90 dnsRegex, err := regexp.Compile(kubeletClusterDNSRegexStr) 91 if err != nil { 92 // This should never happen and can only be fixed by changing the code 93 panic(err) 94 } 95 domainRegex, err := regexp.Compile(kubeletClusterDomainRegexStr) 96 if err != nil { 97 // This should never happen and can only be fixed by changing the code 98 panic(err) 99 } 100 101 h, err := net.LookupHost("kubernetes.default") 102 if err == nil { 103 return printSuccess("Dns Check (Optional): %s", success) 104 } 105 if len(h) > 0 { 106 return printSuccess("Dns Check (Optional): %s", success) 107 } 108 109 kubecmd, err := exec.Command("ps", "aux").CombinedOutput() 110 if err != nil { 111 // Executing ps aux shouldn't have failed 112 panic(err) 113 } 114 115 // look for the dns flag and parse the value 116 dns := dnsRegex.FindStringSubmatch(string(kubecmd)) 117 if len(dns) < 2 { 118 return printSuccess( 119 "Dns Check (Optional): %s No hosts resolve to kubernetes.default. kubelet will need to set "+ 120 "--cluster-dns and --cluster-domain when run", notConfigured) 121 } 122 123 // look for the domain flag and parse the value 124 domain := domainRegex.FindStringSubmatch(string(kubecmd)) 125 if len(domain) < 2 { 126 return printSuccess( 127 "Dns Check (Optional): %s No hosts resolve to kubernetes.default. kubelet will need to set "+ 128 "--cluster-dns and --cluster-domain when run", notConfigured) 129 } 130 131 // do a lookup with the flags the kubelet is running with 132 nsArgs := []string{"-q=a", fmt.Sprintf("kubernetes.default.%s", domain[1]), dns[1]} 133 if err = exec.Command("nslookup", nsArgs...).Run(); err != nil { 134 // Mark this as failed since there was a clear intention to set it up, but it is done so improperly 135 return printError( 136 "Dns Check (Optional): %s No hosts resolve to kubernetes.default kubelet found, but cannot resolve "+ 137 "kubernetes.default using nslookup %s error: %v", failed, strings.Join(nsArgs, " "), err) 138 } 139 140 // Can resolve kubernetes.default using the kubelete dns and domain values 141 return printSuccess("Dns Check (Optional): %s", success) 142 } 143 144 const cmdlineCGroupMemory = `cgroup_enable=memory` 145 146 // kernel checks that the kernel has been configured correctly to support the required cgroup features 147 func kernel() error { 148 cmdline, err := os.ReadFile("/proc/cmdline") 149 if err != nil { 150 return printError("Kernel Command Line Check %s: Could not check /proc/cmdline", failed) 151 } 152 if !strings.Contains(string(cmdline), cmdlineCGroupMemory) { 153 return printError("Kernel Command Line Check %s: cgroup_enable=memory not enabled in /proc/cmdline", failed) 154 } 155 return printSuccess("Kernel Command Line %s", success) 156 } 157 158 const iptablesInputRegexStr = `Chain INPUT \(policy DROP\)` 159 const iptablesForwardRegexStr = `Chain FORWARD \(policy DROP\)` 160 161 // firewall checks that iptables does not have common firewall rules setup that would disrupt traffic 162 func firewall() error { 163 out, err := exec.Command("iptables", "-L", "INPUT").CombinedOutput() 164 if err != nil { 165 return printSuccess("Firewall IPTables Check %s: Could not run iptables", skipped) 166 } 167 inputRegex, err := regexp.Compile(iptablesInputRegexStr) 168 if err != nil { 169 // This should never happen and can only be fixed by changing the code 170 panic(err) 171 } 172 if inputRegex.Match(out) { 173 return printError("Firewall IPTables Check %s: Found INPUT rule matching %s", failed, iptablesInputRegexStr) 174 } 175 176 // Check GCE forward rules 177 out, err = exec.Command("iptables", "-L", "FORWARD").CombinedOutput() 178 if err != nil { 179 return printSuccess("Firewall IPTables Check %s: Could not run iptables", skipped) 180 } 181 forwardRegex, err := regexp.Compile(iptablesForwardRegexStr) 182 if err != nil { 183 // This should never happen and can only be fixed by changing the code 184 panic(err) 185 } 186 if forwardRegex.Match(out) { 187 return printError("Firewall IPTables Check %s: Found FORWARD rule matching %s", failed, iptablesInputRegexStr) 188 } 189 190 return printSuccess("Firewall IPTables Check %s", success) 191 } 192 193 // daemons checks that the required node programs are running: kubelet and kube-proxy 194 func daemons() error { 195 if exec.Command("pgrep", "-f", "kubelet").Run() != nil { 196 return printError("Daemon Check %s: kubelet process not found", failed) 197 } 198 199 if exec.Command("pgrep", "-f", "kube-proxy").Run() != nil { 200 return printError("Daemon Check %s: kube-proxy process not found", failed) 201 } 202 203 return printSuccess("Daemon Check %s", success) 204 } 205 206 // printError provides its arguments to print a format string to the console (newline terminated) and returns an 207 // error with the same string 208 func printError(s string, args ...interface{}) error { 209 es := fmt.Sprintf(s, args...) 210 fmt.Println(es) 211 return errors.New(es) 212 } 213 214 // printSuccess provides its arguments to print a format string to the console (newline terminated) and returns nil 215 func printSuccess(s string, args ...interface{}) error { 216 fmt.Println(fmt.Sprintf(s, args...)) 217 return nil 218 } 219 220 // appendNotNil appends err to errs iff err is not nil 221 func appendNotNil(errs []error, err error) []error { 222 if err != nil { 223 return append(errs, err) 224 } 225 return errs 226 }