Lorenz Brun | a9b455f | 2021-12-07 03:53:22 +0100 | [diff] [blame] | 1 | package main |
| 2 | |
| 3 | import ( |
| 4 | "context" |
Lorenz Brun | a9b455f | 2021-12-07 03:53:22 +0100 | [diff] [blame] | 5 | "log" |
Lorenz Brun | a9b455f | 2021-12-07 03:53:22 +0100 | [diff] [blame] | 6 | "os" |
Lorenz Brun | 20d1dd1 | 2022-07-01 12:21:42 +0000 | [diff] [blame] | 7 | "os/exec" |
Lorenz Brun | a9b455f | 2021-12-07 03:53:22 +0100 | [diff] [blame] | 8 | |
Lorenz Brun | a9b455f | 2021-12-07 03:53:22 +0100 | [diff] [blame] | 9 | "github.com/spf13/cobra" |
| 10 | |
Mateusz Zalega | 18a67b0 | 2022-08-02 13:37:50 +0200 | [diff] [blame] | 11 | "source.monogon.dev/metropolis/cli/metroctl/core" |
Lorenz Brun | a9b455f | 2021-12-07 03:53:22 +0100 | [diff] [blame] | 12 | clicontext "source.monogon.dev/metropolis/cli/pkg/context" |
Lorenz Brun | a9b455f | 2021-12-07 03:53:22 +0100 | [diff] [blame] | 13 | "source.monogon.dev/metropolis/node/core/rpc" |
Serge Bazanski | dc1bec4 | 2021-12-16 17:38:53 +0100 | [diff] [blame] | 14 | apb "source.monogon.dev/metropolis/proto/api" |
Lorenz Brun | a9b455f | 2021-12-07 03:53:22 +0100 | [diff] [blame] | 15 | ) |
| 16 | |
| 17 | var takeownershipCommand = &cobra.Command{ |
Mateusz Zalega | b1e7ee4 | 2022-07-08 12:19:02 +0200 | [diff] [blame] | 18 | Use: "takeownership", |
Lorenz Brun | a9b455f | 2021-12-07 03:53:22 +0100 | [diff] [blame] | 19 | Short: "Takes ownership of a new Metropolis cluster", |
| 20 | Long: `This takes ownership of a new Metropolis cluster by asking the new |
| 21 | cluster to issue an owner certificate to for the owner key generated by a |
Mateusz Zalega | b1e7ee4 | 2022-07-08 12:19:02 +0200 | [diff] [blame] | 22 | previous invocation of metroctl install on this machine. A single cluster |
| 23 | endpoint must be provided with the --endpoints parameter.`, |
| 24 | Args: cobra.ExactArgs(0), |
| 25 | Run: doTakeOwnership, |
Lorenz Brun | a9b455f | 2021-12-07 03:53:22 +0100 | [diff] [blame] | 26 | } |
| 27 | |
Mateusz Zalega | b1e7ee4 | 2022-07-08 12:19:02 +0200 | [diff] [blame] | 28 | func 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 Zalega | b1e7ee4 | 2022-07-08 12:19:02 +0200 | [diff] [blame] | 32 | |
Mateusz Zalega | 1846450 | 2022-07-14 16:18:26 +0200 | [diff] [blame] | 33 | // Retrieve the cluster owner's private key, and use it to construct |
| 34 | // ephemeral credentials. Then, dial the cluster. |
Serge Bazanski | cf23ebc | 2023-03-14 17:02:04 +0100 | [diff] [blame] | 35 | opk, err := core.GetOwnerKey(flags.configPath) |
| 36 | if err == core.NoCredentialsError { |
Lorenz Brun | a9b455f | 2021-12-07 03:53:22 +0100 | [diff] [blame] | 37 | 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 Brun | a9b455f | 2021-12-07 03:53:22 +0100 | [diff] [blame] | 38 | } |
Mateusz Zalega | 1846450 | 2022-07-14 16:18:26 +0200 | [diff] [blame] | 39 | if err != nil { |
| 40 | log.Fatalf("Couldn't get owner's key: %v", err) |
Lorenz Brun | a9b455f | 2021-12-07 03:53:22 +0100 | [diff] [blame] | 41 | } |
Mateusz Zalega | 1846450 | 2022-07-14 16:18:26 +0200 | [diff] [blame] | 42 | ctx := clicontext.WithInterrupt(context.Background()) |
Mateusz Zalega | 18a67b0 | 2022-08-02 13:37:50 +0200 | [diff] [blame] | 43 | cc, err := core.DialCluster(ctx, opk, nil, flags.proxyAddr, flags.clusterEndpoints, rpcLogger) |
Mateusz Zalega | 1846450 | 2022-07-14 16:18:26 +0200 | [diff] [blame] | 44 | if err != nil { |
| 45 | log.Fatalf("While dialing the cluster: %v", err) |
Lorenz Brun | a9b455f | 2021-12-07 03:53:22 +0100 | [diff] [blame] | 46 | } |
Mateusz Zalega | 1846450 | 2022-07-14 16:18:26 +0200 | [diff] [blame] | 47 | aaa := apb.NewAAAClient(cc) |
Lorenz Brun | a9b455f | 2021-12-07 03:53:22 +0100 | [diff] [blame] | 48 | |
Mateusz Zalega | 1846450 | 2022-07-14 16:18:26 +0200 | [diff] [blame] | 49 | ownerCert, err := rpc.RetrieveOwnerCertificate(ctx, aaa, opk) |
Lorenz Brun | a9b455f | 2021-12-07 03:53:22 +0100 | [diff] [blame] | 50 | if err != nil { |
| 51 | log.Fatalf("Failed to retrive owner certificate from cluster: %v", err) |
| 52 | } |
Serge Bazanski | cf23ebc | 2023-03-14 17:02:04 +0100 | [diff] [blame] | 53 | if err := core.WriteOwnerCertificate(flags.configPath, ownerCert.Certificate[0]); err != nil { |
Lorenz Brun | a9b455f | 2021-12-07 03:53:22 +0100 | [diff] [blame] | 54 | 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 Brun | 20d1dd1 | 2022-07-01 12:21:42 +0000 | [diff] [blame] | 57 | log.Print("Successfully retrieved owner credentials! You now own this cluster. Setting up kubeconfig now...") |
| 58 | |
Lorenz Brun | 20d1dd1 | 2022-07-01 12:21:42 +0000 | [diff] [blame] | 59 | // 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 Bazanski | 1f8cad7 | 2023-03-20 16:58:10 +0100 | [diff] [blame] | 69 | // 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 Windelschmidt | b37d7d8 | 2023-06-14 19:06:44 +0200 | [diff] [blame] | 71 | configName := "metroctl" |
| 72 | if err := core.InstallKubeletConfig(metroctlPath, connectOptions(), configName, flags.clusterEndpoints[0]); err != nil { |
Serge Bazanski | cf23ebc | 2023-03-14 17:02:04 +0100 | [diff] [blame] | 73 | log.Fatalf("Failed to install metroctl/k8s integration: %v", err) |
Lorenz Brun | 20d1dd1 | 2022-07-01 12:21:42 +0000 | [diff] [blame] | 74 | } |
Tim Windelschmidt | b37d7d8 | 2023-06-14 19:06:44 +0200 | [diff] [blame] | 75 | log.Printf("Success! kubeconfig is set up. You can now run kubectl --context=%s ... to access the Kubernetes cluster.", configName) |
Lorenz Brun | a9b455f | 2021-12-07 03:53:22 +0100 | [diff] [blame] | 76 | } |
| 77 | |
| 78 | func init() { |
| 79 | rootCmd.AddCommand(takeownershipCommand) |
| 80 | } |