diff --git a/cmd/beta.go b/cmd/beta.go index 65405b63c..c6e29950a 100644 --- a/cmd/beta.go +++ b/cmd/beta.go @@ -11,6 +11,7 @@ import ( "github.com/kubefirst/kubefirst/cmd/digitalocean" "github.com/kubefirst/kubefirst/cmd/google" + "github.com/kubefirst/kubefirst/cmd/k3s" "github.com/kubefirst/kubefirst/cmd/vultr" "github.com/spf13/cobra" ) @@ -30,6 +31,7 @@ func init() { cobra.OnInitialize() betaCmd.AddCommand( digitalocean.NewCommand(), + k3s.NewCommand(), google.NewCommand(), vultr.NewCommand(), ) diff --git a/cmd/k3s/command.go b/cmd/k3s/command.go new file mode 100644 index 000000000..9dcfadc33 --- /dev/null +++ b/cmd/k3s/command.go @@ -0,0 +1,115 @@ +/* +Copyright (C) 2021-2023, Kubefirst + +This program is licensed under MIT. +See the LICENSE file for more details. +*/ +package k3s + +import ( + "fmt" + + "github.com/kubefirst/kubefirst/internal/common" + "github.com/spf13/cobra" +) + +var ( + // Create + alertsEmailFlag string + ciFlag bool + clusterNameFlag string + clusterTypeFlag string + dnsProviderFlag string + domainNameFlag string + githubOrgFlag string + gitlabGroupFlag string + gitProviderFlag string + gitProtocolFlag string + gitopsTemplateURLFlag string + gitopsTemplateBranchFlag string + useTelemetryFlag bool + forceDestroyFlag bool + + // RootCredentials + copyArgoCDPasswordToClipboardFlag bool + copyKbotPasswordToClipboardFlag bool + copyVaultPasswordToClipboardFlag bool + + // Supported providers + supportedDNSProviders = []string{"cloudflare"} + supportedGitProviders = []string{"github", "gitlab"} + + // Supported git providers + supportedGitProtocolOverride = []string{"https", "ssh"} +) + +func NewCommand() *cobra.Command { + k3sCmd := &cobra.Command{ + Use: "k3s", + Short: "kubefirst K3s installation", + Long: "kubefirst k3s on premises installation", + } + + // on error, doesnt show helper/usage + k3sCmd.SilenceUsage = true + + // wire up new commands + k3sCmd.AddCommand(Create(), Destroy(), RootCredentials()) + + return k3sCmd +} + +func Create() *cobra.Command { + createCmd := &cobra.Command{ + Use: "create", + Short: "create the kubefirst platform running on GCP kubernetes", + TraverseChildren: true, + RunE: createK3s, + // PreRun: common.CheckDocker, + } + + // todo review defaults and update descriptions + createCmd.Flags().StringVar(&alertsEmailFlag, "alerts-email", "", "email address for let's encrypt certificate notifications (required)") + createCmd.MarkFlagRequired("alerts-email") + createCmd.Flags().BoolVar(&ciFlag, "ci", false, "if running kubefirst in ci, set this flag to disable interactive features") + createCmd.Flags().StringVar(&clusterNameFlag, "cluster-name", "kubefirst", "the name of the cluster to create") + createCmd.Flags().StringVar(&clusterTypeFlag, "cluster-type", "mgmt", "the type of cluster to create (i.e. mgmt|workload)") + createCmd.Flags().StringVar(&dnsProviderFlag, "dns-provider", "cloudflare", fmt.Sprintf("the dns provider - one of: %s", supportedDNSProviders)) + createCmd.MarkFlagRequired("domain-name") + createCmd.Flags().StringVar(&gitProviderFlag, "git-provider", "github", fmt.Sprintf("the git provider - one of: %s", supportedGitProviders)) + createCmd.Flags().StringVar(&gitProtocolFlag, "git-protocol", "ssh", fmt.Sprintf("the git protocol - one of: %s", supportedGitProtocolOverride)) + createCmd.Flags().StringVar(&githubOrgFlag, "github-org", "", "the GitHub organization for the new gitops and metaphor repositories - required if using github") + createCmd.Flags().StringVar(&gitlabGroupFlag, "gitlab-group", "", "the GitLab group for the new gitops and metaphor projects - required if using gitlab") + createCmd.Flags().StringVar(&gitopsTemplateBranchFlag, "gitops-template-branch", "", "the branch to clone for the gitops-template repository") + createCmd.Flags().StringVar(&gitopsTemplateURLFlag, "gitops-template-url", "https://github.com/kubefirst/gitops-template.git", "the fully qualified url to the gitops-template repository to clone") + createCmd.Flags().BoolVar(&useTelemetryFlag, "use-telemetry", true, "whether to emit telemetry") + createCmd.Flags().BoolVar(&forceDestroyFlag, "force-destroy", false, "allows force destruction on objects (helpful for test environments, defaults to false)") + return createCmd +} + +func Destroy() *cobra.Command { + destroyCmd := &cobra.Command{ + Use: "destroy", + Short: "destroy the kubefirst platform", + Long: "destroy the kubefirst platform running in k3s cluster", + RunE: common.Destroy, + // PreRun: common.CheckDocker, + } + + return destroyCmd +} + +func RootCredentials() *cobra.Command { + authCmd := &cobra.Command{ + Use: "root-credentials", + Short: "retrieve root authentication information for platform components", + Long: "retrieve root authentication information for platform components", + RunE: common.GetRootCredentials, + } + + authCmd.Flags().BoolVar(©ArgoCDPasswordToClipboardFlag, "argocd", false, "copy the argocd password to the clipboard (optional)") + authCmd.Flags().BoolVar(©KbotPasswordToClipboardFlag, "kbot", false, "copy the kbot password to the clipboard (optional)") + authCmd.Flags().BoolVar(©VaultPasswordToClipboardFlag, "vault", false, "copy the vault password to the clipboard (optional)") + + return authCmd +} diff --git a/cmd/k3s/create.go b/cmd/k3s/create.go new file mode 100644 index 000000000..ed0b28df5 --- /dev/null +++ b/cmd/k3s/create.go @@ -0,0 +1,117 @@ +/* +Copyright (C) 2021-2023, Kubefirst + +This program is licensed under MIT. +See the LICENSE file for more details. +*/ +package k3s + +import ( + "fmt" + + "github.com/rs/zerolog/log" + + "github.com/kubefirst/kubefirst/internal/cluster" + "github.com/kubefirst/kubefirst/internal/gitShim" + "github.com/kubefirst/kubefirst/internal/launch" + "github.com/kubefirst/kubefirst/internal/progress" + "github.com/kubefirst/kubefirst/internal/provision" + "github.com/kubefirst/kubefirst/internal/utilities" + "github.com/kubefirst/runtime/pkg" + internalssh "github.com/kubefirst/runtime/pkg/ssh" + "github.com/spf13/cobra" + "github.com/spf13/viper" + _ "k8s.io/client-go/plugin/pkg/client/auth" +) + +func createK3s(cmd *cobra.Command, args []string) error { + cliFlags, err := utilities.GetFlags(cmd, "k3s") + if err != nil { + progress.Error(err.Error()) + return nil + } + + progress.DisplayLogHints(20) + + err = ValidateProvidedFlags(cliFlags.GitProvider) + if err != nil { + progress.Error(err.Error()) + return nil + } + + // If cluster setup is complete, return + clusterSetupComplete := viper.GetBool("kubefirst-checks.cluster-install-complete") + if clusterSetupComplete { + err = fmt.Errorf("this cluster install process has already completed successfully") + progress.Error(err.Error()) + return nil + } + + utilities.CreateK1ClusterDirectory(clusterNameFlag) + + gitAuth, err := gitShim.ValidateGitCredentials(cliFlags.GitProvider, cliFlags.GithubOrg, cliFlags.GitlabGroup) + if err != nil { + progress.Error(err.Error()) + return nil + } + + executionControl := viper.GetBool(fmt.Sprintf("kubefirst-checks.%s-credentials", cliFlags.GitProvider)) + if !executionControl { + newRepositoryNames := []string{"gitops", "metaphor"} + newTeamNames := []string{"admins", "developers"} + + initGitParameters := gitShim.GitInitParameters{ + GitProvider: gitProviderFlag, + GitToken: gitAuth.Token, + GitOwner: gitAuth.Owner, + Repositories: newRepositoryNames, + Teams: newTeamNames, + } + err = gitShim.InitializeGitProvider(&initGitParameters) + if err != nil { + progress.Error(err.Error()) + return nil + } + } + viper.Set(fmt.Sprintf("kubefirst-checks.%s-credentials", cliFlags.GitProvider), true) + viper.WriteConfig() + + k3dClusterCreationComplete := viper.GetBool("launch.deployed") + if !k3dClusterCreationComplete { + launch.Up(nil, true, cliFlags.UseTelemetry) + } + + err = pkg.IsAppAvailable(fmt.Sprintf("%s/api/proxyHealth", cluster.GetConsoleIngresUrl()), "kubefirst api") + if err != nil { + progress.Error("unable to start kubefirst api") + } + + provision.CreateMgmtCluster(gitAuth, cliFlags) + + return nil +} + +func ValidateProvidedFlags(gitProvider string) error { + progress.AddStep("Validate provided flags") + + switch gitProvider { + case "github": + key, err := internalssh.GetHostKey("github.com") + if err != nil { + return fmt.Errorf("known_hosts file does not exist - please run `ssh-keyscan github.com >> ~/.ssh/known_hosts` to remedy") + } else { + log.Info().Msgf("%s %s\n", "github.com", key.Type()) + } + case "gitlab": + key, err := internalssh.GetHostKey("gitlab.com") + if err != nil { + return fmt.Errorf("known_hosts file does not exist - please run `ssh-keyscan gitlab.com >> ~/.ssh/known_hosts` to remedy") + } else { + log.Info().Msgf("%s %s\n", "gitlab.com", key.Type()) + } + } + + progress.CompleteStep("Validate provided flags") + + return nil +}