Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add k3s provisionning #1875

Merged
merged 1 commit into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cmd/beta.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"fmt"

"github.com/kubefirst/kubefirst/cmd/google"
"github.com/kubefirst/kubefirst/cmd/k3s"
"github.com/kubefirst/kubefirst/cmd/vultr"
"github.com/kubefirst/kubefirst/internal/progress"
"github.com/spf13/cobra"
Expand All @@ -33,6 +34,7 @@ var betaCmd = &cobra.Command{
func init() {
cobra.OnInitialize()
betaCmd.AddCommand(
k3s.NewCommand(),
google.NewCommand(),
vultr.NewCommand(),
)
Expand Down
134 changes: 134 additions & 0 deletions cmd/k3s/command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*
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
// TODO: add ssh key flag to connect on k3s targets
alertsEmailFlag string
ciFlag bool
cloudRegionFlag string
nodeTypeFlag string
nodeCountFlag string
clusterNameFlag string
clusterTypeFlag string
k3sServersPrivateIpsFlag []string
k3sServersPublicIpsFlag []string
k3sSshUserflag string
k3sSshPrivateKeyflag string
K3sServersArgsFlags []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 premise",
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(&cloudRegionFlag, "cloud-region", "on-premise", "NOT USED, PRESENT FOR COMPATIBILITY ISSUE")
createCmd.Flags().StringVar(&nodeTypeFlag, "node-type", "on-premise", "NOT USED, PRESENT FOR COMPATIBILITY ISSUE")
createCmd.Flags().StringVar(&nodeCountFlag, "node-count", "3", "NOT USED, PRESENT FOR COMPATIBILITY ISSUE")
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().StringSliceVar(&k3sServersPrivateIpsFlag, "servers-private-ips", []string{}, "the list of k3s (servers) private ip x.x.x.x,y.y.y.y comma separated (required)")
createCmd.MarkFlagRequired("servers-private-ips")
createCmd.Flags().StringSliceVar(&k3sServersPublicIpsFlag, "servers-public-ips", []string{}, "the list of k3s (servers) public ip x.x.x.x,y.y.y.y comma separated (required)")
createCmd.Flags().StringSliceVar(&K3sServersArgsFlags, "servers-args", []string{"--disable traefik", "--write-kubeconfig-mode 644"}, "list of k3s extras args to add to the k3s server installation,comma separated in between quote, if --servers-publis-ips <VALUES> --tls-san <VALUES> is added to default --servers-args")
createCmd.Flags().StringVar(&k3sSshUserflag, "ssh-user", "root", "the user used to log into servers with ssh connection")
createCmd.Flags().StringVar(&k3sSshPrivateKeyflag, "ssh-privatekey", "", "the private key used to log into servers with ssh connection")
createCmd.MarkFlagRequired("ssh-privatekey")
createCmd.Flags().StringVar(&dnsProviderFlag, "dns-provider", "cloudflare", fmt.Sprintf("the dns provider - one of: %s", supportedDNSProviders))
createCmd.Flags().StringVar(&domainNameFlag, "domain-name", "", "the cloudProvider DNS Name to use for DNS records (i.e. your-domain.com|subdomain.your-domain.com) (required)")
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(&copyArgoCDPasswordToClipboardFlag, "argocd", false, "copy the argocd password to the clipboard (optional)")
authCmd.Flags().BoolVar(&copyKbotPasswordToClipboardFlag, "kbot", false, "copy the kbot password to the clipboard (optional)")
authCmd.Flags().BoolVar(&copyVaultPasswordToClipboardFlag, "vault", false, "copy the vault password to the clipboard (optional)")

return authCmd
}
117 changes: 117 additions & 0 deletions cmd/k3s/create.go
Original file line number Diff line number Diff line change
@@ -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
}
3 changes: 3 additions & 0 deletions internal/progress/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ func DisplaySuccessMessage(cluster types.Cluster) successMsg {

case "vultr":
cloudCliKubeconfig = fmt.Sprintf("vultr-cli kubernetes config %s", cluster.ClusterName)

case "k3s":
cloudCliKubeconfig = fmt.Sprint(("use the kubeconfig file outputed from terraform to acces to the cluster"))
break

}
Expand Down
5 changes: 5 additions & 0 deletions internal/types/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,9 @@ type CliFlags struct {
NodeType string
NodeCount string
InstallCatalogApps string
K3sSshUser string
K3sSshPrivateKey string
K3sServersPrivateIps []string
K3sServersPublicIps []string
K3sServersArgs []string
}
45 changes: 45 additions & 0 deletions internal/utilities/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,44 @@ func GetFlags(cmd *cobra.Command, cloudProvider string) (types.CliFlags, error)
cliFlags.GoogleProject = googleProject
}

