root: move metropolis-specific tools to metropolis/, rename launch-multi2 to launch-cluster

Since we now have more than one top-level project it makes sense to not
have metropolis aliases in the root.

We also drive-by rename launch-multi2 to launch-cluster and bump it up
to three nodes.

Change-Id: Ic99065465006e0dace05bcc1f2a702d430014b84
Reviewed-on: https://review.monogon.dev/c/monogon/+/2764
Tested-by: Jenkins CI
Reviewed-by: Leopold Schabel <leo@monogon.tech>
diff --git a/metropolis/test/launch/cli/launch-cluster/BUILD.bazel b/metropolis/test/launch/cli/launch-cluster/BUILD.bazel
new file mode 100644
index 0000000..974258a
--- /dev/null
+++ b/metropolis/test/launch/cli/launch-cluster/BUILD.bazel
@@ -0,0 +1,33 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
+load("@bazel_skylib//rules:native_binary.bzl", "native_test")
+
+go_library(
+    name = "launch-cluster_lib",
+    srcs = ["main.go"],
+    importpath = "source.monogon.dev/metropolis/test/launch/cli/launch-cluster",
+    visibility = ["//visibility:private"],
+    deps = [
+        "//metropolis/cli/metroctl/core",
+        "//metropolis/cli/pkg/context",
+        "//metropolis/test/launch/cluster",
+    ],
+)
+
+go_binary(
+    name = "launch-cluster_bin",
+    data = [
+        "//metropolis/cli/metroctl",
+    ],
+    embed = [":launch-cluster_lib"],
+    visibility = ["//:__pkg__"],
+)
+
+# Wrap the binary in a native_test so that we can run it with the
+# `bazel test` command inside the sandbox.
+native_test(
+    name = "launch-cluster",
+    src = ":launch-cluster_bin",
+    out = "launch",
+    tags = ["manual"],
+    visibility = ["//visibility:public"],
+)
diff --git a/metropolis/test/launch/cli/launch-cluster/main.go b/metropolis/test/launch/cli/launch-cluster/main.go
new file mode 100644
index 0000000..e5959f3
--- /dev/null
+++ b/metropolis/test/launch/cli/launch-cluster/main.go
@@ -0,0 +1,67 @@
+// Copyright 2020 The Monogon Project Authors.
+//
+// SPDX-License-Identifier: Apache-2.0
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+	"context"
+	"log"
+
+	metroctl "source.monogon.dev/metropolis/cli/metroctl/core"
+	clicontext "source.monogon.dev/metropolis/cli/pkg/context"
+	"source.monogon.dev/metropolis/test/launch/cluster"
+)
+
+func main() {
+	ctx := clicontext.WithInterrupt(context.Background())
+	cl, err := cluster.LaunchCluster(ctx, cluster.ClusterOptions{
+		NumNodes:        3,
+		NodeLogsToFiles: true,
+	})
+	if err != nil {
+		log.Fatalf("LaunchCluster: %v", err)
+	}
+
+	mpath, err := cluster.MetroctlRunfilePath()
+	if err != nil {
+		log.Fatalf("MetroctlRunfilePath: %v", err)
+	}
+	wpath, err := cl.MakeMetroctlWrapper()
+	if err != nil {
+		log.Fatalf("MakeWrapper: %v", err)
+	}
+
+	apiservers, err := cl.KubernetesControllerNodeAddresses(ctx)
+	if err != nil {
+		log.Fatalf("Could not get Kubernetes controller nodes: %v", err)
+	}
+	if len(apiservers) < 1 {
+		log.Fatalf("Cluster has no Kubernetes controller nodes")
+	}
+
+	configName := "launch-cluster"
+	if err := metroctl.InstallKubeletConfig(ctx, mpath, cl.ConnectOptions(), configName, apiservers[0]); err != nil {
+		log.Fatalf("InstallKubeletConfig: %v", err)
+	}
+
+	log.Printf("Launch: Cluster running!")
+	log.Printf("  To access cluster use: metroctl %s", cl.MetroctlFlags())
+	log.Printf("  Or use this handy wrapper: %s", wpath)
+	log.Printf("  To access Kubernetes, use kubectl --context=%s", configName)
+
+	<-ctx.Done()
+	cl.Close()
+}