blob: 740dfb1f6d33d1bbda23bcf382edde4f3998c1e4 [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"
Lorenz Bruna9b455f2021-12-07 03:53:22 +01006 "os"
Lorenz Brun20d1dd12022-07-01 12:21:42 +00007 "os/exec"
Lorenz Bruna9b455f2021-12-07 03:53:22 +01008
Lorenz Bruna9b455f2021-12-07 03:53:22 +01009 "github.com/spf13/cobra"
10
Mateusz Zalega18a67b02022-08-02 13:37:50 +020011 "source.monogon.dev/metropolis/cli/metroctl/core"
Lorenz Bruna9b455f2021-12-07 03:53:22 +010012 clicontext "source.monogon.dev/metropolis/cli/pkg/context"
Lorenz Bruna9b455f2021-12-07 03:53:22 +010013 "source.monogon.dev/metropolis/node/core/rpc"
Serge Bazanskidc1bec42021-12-16 17:38:53 +010014 apb "source.monogon.dev/metropolis/proto/api"
Lorenz Bruna9b455f2021-12-07 03:53:22 +010015)
16
17var takeownershipCommand = &cobra.Command{
Mateusz Zalegab1e7ee42022-07-08 12:19:02 +020018 Use: "takeownership",
Lorenz Bruna9b455f2021-12-07 03:53:22 +010019 Short: "Takes ownership of a new Metropolis cluster",
20 Long: `This takes ownership of a new Metropolis cluster by asking the new
21cluster to issue an owner certificate to for the owner key generated by a
Mateusz Zalegab1e7ee42022-07-08 12:19:02 +020022previous invocation of metroctl install on this machine. A single cluster
23endpoint must be provided with the --endpoints parameter.`,
24 Args: cobra.ExactArgs(0),
25 Run: doTakeOwnership,
Lorenz Bruna9b455f2021-12-07 03:53:22 +010026}
27
Mateusz Zalegab1e7ee42022-07-08 12:19:02 +020028func doTakeOwnership(cmd *cobra.Command, _ []string) {
29 if len(flags.clusterEndpoints) != 1 {
30 log.Fatalf("takeownership requires a single cluster endpoint to be provided with the --endpoints parameter.")
31 }
Mateusz Zalegab1e7ee42022-07-08 12:19:02 +020032
Mateusz Zalega18464502022-07-14 16:18:26 +020033 // Retrieve the cluster owner's private key, and use it to construct
34 // ephemeral credentials. Then, dial the cluster.
Serge Bazanskicf23ebc2023-03-14 17:02:04 +010035 opk, err := core.GetOwnerKey(flags.configPath)
36 if err == core.NoCredentialsError {
Lorenz Bruna9b455f2021-12-07 03:53:22 +010037 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 +010038 }
Mateusz Zalega18464502022-07-14 16:18:26 +020039 if err != nil {
40 log.Fatalf("Couldn't get owner's key: %v", err)
Lorenz Bruna9b455f2021-12-07 03:53:22 +010041 }
Mateusz Zalega18464502022-07-14 16:18:26 +020042 ctx := clicontext.WithInterrupt(context.Background())
Mateusz Zalega18a67b02022-08-02 13:37:50 +020043 cc, err := core.DialCluster(ctx, opk, nil, flags.proxyAddr, flags.clusterEndpoints, rpcLogger)
Mateusz Zalega18464502022-07-14 16:18:26 +020044 if err != nil {
45 log.Fatalf("While dialing the cluster: %v", err)
Lorenz Bruna9b455f2021-12-07 03:53:22 +010046 }
Mateusz Zalega18464502022-07-14 16:18:26 +020047 aaa := apb.NewAAAClient(cc)
Lorenz Bruna9b455f2021-12-07 03:53:22 +010048
Mateusz Zalega18464502022-07-14 16:18:26 +020049 ownerCert, err := rpc.RetrieveOwnerCertificate(ctx, aaa, opk)
Lorenz Bruna9b455f2021-12-07 03:53:22 +010050 if err != nil {
51 log.Fatalf("Failed to retrive owner certificate from cluster: %v", err)
52 }
Serge Bazanskicf23ebc2023-03-14 17:02:04 +010053 if err := core.WriteOwnerCertificate(flags.configPath, ownerCert.Certificate[0]); err != nil {
Lorenz Bruna9b455f2021-12-07 03:53:22 +010054 log.Printf("Failed to store retrieved owner certificate: %v", err)
55 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.")
56 }
Lorenz Brun20d1dd12022-07-01 12:21:42 +000057 log.Print("Successfully retrieved owner credentials! You now own this cluster. Setting up kubeconfig now...")
58
Lorenz Brun20d1dd12022-07-01 12:21:42 +000059 // If the user has metroctl in their path, use the metroctl from path as
60 // a credential plugin. Otherwise use the path to the currently-running
61 // metroctl.
62 metroctlPath := "metroctl"
63 if _, err := exec.LookPath("metroctl"); err != nil {
64 metroctlPath, err = os.Executable()
65 if err != nil {
66 log.Fatalf("Failed to create kubectl entry as metroctl is neither in PATH nor can its absolute path be determined: %v", err)
67 }
68 }
Serge Bazanski1f8cad72023-03-20 16:58:10 +010069 // TODO(q3k, issues/144): this only works as long as all nodes are kubernetes controller
70 // nodes. This won't be the case for too long. Figure this out.
Tim Windelschmidtb37d7d82023-06-14 19:06:44 +020071 configName := "metroctl"
72 if err := core.InstallKubeletConfig(metroctlPath, connectOptions(), configName, flags.clusterEndpoints[0]); err != nil {
Serge Bazanskicf23ebc2023-03-14 17:02:04 +010073 log.Fatalf("Failed to install metroctl/k8s integration: %v", err)
Lorenz Brun20d1dd12022-07-01 12:21:42 +000074 }
Tim Windelschmidtb37d7d82023-06-14 19:06:44 +020075 log.Printf("Success! kubeconfig is set up. You can now run kubectl --context=%s ... to access the Kubernetes cluster.", configName)
Lorenz Bruna9b455f2021-12-07 03:53:22 +010076}
77
78func init() {
79 rootCmd.AddCommand(takeownershipCommand)
80}