m/test/launch/cli/launch-cluster: fix metroctl path

os.Executable() returns the path to launch-cluster, not metroctl. This 
bug meant that trying to use kubectl on the cluster instead launched 
another cluster.

Change-Id: I94305c2688e55e2d2776d4a141d80b9f4ee3ec8f
Reviewed-on: https://review.monogon.dev/c/monogon/+/3352
Reviewed-by: Tim Windelschmidt <tim@monogon.tech>
Tested-by: Jenkins CI
diff --git a/metropolis/test/launch/cli/launch-cluster/BUILD.bazel b/metropolis/test/launch/cli/launch-cluster/BUILD.bazel
index 74067a7..250a1b1 100644
--- a/metropolis/test/launch/cli/launch-cluster/BUILD.bazel
+++ b/metropolis/test/launch/cli/launch-cluster/BUILD.bazel
@@ -4,14 +4,21 @@
 go_library(
     name = "launch-cluster_lib",
     srcs = ["main.go"],
+    data = [
+        "//metropolis/cli/metroctl",
+    ],
     importpath = "source.monogon.dev/metropolis/test/launch/cli/launch-cluster",
     visibility = ["//visibility:private"],
+    x_defs = {
+        "xMetroctlPath": "$(rlocationpath //metropolis/cli/metroctl )",
+    },
     deps = [
         "//metropolis/cli/flagdefs",
         "//metropolis/cli/metroctl/core",
         "//metropolis/node",
         "//metropolis/proto/common",
         "//metropolis/test/launch",
+        "@io_bazel_rules_go//go/runfiles:go_default_library",
     ],
 )
 
diff --git a/metropolis/test/launch/cli/launch-cluster/main.go b/metropolis/test/launch/cli/launch-cluster/main.go
index 3aeb319..abac980 100644
--- a/metropolis/test/launch/cli/launch-cluster/main.go
+++ b/metropolis/test/launch/cli/launch-cluster/main.go
@@ -24,12 +24,13 @@
 	"log"
 	"net"
 	"os"
-	"os/exec"
 	"os/signal"
 	"strconv"
 	"strings"
 	"time"
 
+	"github.com/bazelbuild/rules_go/go/runfiles"
+
 	"source.monogon.dev/metropolis/cli/flagdefs"
 	metroctl "source.monogon.dev/metropolis/cli/metroctl/core"
 	"source.monogon.dev/metropolis/node"
@@ -37,6 +38,25 @@
 	mlaunch "source.monogon.dev/metropolis/test/launch"
 )
 
+var (
+	// These are filled by bazel at linking time with the canonical path of
+	// their corresponding file. Inside the init function we resolve it
+	// with the rules_go runfiles package to the real path.
+	xMetroctlPath string
+)
+
+func init() {
+	var err error
+	for _, path := range []*string{
+		&xMetroctlPath,
+	} {
+		*path, err = runfiles.Rlocation(*path)
+		if err != nil {
+			panic(err)
+		}
+	}
+}
+
 const maxNodes = 256
 
 func nodeSetFlag(p *[]int, name string, usage string) {
@@ -176,19 +196,8 @@
 		time.Sleep(100 * time.Millisecond)
 	}
 
-	// If the user has metroctl in their path, use the metroctl from path as
-	// a credential plugin. Otherwise use the path to the currently-running
-	// metroctl.
-	metroctlPath := "metroctl"
-	if _, err := exec.LookPath("metroctl"); err != nil {
-		metroctlPath, err = os.Executable()
-		if err != nil {
-			log.Fatalf("Failed to create kubectl entry as metroctl is neither in PATH nor can its absolute path be determined: %v", err)
-		}
-	}
-
 	configName := "launch-cluster"
-	if err := metroctl.InstallKubeletConfig(ctx, metroctlPath, cl.ConnectOptions(), configName, apiserver); err != nil {
+	if err := metroctl.InstallKubeletConfig(ctx, xMetroctlPath, cl.ConnectOptions(), configName, apiserver); err != nil {
 		log.Fatalf("InstallKubeletConfig: %v", err)
 	}