m/c/metroctl: automatically set up kubeconfig
When running takeownership this automatically sets up the necessary
kubeconfig configuration to make sure kubectl can access the cluster.
Change-Id: I135bfda2a13ea169a41506d3615d4e8a0bb0ea21
Reviewed-on: https://review.monogon.dev/c/monogon/+/818
Tested-by: Jenkins CI
Reviewed-by: Mateusz Zalega <mateusz@monogon.tech>
diff --git a/metropolis/cli/metroctl/takeownership.go b/metropolis/cli/metroctl/takeownership.go
index 17ed121..d6d9df6 100644
--- a/metropolis/cli/metroctl/takeownership.go
+++ b/metropolis/cli/metroctl/takeownership.go
@@ -7,11 +7,15 @@
"log"
"net"
"os"
+ "os/exec"
"path/filepath"
"github.com/adrg/xdg"
"github.com/spf13/cobra"
"google.golang.org/grpc"
+ clientauthentication "k8s.io/client-go/pkg/apis/clientauthentication/v1"
+ "k8s.io/client-go/tools/clientcmd"
+ clientapi "k8s.io/client-go/tools/clientcmd/api"
clicontext "source.monogon.dev/metropolis/cli/pkg/context"
"source.monogon.dev/metropolis/node"
@@ -72,7 +76,61 @@
log.Printf("Failed to store retrieved owner certificate: %v", err)
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.")
}
- log.Print("Successfully retrieved owner credentials! You now own this cluster.")
+ log.Print("Successfully retrieved owner credentials! You now own this cluster. Setting up kubeconfig now...")
+
+ ca := clientcmd.NewDefaultPathOptions()
+ config, err := ca.GetStartingConfig()
+ if err != nil {
+ log.Fatalf("Failed to get initial kubeconfig to add Metropolis cluster: %v", err)
+ }
+ // 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)
+ }
+ }
+
+ config.AuthInfos["metropolis"] = &clientapi.AuthInfo{
+ Exec: &clientapi.ExecConfig{
+ APIVersion: clientauthentication.SchemeGroupVersion.String(),
+ Command: metroctlPath,
+ Args: []string{k8scredpluginCmd.Use},
+ InstallHint: `Authenticating to Metropolis clusters requires metroctl to be present.
+Running metroctl takeownership creates this entry and either points to metroctl as a command in
+PATH if metroctl is in PATH at that time or to the absolute path to metroctl at that time.
+If you moved metroctl afterwards or want to switch to PATH resolution, edit $HOME/.kube/config and
+change users.metropolis.exec.command to the required path (or just metroctl if using PATH resolution).`,
+ InteractiveMode: clientapi.NeverExecInteractiveMode,
+ },
+ }
+
+ config.Clusters["metropolis"] = &clientapi.Cluster{
+ // MVP: This is insecure, but making this work would be wasted effort
+ // as all of it will be replaced by the identity system.
+ InsecureSkipTLSVerify: true,
+ Server: "https://" + net.JoinHostPort(args[0], node.KubernetesAPIWrappedPort.PortString()),
+ }
+
+ config.Contexts["metropolis"] = &clientapi.Context{
+ AuthInfo: "metropolis",
+ Cluster: "metropolis",
+ Namespace: "default",
+ }
+
+ // Only set us as the current context if no other exists. Changing that
+ // unprompted would be kind of rude.
+ if config.CurrentContext == "" {
+ config.CurrentContext = "metropolis"
+ }
+
+ if err := clientcmd.ModifyConfig(ca, *config, true); err != nil {
+ log.Fatalf("Failed to modify kubeconfig to add Metropolis cluster: %v", err)
+ }
+ log.Println("Success! kubeconfig is set up. You can now run kubectl --context=metropolis ... to access the Kubernetes cluster.")
}
func init() {