blob: 2c373407b92a9424dd9ceb48a961563b6b14fa84 [file] [log] [blame]
Lorenz Bruna9b455f2021-12-07 03:53:22 +01001package main
2
3import (
4 "context"
Lorenz Bruna9b455f2021-12-07 03:53:22 +01005 "log"
6 "net"
7 "os"
Lorenz Brun20d1dd12022-07-01 12:21:42 +00008 "os/exec"
Lorenz Bruna9b455f2021-12-07 03:53:22 +01009
Lorenz Bruna9b455f2021-12-07 03:53:22 +010010 "github.com/spf13/cobra"
11
Mateusz Zalega18a67b02022-08-02 13:37:50 +020012 "source.monogon.dev/metropolis/cli/metroctl/core"
Lorenz Bruna9b455f2021-12-07 03:53:22 +010013 clicontext "source.monogon.dev/metropolis/cli/pkg/context"
14 "source.monogon.dev/metropolis/node"
15 "source.monogon.dev/metropolis/node/core/rpc"
Serge Bazanskidc1bec42021-12-16 17:38:53 +010016 apb "source.monogon.dev/metropolis/proto/api"
Lorenz Bruna9b455f2021-12-07 03:53:22 +010017)
18
19var takeownershipCommand = &cobra.Command{
Mateusz Zalegab1e7ee42022-07-08 12:19:02 +020020 Use: "takeownership",
Lorenz Bruna9b455f2021-12-07 03:53:22 +010021 Short: "Takes ownership of a new Metropolis cluster",
22 Long: `This takes ownership of a new Metropolis cluster by asking the new
23cluster to issue an owner certificate to for the owner key generated by a
Mateusz Zalegab1e7ee42022-07-08 12:19:02 +020024previous invocation of metroctl install on this machine. A single cluster
25endpoint must be provided with the --endpoints parameter.`,
26 Args: cobra.ExactArgs(0),
27 Run: doTakeOwnership,
Lorenz Bruna9b455f2021-12-07 03:53:22 +010028}
29
Mateusz Zalegab1e7ee42022-07-08 12:19:02 +020030func doTakeOwnership(cmd *cobra.Command, _ []string) {
31 if len(flags.clusterEndpoints) != 1 {
32 log.Fatalf("takeownership requires a single cluster endpoint to be provided with the --endpoints parameter.")
33 }
Mateusz Zalegab1e7ee42022-07-08 12:19:02 +020034
Mateusz Zalega18464502022-07-14 16:18:26 +020035 // Retrieve the cluster owner's private key, and use it to construct
36 // ephemeral credentials. Then, dial the cluster.
Serge Bazanskicf23ebc2023-03-14 17:02:04 +010037 opk, err := core.GetOwnerKey(flags.configPath)
38 if err == core.NoCredentialsError {
Lorenz Bruna9b455f2021-12-07 03:53:22 +010039 log.Fatalf("Owner key does not exist. takeownership needs to be executed on the same system that has previously installed the cluster using metroctl install.")
Lorenz Bruna9b455f2021-12-07 03:53:22 +010040 }
Mateusz Zalega18464502022-07-14 16:18:26 +020041 if err != nil {
42 log.Fatalf("Couldn't get owner's key: %v", err)
Lorenz Bruna9b455f2021-12-07 03:53:22 +010043 }
Mateusz Zalega18464502022-07-14 16:18:26 +020044 ctx := clicontext.WithInterrupt(context.Background())
Mateusz Zalega18a67b02022-08-02 13:37:50 +020045 cc, err := core.DialCluster(ctx, opk, nil, flags.proxyAddr, flags.clusterEndpoints, rpcLogger)
Mateusz Zalega18464502022-07-14 16:18:26 +020046 if err != nil {
47 log.Fatalf("While dialing the cluster: %v", err)
Lorenz Bruna9b455f2021-12-07 03:53:22 +010048 }
Mateusz Zalega18464502022-07-14 16:18:26 +020049 aaa := apb.NewAAAClient(cc)
Lorenz Bruna9b455f2021-12-07 03:53:22 +010050
Mateusz Zalega18464502022-07-14 16:18:26 +020051 ownerCert, err := rpc.RetrieveOwnerCertificate(ctx, aaa, opk)
Lorenz Bruna9b455f2021-12-07 03:53:22 +010052 if err != nil {
53 log.Fatalf("Failed to retrive owner certificate from cluster: %v", err)
54 }
Serge Bazanskicf23ebc2023-03-14 17:02:04 +010055 if err := core.WriteOwnerCertificate(flags.configPath, ownerCert.Certificate[0]); err != nil {
Lorenz Bruna9b455f2021-12-07 03:53:22 +010056 log.Printf("Failed to store retrieved owner certificate: %v", err)
57 log.Fatalln("Sorry, the cluster has been lost as taking ownership cannot be repeated. Fix the reason the file couldn't be written and reinstall the node.")
58 }
Lorenz Brun20d1dd12022-07-01 12:21:42 +000059 log.Print("Successfully retrieved owner credentials! You now own this cluster. Setting up kubeconfig now...")
60
Lorenz Brun20d1dd12022-07-01 12:21:42 +000061 // If the user has metroctl in their path, use the metroctl from path as
62 // a credential plugin. Otherwise use the path to the currently-running
63 // metroctl.
64 metroctlPath := "metroctl"
65 if _, err := exec.LookPath("metroctl"); err != nil {
66 metroctlPath, err = os.Executable()
67 if err != nil {
68 log.Fatalf("Failed to create kubectl entry as metroctl is neither in PATH nor can its absolute path be determined: %v", err)
69 }
70 }
Serge Bazanski1f8cad72023-03-20 16:58:10 +010071 // TODO(q3k, issues/144): this only works as long as all nodes are kubernetes controller
72 // nodes. This won't be the case for too long. Figure this out.
73 apiserver := "https://" + net.JoinHostPort(flags.clusterEndpoints[0], node.KubernetesAPIWrappedPort.PortString())
74 if err := core.InstallKubeletConfig(metroctlPath, connectOptions(), "metroctl", apiserver); err != nil {
Serge Bazanskicf23ebc2023-03-14 17:02:04 +010075 log.Fatalf("Failed to install metroctl/k8s integration: %v", err)
Lorenz Brun20d1dd12022-07-01 12:21:42 +000076 }
77 log.Println("Success! kubeconfig is set up. You can now run kubectl --context=metropolis ... to access the Kubernetes cluster.")
Lorenz Bruna9b455f2021-12-07 03:53:22 +010078}
79
80func init() {
81 rootCmd.AddCommand(takeownershipCommand)
82}