// TODO: reafactor this part
if cloudProvider == "k3s" {
k3sServersPrivateIps, err := cmd.Flags().GetStringSlice("servers-private-ips")
if err != nil {
progress.Error(err.Error())
return cliFlags, err
}
cliFlags.K3sServersPrivateIps = k3sServersPrivateIps

k3sServersPublicIps, err := cmd.Flags().GetStringSlice("servers-public-ips")
if err != nil {
progress.Error(err.Error())
return cliFlags, err
}
cliFlags.K3sServersPublicIps = k3sServersPublicIps

k3sSshUserFlag, err := cmd.Flags().GetString("ssh-user")
if err != nil {
progress.Error(err.Error())
return cliFlags, err
}
cliFlags.K3sSshUser = k3sSshUserFlag

k3sSshPrivateKeyFlag, err := cmd.Flags().GetString("ssh-privatekey")
if err != nil {
progress.Error(err.Error())
return cliFlags, err
}
cliFlags.K3sSshPrivateKey = k3sSshPrivateKeyFlag

K3sServersArgsFlags, err := cmd.Flags().GetStringSlice("servers-args")
if err != nil {
progress.Error(err.Error())
return cliFlags, err
}
cliFlags.K3sServersArgs = K3sServersArgsFlags
}

cliFlags.AlertsEmail = alertsEmailFlag
cliFlags.CloudRegion = cloudRegionFlag
cliFlags.ClusterName = clusterNameFlag
Expand All @@ -162,6 +200,13 @@ func GetFlags(cmd *cobra.Command, cloudProvider string) (types.CliFlags, error)
viper.Set("flags.git-protocol", cliFlags.GitProtocol)
viper.Set("flags.cloud-region", cliFlags.CloudRegion)
viper.Set("kubefirst.cloud-provider", cloudProvider)
if cloudProvider == "k3s" {
viper.Set("flags.servers-private-ips", cliFlags.K3sServersPrivateIps)
viper.Set("flags.servers-public-ips", cliFlags.K3sServersPublicIps)
viper.Set("flags.ssh-user", cliFlags.K3sSshUser)
viper.Set("flags.ssh-privatekey", cliFlags.K3sSshPrivateKey)
viper.Set("flags.servers-args", cliFlags.K3sServersArgs)
}
viper.WriteConfig()

return cliFlags, nil
Expand Down
10 changes: 8 additions & 2 deletions internal/utilities/utilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ func CreateClusterRecordFromRaw(
case "civo":
cl.CivoAuth.Token = os.Getenv("CIVO_TOKEN")
case "aws":
//ToDo: where to get credentials?
// ToDo: where to get credentials?
cl.AWSAuth.AccessKeyID = viper.GetString("kubefirst.state-store-creds.access-key-id")
cl.AWSAuth.SecretAccessKey = viper.GetString("kubefirst.state-store-creds.secret-access-key-id")
cl.AWSAuth.SessionToken = viper.GetString("kubefirst.state-store-creds.token")
Expand Down Expand Up @@ -192,7 +192,7 @@ func CreateClusterDefinitionRecordFromRaw(gitAuth apiTypes.GitAuth, cliFlags typ
case "civo":
cl.CivoAuth.Token = os.Getenv("CIVO_TOKEN")
case "aws":
//ToDo: where to get credentials?
// ToDo: where to get credentials?
cl.AWSAuth.AccessKeyID = viper.GetString("kubefirst.state-store-creds.access-key-id")
cl.AWSAuth.SecretAccessKey = viper.GetString("kubefirst.state-store-creds.secret-access-key-id")
cl.AWSAuth.SessionToken = viper.GetString("kubefirst.state-store-creds.token")
Expand All @@ -203,6 +203,12 @@ func CreateClusterDefinitionRecordFromRaw(gitAuth apiTypes.GitAuth, cliFlags typ
cl.DigitaloceanAuth.SpacesSecret = os.Getenv("DO_SPACES_SECRET")
case "vultr":
cl.VultrAuth.Token = os.Getenv("VULTR_API_KEY")
case "k3s":
cl.K3sAuth.K3sServersPrivateIps = viper.GetStringSlice("flags.servers-private-ips")
cl.K3sAuth.K3sServersPublicIps = viper.GetStringSlice("flags.servers-public-ips")
cl.K3sAuth.K3sSshUser = viper.GetString("flags.ssh-user")
cl.K3sAuth.K3sSshPrivateKey = viper.GetString("flags.ssh-privatekey")
cl.K3sAuth.K3sServersArgs = viper.GetStringSlice("flags.servers-args")
case "google":
jsonFilePath := os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")

Expand Down
Loading