2323 kubeconfigPath string
2424 clientset kubernetes.Interface
2525 testNamespace = "rltop-test"
26+ clusterName = "kubectl-rltop-test"
2627)
2728
2829func TestMain (m * testing.M ) {
@@ -42,17 +43,22 @@ func TestMain(m *testing.M) {
4243}
4344
4445func setup () error {
45- // Check if k3s is already running
46- if isK3sRunning () {
47- fmt .Println ("k3s is already running, using existing cluster" )
48- kubeconfigPath = "/etc/rancher/k3s/k3s.yaml"
46+ // Check if kind cluster already exists
47+ if isKindClusterExists () {
48+ fmt .Printf ("kind cluster '%s' already exists, using existing cluster\n " , clusterName )
4949 } else {
50- // Install and start k3s
51- fmt .Println ( "Installing k3s ..." )
52- if err := installK3s (); err != nil {
53- return fmt .Errorf ("failed to install k3s : %w" , err )
50+ // Create kind cluster
51+ fmt .Printf ( "Creating kind cluster '%s' ...\n " , clusterName )
52+ if err := createKindCluster (); err != nil {
53+ return fmt .Errorf ("failed to create kind cluster : %w" , err )
5454 }
55- kubeconfigPath = "/etc/rancher/k3s/k3s.yaml"
55+ }
56+
57+ // Get kubeconfig path for kind cluster
58+ var err error
59+ kubeconfigPath , err = getKindKubeconfig ()
60+ if err != nil {
61+ return fmt .Errorf ("failed to get kind kubeconfig: %w" , err )
5662 }
5763
5864 // Wait for cluster to be ready
@@ -108,38 +114,130 @@ func teardown() {
108114 // Clean up test namespace
109115 clientset .CoreV1 ().Namespaces ().Delete (ctx , testNamespace , metav1.DeleteOptions {})
110116 }
117+ // Note: We don't delete the kind cluster here to allow reuse
118+ // Users can delete it manually with: kind delete cluster --name kubectl-rltop-test
111119}
112120
113- func isK3sRunning () bool {
114- cmd := exec .Command ("systemctl" , "is-active" , "--quiet" , "k3s" )
115- return cmd .Run () == nil
121+ func isKindClusterExists () bool {
122+ cmd := exec .Command ("kind" , "get" , "clusters" )
123+ output , err := cmd .Output ()
124+ if err != nil {
125+ return false
126+ }
127+ return strings .Contains (string (output ), clusterName )
116128}
117129
118- func installK3s () error {
119- // Check if k3s is already installed
120- if _ , err := exec .LookPath ("k3s" ); err == nil {
121- // k3s is installed, try to start it
122- cmd := exec .Command ("sudo" , "systemctl" , "start" , "k3s" )
123- if err := cmd .Run (); err != nil {
124- return fmt .Errorf ("failed to start k3s: %w" , err )
125- }
126- return nil
130+ func createKindCluster () error {
131+ // Check if kind is installed
132+ if _ , err := exec .LookPath ("kind" ); err != nil {
133+ return fmt .Errorf ("kind is not installed. Please install it: https://kind.sigs.k8s.io/docs/user/quick-start/#installation" )
134+ }
135+
136+ // Check if Docker is running
137+ if err := checkDockerRunning (); err != nil {
138+ return fmt .Errorf ("docker is not running: %w. Please start Docker" , err )
139+ }
140+
141+ // Create kind cluster with metrics-server enabled
142+ // We use a config that enables metrics-server
143+ config := `kind: Cluster
144+ apiVersion: kind.x-k8s.io/v1alpha4
145+ nodes:
146+ - role: control-plane
147+ kubeadmConfigPatches:
148+ - |
149+ kind: InitConfiguration
150+ nodeRegistration:
151+ kubeletExtraArgs:
152+ node-labels: "ingress-ready=true"
153+ extraPortMappings:
154+ - containerPort: 80
155+ hostPort: 80
156+ protocol: TCP
157+ - containerPort: 443
158+ hostPort: 443
159+ protocol: TCP`
160+
161+ // Write config to temp file
162+ tmpfile , err := os .CreateTemp ("" , "kind-config-*.yaml" )
163+ if err != nil {
164+ return fmt .Errorf ("failed to create temp config file: %w" , err )
165+ }
166+ defer os .Remove (tmpfile .Name ())
167+
168+ if _ , err := tmpfile .WriteString (config ); err != nil {
169+ return fmt .Errorf ("failed to write config: %w" , err )
170+ }
171+ if err := tmpfile .Close (); err != nil {
172+ return fmt .Errorf ("failed to close config file: %w" , err )
173+ }
174+
175+ // Create cluster
176+ cmd := exec .Command ("kind" , "create" , "cluster" , "--name" , clusterName , "--config" , tmpfile .Name ())
177+ cmd .Stdout = os .Stdout
178+ cmd .Stderr = os .Stderr
179+ if err := cmd .Run (); err != nil {
180+ return fmt .Errorf ("failed to create kind cluster: %w" , err )
127181 }
128182
129- // Install k3s
130- cmd := exec .Command ("sh" , "-c" , "curl -sfL https://get.k3s.io | sh -" )
183+ // Get kubeconfig for the newly created cluster
184+ kubeconfig , err := getKindKubeconfig ()
185+ if err != nil {
186+ return fmt .Errorf ("failed to get kubeconfig after cluster creation: %w" , err )
187+ }
188+
189+ // Install metrics-server
190+ fmt .Println ("Installing metrics-server..." )
191+ cmd = exec .Command ("kubectl" , "apply" , "-f" , "https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml" )
192+ cmd .Env = append (os .Environ (), fmt .Sprintf ("KUBECONFIG=%s" , kubeconfig ))
131193 cmd .Stdout = os .Stdout
132194 cmd .Stderr = os .Stderr
133195 if err := cmd .Run (); err != nil {
134- return fmt .Errorf ("failed to install k3s : %w" , err )
196+ return fmt .Errorf ("failed to install metrics-server : %w" , err )
135197 }
136198
137- // Wait a bit for k3s to start
138- time .Sleep (5 * time .Second )
199+ // Patch metrics-server to work in kind (disable TLS verification)
200+ cmd = exec .Command ("kubectl" , "patch" , "deployment" , "metrics-server" , "-n" , "kube-system" ,
201+ "--type" , "json" , "-p" , `[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--kubelet-insecure-tls"}]` )
202+ cmd .Env = append (os .Environ (), fmt .Sprintf ("KUBECONFIG=%s" , kubeconfig ))
203+ cmd .Stdout = os .Stdout
204+ cmd .Stderr = os .Stderr
205+ if err := cmd .Run (); err != nil {
206+ return fmt .Errorf ("failed to patch metrics-server: %w" , err )
207+ }
139208
140209 return nil
141210}
142211
212+ func getKindKubeconfig () (string , error ) {
213+ // Get kubeconfig from kind
214+ cmd := exec .Command ("kind" , "get" , "kubeconfig" , "--name" , clusterName )
215+ output , err := cmd .Output ()
216+ if err != nil {
217+ return "" , fmt .Errorf ("failed to get kubeconfig: %w" , err )
218+ }
219+
220+ // Write to temp file
221+ tmpfile , err := os .CreateTemp ("" , "kubeconfig-*.yaml" )
222+ if err != nil {
223+ return "" , fmt .Errorf ("failed to create temp kubeconfig file: %w" , err )
224+ }
225+
226+ if _ , err := tmpfile .Write (output ); err != nil {
227+ return "" , fmt .Errorf ("failed to write kubeconfig: %w" , err )
228+ }
229+ if err := tmpfile .Close (); err != nil {
230+ return "" , fmt .Errorf ("failed to close kubeconfig file: %w" , err )
231+ }
232+
233+ return tmpfile .Name (), nil
234+ }
235+
236+ func checkDockerRunning () error {
237+ cmd := exec .Command ("docker" , "info" )
238+ return cmd .Run ()
239+ }
240+
143241func waitForClusterReady (timeout time.Duration ) error {
144242 ctx , cancel := context .WithTimeout (context .Background (), timeout )
145243 defer cancel ()
@@ -150,6 +248,7 @@ func waitForClusterReady(timeout time.Duration) error {
150248 return fmt .Errorf ("timeout waiting for cluster to be ready" )
151249 default :
152250 cmd := exec .Command ("kubectl" , "--kubeconfig" , kubeconfigPath , "get" , "nodes" , "--no-headers" )
251+ cmd .Env = append (os .Environ (), fmt .Sprintf ("KUBECONFIG=%s" , kubeconfigPath ))
153252 if err := cmd .Run (); err == nil {
154253 return nil
155254 }
@@ -169,7 +268,10 @@ func waitForMetricsServer(timeout time.Duration) error {
169268 default :
170269 cmd := exec .Command ("kubectl" , "--kubeconfig" , kubeconfigPath , "wait" , "--for=condition=ready" ,
171270 "pod" , "-l" , "k8s-app=metrics-server" , "-n" , "kube-system" , "--timeout=30s" )
271+ cmd .Env = append (os .Environ (), fmt .Sprintf ("KUBECONFIG=%s" , kubeconfigPath ))
172272 if err := cmd .Run (); err == nil {
273+ // Wait a bit more for metrics to be available
274+ time .Sleep (5 * time .Second )
173275 return nil
174276 }
175277 time .Sleep (5 * time .Second )
0 commit comments