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

[WIP] chore: restructure CLI init and begin logging refactor #2350

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
89 changes: 57 additions & 32 deletions cmd/aws/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,26 @@

import (
"fmt"
"io"

"github.com/konstructio/kubefirst-api/pkg/constants"
"github.com/konstructio/kubefirst/internal/common"
"github.com/konstructio/kubefirst/internal/progress"
"github.com/spf13/cobra"
)

var (
// Create
alertsEmailFlag string

Check failure on line 20 in cmd/aws/command.go

View workflow job for this annotation

GitHub Actions / build

var `alertsEmailFlag` is unused (unused)
ciFlag bool
cloudRegionFlag string
clusterNameFlag string

Check failure on line 23 in cmd/aws/command.go

View workflow job for this annotation

GitHub Actions / build

var `clusterNameFlag` is unused (unused)
clusterTypeFlag string

Check failure on line 24 in cmd/aws/command.go

View workflow job for this annotation

GitHub Actions / build

var `clusterTypeFlag` is unused (unused)
dnsProviderFlag string
githubOrgFlag string

Check failure on line 26 in cmd/aws/command.go

View workflow job for this annotation

GitHub Actions / build

var `githubOrgFlag` is unused (unused)
gitlabGroupFlag string

Check failure on line 27 in cmd/aws/command.go

View workflow job for this annotation

GitHub Actions / build

var `gitlabGroupFlag` is unused (unused)
gitProviderFlag string

Check failure on line 28 in cmd/aws/command.go

View workflow job for this annotation

GitHub Actions / build

var `gitProviderFlag` is unused (unused)
gitProtocolFlag string

Check failure on line 29 in cmd/aws/command.go

View workflow job for this annotation

GitHub Actions / build

var `gitProtocolFlag` is unused (unused)
gitopsTemplateURLFlag string

Check failure on line 30 in cmd/aws/command.go

View workflow job for this annotation

GitHub Actions / build

var `gitopsTemplateURLFlag` is unused (unused)
gitopsTemplateBranchFlag string
domainNameFlag string
subdomainNameFlag string
Expand All @@ -44,61 +44,86 @@
supportedGitProtocolOverride = []string{"https", "ssh"}
)

func NewCommand() *cobra.Command {
awsCmd := &cobra.Command{
type options struct {
AlertsEmail string
CI bool
CloudRegion string
ClusterName string
ClusterType string
DNSProvider string
GitHubOrg string
GitLabGroup string
GitProvider string
GitProtocol string
GitopsTemplateURL string
GitopsTemplateBranch string
DomainName string
SubdomainName string
UseTelemetry bool
ECR bool
NodeType string
NodeCount string
InstallCatalogApps string
InstallKubefirstPro bool
}

func NewCommand(logger common.Logger, writer io.Writer) *cobra.Command {
cmd := &cobra.Command{
Use: "aws",
Short: "kubefirst aws installation",
Long: "kubefirst aws",
Run: func(_ *cobra.Command, _ []string) {
fmt.Println("To learn more about aws in kubefirst, run:")
fmt.Println(" kubefirst help")

if progress.Progress != nil {
progress.Progress.Quit()
}
fmt.Println(" kubefirst aws help")
},
}

service := Service{
logger,
writer,
}

// wire up new commands
awsCmd.AddCommand(Create(), Destroy(), Quota(), RootCredentials())
cmd.AddCommand(Create(service), Destroy(), Quota(), RootCredentials())

return awsCmd
return cmd
}

func Create() *cobra.Command {
func Create(service Service) *cobra.Command {
var opts options

createCmd := &cobra.Command{
Use: "create",
Short: "create the kubefirst platform running in aws",
TraverseChildren: true,
RunE: createAws,
// PreRun: common.CheckDocker,
RunE: service.createAws,
}

awsDefaults := constants.GetCloudDefaults().Aws

// todo review defaults and update descriptions
createCmd.Flags().StringVar(&alertsEmailFlag, "alerts-email", "", "email address for let's encrypt certificate notifications (required)")
createCmd.Flags().StringVar(&opts.AlertsEmail, "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", "us-east-1", "the aws region to provision infrastructure in")
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(&nodeCountFlag, "node-count", awsDefaults.NodeCount, "the node count for the cluster")
createCmd.Flags().StringVar(&nodeTypeFlag, "node-type", awsDefaults.InstanceSize, "the instance size of the cluster to create")
createCmd.Flags().StringVar(&dnsProviderFlag, "dns-provider", "aws", fmt.Sprintf("the dns provider - one of: %q", supportedDNSProviders))
createCmd.Flags().StringVar(&subdomainNameFlag, "subdomain", "", "the subdomain to use for DNS records (Cloudflare)")
createCmd.Flags().StringVar(&domainNameFlag, "domain-name", "", "the Route53/Cloudflare hosted zone name to use for DNS records (i.e. your-domain.com|subdomain.your-domain.com) (required)")
createCmd.Flags().StringVar(&opts.CloudRegion, "cloud-region", "us-east-1", "the aws region to provision infrastructure in")
createCmd.Flags().StringVar(&opts.ClusterName, "cluster-name", "kubefirst", "the name of the cluster to create")
createCmd.Flags().StringVar(&opts.ClusterType, "cluster-type", "mgmt", "the type of cluster to create (i.e. mgmt|workload)")
createCmd.Flags().StringVar(&opts.NodeCount, "node-count", awsDefaults.NodeCount, "the node count for the cluster")
createCmd.Flags().StringVar(&opts.NodeType, "node-type", awsDefaults.InstanceSize, "the instance size of the cluster to create")
createCmd.Flags().StringVar(&opts.DNSProvider, "dns-provider", "aws", fmt.Sprintf("the dns provider - one of: %q", supportedDNSProviders))
createCmd.Flags().StringVar(&opts.SubdomainName, "subdomain", "", "the subdomain to use for DNS records (Cloudflare)")
createCmd.Flags().StringVar(&opts.DomainName, "domain-name", "", "the Route53/Cloudflare hosted zone name to use for DNS records (i.e. your-domain.com|subdomain.your-domain.com) (required)")
createCmd.MarkFlagRequired("domain-name")
createCmd.Flags().StringVar(&gitProviderFlag, "git-provider", "github", fmt.Sprintf("the git provider - one of: %q", supportedGitProviders))
createCmd.Flags().StringVar(&gitProtocolFlag, "git-protocol", "ssh", fmt.Sprintf("the git protocol - one of: %q", 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/konstructio/gitops-template.git", "the fully qualified url to the gitops-template repository to clone")
createCmd.Flags().StringVar(&installCatalogApps, "install-catalog-apps", "", "comma separated values to install after provision")
createCmd.Flags().BoolVar(&useTelemetryFlag, "use-telemetry", true, "whether to emit telemetry")
createCmd.Flags().BoolVar(&ecrFlag, "ecr", false, "whether or not to use ecr vs the git provider")
createCmd.Flags().BoolVar(&installKubefirstProFlag, "install-kubefirst-pro", true, "whether or not to install kubefirst pro")
createCmd.Flags().StringVar(&opts.GitProvider, "git-provider", "github", fmt.Sprintf("the git provider - one of: %q", supportedGitProviders))
createCmd.Flags().StringVar(&opts.GitProtocol, "git-protocol", "ssh", fmt.Sprintf("the git protocol - one of: %q", supportedGitProtocolOverride))
createCmd.Flags().StringVar(&opts.GitHubOrg, "github-org", "", "the GitHub organization for the new gitops and metaphor repositories - required if using github")
createCmd.Flags().StringVar(&opts.GitLabGroup, "gitlab-group", "", "the GitLab group for the new gitops and metaphor projects - required if using gitlab")
createCmd.Flags().StringVar(&opts.GitopsTemplateBranch, "gitops-template-branch", "", "the branch to clone for the gitops-template repository")
createCmd.Flags().StringVar(&opts.GitopsTemplateURL, "gitops-template-url", "https://github.com/konstructio/gitops-template.git", "the fully qualified url to the gitops-template repository to clone")
createCmd.Flags().StringVar(&opts.InstallCatalogApps, "install-catalog-apps", "", "comma separated values to install after provision")
createCmd.Flags().BoolVar(&opts.UseTelemetry, "use-telemetry", true, "whether to emit telemetry")
createCmd.Flags().BoolVar(&opts.ECR, "ecr", false, "whether or not to use ecr vs the git provider")
createCmd.Flags().BoolVar(&opts.InstallKubefirstPro, "install-kubefirst-pro", true, "whether or not to install kubefirst pro")

return createCmd
}
Expand Down
93 changes: 62 additions & 31 deletions cmd/aws/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,72 +21,55 @@ import (
"github.com/konstructio/kubefirst/internal/launch"
"github.com/konstructio/kubefirst/internal/progress"
"github.com/konstructio/kubefirst/internal/provision"
"github.com/konstructio/kubefirst/internal/types"
"github.com/konstructio/kubefirst/internal/utilities"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

func createAws(cmd *cobra.Command, _ []string) error {
cliFlags, err := utilities.GetFlags(cmd, "aws")
if err != nil {
progress.Error(err.Error())
return nil
}

progress.DisplayLogHints(40)
func (s *Service) createAwsCluster(cliFlags types.CliFlags) error {
// TODO - Add progress steps
// progress.DisplayLogHints(40)

isValid, catalogApps, err := catalog.ValidateCatalogApps(cliFlags.InstallCatalogApps)
if !isValid {
s.logger.Error("invalid catalog apps", "error", err)
return fmt.Errorf("invalid catalog apps: %w", err)
}

err = ValidateProvidedFlags(cliFlags.GitProvider)
if err != nil {
progress.Error(err.Error())
return fmt.Errorf("failed to validate provided flags: %w", err)
}

utilities.CreateK1ClusterDirectory(cliFlags.ClusterName)

// 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
}

// Validate aws region
config, err := awsinternal.NewAwsV2(cloudRegionFlag)
if err != nil {
progress.Error(err.Error())
s.logger.Error("failed to validate AWS region", "error", err)
return fmt.Errorf("failed to validate AWS region: %w", err)
}

awsClient := &awsinternal.Configuration{Config: config}
creds, err := awsClient.Config.Credentials.Retrieve(aws.BackgroundContext())
if err != nil {
progress.Error(err.Error())
s.logger.Error("failed to retrieve AWS credentials", "error", err)
return fmt.Errorf("failed to retrieve AWS credentials: %w", err)
}

viper.Set("kubefirst.state-store-creds.access-key-id", creds.AccessKeyID)
viper.Set("kubefirst.state-store-creds.secret-access-key-id", creds.SecretAccessKey)
viper.Set("kubefirst.state-store-creds.token", creds.SessionToken)
if err := viper.WriteConfig(); err != nil {
s.logger.Error("failed to write config", "error", err)

return fmt.Errorf("failed to write config: %w", err)
}

_, err = awsClient.CheckAvailabilityZones(cliFlags.CloudRegion)
if err != nil {
progress.Error(err.Error())
s.logger.Error("failed to check availability zones", "error", err)
return fmt.Errorf("failed to check availability zones: %w", err)
}

gitAuth, err := gitShim.ValidateGitCredentials(cliFlags.GitProvider, cliFlags.GithubOrg, cliFlags.GitlabGroup)
if err != nil {
progress.Error(err.Error())
s.logger.Error("failed to validate Git credentials", "error", err)
return fmt.Errorf("failed to validate Git credentials: %w", err)
}

Expand All @@ -105,13 +88,14 @@ func createAws(cmd *cobra.Command, _ []string) error {

err = gitShim.InitializeGitProvider(&initGitParameters)
if err != nil {
progress.Error(err.Error())
s.logger.Error("failed to initialize Git provider", "error", err)
return fmt.Errorf("failed to initialize Git provider: %w", err)
}
}

viper.Set(fmt.Sprintf("kubefirst-checks.%s-credentials", cliFlags.GitProvider), true)
if err := viper.WriteConfig(); err != nil {
s.logger.Error("failed to write config", "error", err)
return fmt.Errorf("failed to write config: %w", err)
}

Expand All @@ -124,18 +108,65 @@ func createAws(cmd *cobra.Command, _ []string) error {

err = pkg.IsAppAvailable(fmt.Sprintf("%s/api/proxyHealth", cluster.GetConsoleIngressURL()), "kubefirst api")
if err != nil {
progress.Error("unable to start kubefirst api")
s.logger.Error("failed to check kubefirst API availability", "error", err)
return fmt.Errorf("failed to check kubefirst API availability: %w", err)
}

if err := provision.CreateMgmtCluster(gitAuth, cliFlags, catalogApps); err != nil {
progress.Error(err.Error())
s.logger.Error("failed to create management cluster", "error", err)
return fmt.Errorf("failed to create management cluster: %w", err)
}

return nil
}

func (s *Service) createAws(cmd *cobra.Command, _ []string) error {
fmt.Fprintln(s.writer, "Starting to create AWS cluster")

cliFlags, err := utilities.GetFlags(cmd, "aws")
if err != nil {
s.logger.Error("failed to get flags", "error", err)
return fmt.Errorf("failed to get flags: %w", err)
}

err = ValidateProvidedFlags(cliFlags.GitProvider)
if err != nil {
s.logger.Error("failed to validate provided flags", "error", err)
return fmt.Errorf("failed to validate provided flags: %w", err)
}

// Create k1 cluster directory
homePath, err := os.UserHomeDir()
if err != nil {
s.logger.Error("failed to get user home directory", "error", err)
return fmt.Errorf("failed to get user home directory: %w", err)
}

err = utilities.CreateK1ClusterDirectoryE(homePath, cliFlags.ClusterName)
if err != nil {
s.logger.Error("failed to create k1 cluster directory", "error", err)
return fmt.Errorf("failed to create k1 cluster directory: %w", err)
}

// If cluster setup is complete, return
clusterSetupComplete := viper.GetBool("kubefirst-checks.cluster-install-complete")
if clusterSetupComplete {
s.logger.Info("cluster install process has already completed successfully")
fmt.Fprintln(s.writer, "Cluster install process has already completed successfully")
return nil
}

err = s.createAwsCluster(cliFlags)
if err != nil {
s.logger.Error("failed to create AWS cluster", "error", err)
return fmt.Errorf("failed to create AWS cluster: %w", err)
}

fmt.Fprintln(s.writer, "AWS cluster creation complete")

return nil
}

func ValidateProvidedFlags(gitProvider string) error {
progress.AddStep("Validate provided flags")

Expand Down
12 changes: 12 additions & 0 deletions cmd/aws/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package aws

import (
"io"

"github.com/konstructio/kubefirst/internal/common"
)

type Service struct {
logger common.Logger
writer io.Writer
}
4 changes: 0 additions & 4 deletions cmd/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,3 @@ var infoCmd = &cobra.Command{
return nil
},
}

func init() {
rootCmd.AddCommand(infoCmd)
}
4 changes: 0 additions & 4 deletions cmd/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,3 @@ var logsCmd = &cobra.Command{
return nil
},
}

func init() {
rootCmd.AddCommand(logsCmd)
}
4 changes: 0 additions & 4 deletions cmd/reset.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,6 @@ var resetCmd = &cobra.Command{
},
}

func init() {
rootCmd.AddCommand(resetCmd)
}

// parseConfigEntryKubefirstChecks gathers the kubefirst-checks section of the Viper
// config file and parses as a map[string]bool
func parseConfigEntryKubefirstChecks(checks map[string]interface{}) (map[string]bool, error) {
Expand Down
Loading
Loading