diff --git a/cmd/akamai/command.go b/cmd/akamai/command.go index 57999d57..5eff8a3a 100644 --- a/cmd/akamai/command.go +++ b/cmd/akamai/command.go @@ -10,8 +10,10 @@ import ( "fmt" "github.com/konstructio/kubefirst-api/pkg/constants" + "github.com/konstructio/kubefirst/internal/catalog" "github.com/konstructio/kubefirst/internal/common" "github.com/konstructio/kubefirst/internal/progress" + "github.com/konstructio/kubefirst/internal/provision" "github.com/konstructio/kubefirst/internal/utilities" "github.com/spf13/cobra" ) @@ -51,17 +53,29 @@ func Create() *cobra.Command { Short: "create the kubefirst platform running on akamai kubernetes", TraverseChildren: true, RunE: func(cmd *cobra.Command, _ []string) error { + ctx := cmd.Context() cliFlags, err := utilities.GetFlags(cmd, "akamai") if err != nil { progress.Error(err.Error()) return fmt.Errorf("failed to get flags: %w", err) } - akamaiService := Service{ - cliFlags: &cliFlags, + progress.DisplayLogHints(25) + + isValid, catalogApps, err := catalog.ValidateCatalogApps(ctx, cliFlags.InstallCatalogApps) + if !isValid { + return fmt.Errorf("catalog validation failed: %w", err) + } + + err = ValidateProvidedFlags(cliFlags.GitProvider, cliFlags.DNSProvider) + if err != nil { + progress.Error(err.Error()) + return fmt.Errorf("failed to validate flags: %w", err) } - if err := akamaiService.CreateCluster(cmd.Context()); err != nil { + provision := provision.Provisioner{} + + if err := provision.ProvisionManagementCluster(ctx, &cliFlags, catalogApps); err != nil { return fmt.Errorf("failed to create cluster: %w", err) } diff --git a/cmd/akamai/create.go b/cmd/akamai/create.go index 200b268a..349d8217 100644 --- a/cmd/akamai/create.go +++ b/cmd/akamai/create.go @@ -7,43 +7,14 @@ See the LICENSE file for more details. package akamai import ( - "context" "fmt" "os" internalssh "github.com/konstructio/kubefirst-api/pkg/ssh" - "github.com/konstructio/kubefirst/internal/catalog" "github.com/konstructio/kubefirst/internal/progress" - "github.com/konstructio/kubefirst/internal/provision" - "github.com/konstructio/kubefirst/internal/types" "github.com/rs/zerolog/log" ) -type Service struct { - cliFlags *types.CliFlags -} - -func (s *Service) CreateCluster(ctx context.Context) error { - progress.DisplayLogHints(25) - - isValid, catalogApps, err := catalog.ValidateCatalogApps(ctx, s.cliFlags.InstallCatalogApps) - if !isValid { - return fmt.Errorf("catalog validation failed: %w", err) - } - - err = ValidateProvidedFlags(s.cliFlags.GitProvider, s.cliFlags.DNSProvider) - if err != nil { - progress.Error(err.Error()) - return fmt.Errorf("failed to validate flags: %w", err) - } - - if err := provision.ManagementCluster(s.cliFlags, catalogApps); err != nil { - return fmt.Errorf("failed to provision management cluster: %w", err) - } - - return nil -} - func ValidateProvidedFlags(gitProvider, dnsProvider string) error { progress.AddStep("Validate provided flags") diff --git a/cmd/aws/command.go b/cmd/aws/command.go index 81fa6c6d..3f1523a4 100644 --- a/cmd/aws/command.go +++ b/cmd/aws/command.go @@ -9,11 +9,15 @@ package aws import ( "fmt" + "github.com/aws/aws-sdk-go-v2/config" "github.com/konstructio/kubefirst-api/pkg/constants" + "github.com/konstructio/kubefirst/internal/catalog" "github.com/konstructio/kubefirst/internal/common" "github.com/konstructio/kubefirst/internal/progress" + "github.com/konstructio/kubefirst/internal/provision" "github.com/konstructio/kubefirst/internal/utilities" "github.com/spf13/cobra" + "github.com/spf13/viper" ) var ( @@ -81,23 +85,52 @@ func Create() *cobra.Command { Short: "create the kubefirst platform running in aws", TraverseChildren: true, RunE: func(cmd *cobra.Command, _ []string) error { + ctx := cmd.Context() cliFlags, err := utilities.GetFlags(cmd, "aws") if err != nil { progress.Error(err.Error()) return fmt.Errorf("failed to get flags: %w", err) } - awsService := Service{ - cliFlags: &cliFlags, + progress.DisplayLogHints(40) + + isValid, catalogApps, err := catalog.ValidateCatalogApps(ctx, cliFlags.InstallCatalogApps) + if !isValid { + return fmt.Errorf("invalid catalog apps: %w", err) + } + + cfg, err := config.LoadDefaultConfig(ctx, config.WithRegion(cliFlags.CloudRegion)) + if err != nil { + return fmt.Errorf("unable to load AWS SDK config: %w", err) + } + + err = ValidateProvidedFlags(ctx, cfg, cliFlags.GitProvider, cliFlags.AMIType, cliFlags.NodeType) + if err != nil { + progress.Error(err.Error()) + return fmt.Errorf("failed to validate provided flags: %w", err) } - if err := awsService.CreateCluster(cmd.Context()); err != nil { - return fmt.Errorf("failed to create cluster: %w", err) + creds, err := getSessionCredentials(ctx, cfg.Credentials) + if err != nil { + progress.Error(err.Error()) + 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 { + return fmt.Errorf("failed to write config: %w", err) + } + + provision := provision.Provisioner{} + + if err := provision.ProvisionManagementCluster(ctx, &cliFlags, catalogApps); err != nil { + return fmt.Errorf("failed to provision aws management cluster: %w", err) } return nil }, - // PreRun: common.CheckDocker, } awsDefaults := constants.GetCloudDefaults().Aws diff --git a/cmd/aws/create.go b/cmd/aws/create.go index 53a60e7f..10954e4c 100644 --- a/cmd/aws/create.go +++ b/cmd/aws/create.go @@ -13,62 +13,14 @@ import ( "slices" "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/ec2" ec2Types "github.com/aws/aws-sdk-go-v2/service/ec2/types" "github.com/aws/aws-sdk-go-v2/service/ssm" internalssh "github.com/konstructio/kubefirst-api/pkg/ssh" - "github.com/konstructio/kubefirst/internal/catalog" "github.com/konstructio/kubefirst/internal/progress" - "github.com/konstructio/kubefirst/internal/provision" - "github.com/konstructio/kubefirst/internal/types" "github.com/rs/zerolog/log" - "github.com/spf13/viper" ) -type Service struct { - cliFlags *types.CliFlags -} - -func (s *Service) CreateCluster(ctx context.Context) error { - progress.DisplayLogHints(40) - - isValid, catalogApps, err := catalog.ValidateCatalogApps(ctx, s.cliFlags.InstallCatalogApps) - if !isValid { - return fmt.Errorf("invalid catalog apps: %w", err) - } - - cfg, err := config.LoadDefaultConfig(ctx, config.WithRegion(s.cliFlags.CloudRegion)) - if err != nil { - return fmt.Errorf("unable to load AWS SDK config: %w", err) - } - - err = ValidateProvidedFlags(ctx, cfg, s.cliFlags.GitProvider, s.cliFlags.AMIType, s.cliFlags.NodeType) - if err != nil { - progress.Error(err.Error()) - return fmt.Errorf("failed to validate provided flags: %w", err) - } - - creds, err := getSessionCredentials(ctx, cfg.Credentials) - if err != nil { - progress.Error(err.Error()) - 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 { - return fmt.Errorf("failed to write config: %w", err) - } - - if err := provision.ManagementCluster(s.cliFlags, catalogApps); err != nil { - return fmt.Errorf("failed to provision management cluster: %w", err) - } - - return nil -} - func ValidateProvidedFlags(ctx context.Context, cfg aws.Config, gitProvider, amiType, nodeType string) error { progress.AddStep("Validate provided flags") diff --git a/cmd/azure/command.go b/cmd/azure/command.go index 67b75050..e8b83727 100644 --- a/cmd/azure/command.go +++ b/cmd/azure/command.go @@ -11,8 +11,10 @@ import ( "fmt" "github.com/konstructio/kubefirst-api/pkg/constants" + "github.com/konstructio/kubefirst/internal/catalog" "github.com/konstructio/kubefirst/internal/common" "github.com/konstructio/kubefirst/internal/progress" + "github.com/konstructio/kubefirst/internal/provision" "github.com/konstructio/kubefirst/internal/utilities" "github.com/spf13/cobra" ) @@ -56,17 +58,30 @@ func Create() *cobra.Command { Short: "create the kubefirst platform running on Azure kubernetes", TraverseChildren: true, RunE: func(cmd *cobra.Command, _ []string) error { + ctx := cmd.Context() cliFlags, err := utilities.GetFlags(cmd, "azure") if err != nil { progress.Error(err.Error()) return fmt.Errorf("failed to get flags: %w", err) } - azureService := Service{ - cliFlags: &cliFlags, + progress.DisplayLogHints(20) + + isValid, catalogApps, err := catalog.ValidateCatalogApps(ctx, cliFlags.InstallCatalogApps) + if !isValid { + progress.Error(err.Error()) + return nil } - if err := azureService.CreateCluster(cmd.Context()); err != nil { + err = ValidateProvidedFlags(cliFlags.GitProvider) + if err != nil { + progress.Error(err.Error()) + return nil + } + + provision := provision.Provisioner{} + + if err := provision.ProvisionManagementCluster(ctx, &cliFlags, catalogApps); err != nil { return fmt.Errorf("failed to create Azure management cluster: %w", err) } diff --git a/cmd/azure/create.go b/cmd/azure/create.go index 7548c8a5..d3067189 100644 --- a/cmd/azure/create.go +++ b/cmd/azure/create.go @@ -7,15 +7,11 @@ See the LICENSE file for more details. package azure import ( - "context" "fmt" "os" internalssh "github.com/konstructio/kubefirst-api/pkg/ssh" - "github.com/konstructio/kubefirst/internal/catalog" "github.com/konstructio/kubefirst/internal/progress" - "github.com/konstructio/kubefirst/internal/provision" - "github.com/konstructio/kubefirst/internal/types" "github.com/rs/zerolog/log" ) @@ -30,32 +26,6 @@ var envvarSecrets = []string{ "ARM_SUBSCRIPTION_ID", } -type Service struct { - cliFlags *types.CliFlags -} - -func (s *Service) CreateCluster(ctx context.Context) error { - progress.DisplayLogHints(20) - - isValid, catalogApps, err := catalog.ValidateCatalogApps(ctx, s.cliFlags.InstallCatalogApps) - if !isValid { - progress.Error(err.Error()) - return nil - } - - err = ValidateProvidedFlags(s.cliFlags.GitProvider) - if err != nil { - progress.Error(err.Error()) - return nil - } - - if err := provision.ManagementCluster(s.cliFlags, catalogApps); err != nil { - return fmt.Errorf("failed to provision management cluster: %w", err) - } - - return nil -} - func ValidateProvidedFlags(gitProvider string) error { progress.AddStep("Validate provided flags") diff --git a/cmd/civo/command.go b/cmd/civo/command.go index 8782f29f..3ed35593 100644 --- a/cmd/civo/command.go +++ b/cmd/civo/command.go @@ -10,8 +10,10 @@ import ( "fmt" "github.com/konstructio/kubefirst-api/pkg/constants" + "github.com/konstructio/kubefirst/internal/catalog" "github.com/konstructio/kubefirst/internal/common" "github.com/konstructio/kubefirst/internal/progress" + "github.com/konstructio/kubefirst/internal/provision" "github.com/konstructio/kubefirst/internal/utilities" "github.com/spf13/cobra" ) @@ -62,18 +64,29 @@ func Create() *cobra.Command { Short: "Create the Kubefirst platform running on Civo Kubernetes", TraverseChildren: true, RunE: func(cmd *cobra.Command, _ []string) error { + ctx := cmd.Context() cliFlags, err := utilities.GetFlags(cmd, "civo") if err != nil { progress.Error(err.Error()) return fmt.Errorf("failed to get CLI flags: %w", err) } - service := &Service{ - cliFlags: &cliFlags, + progress.DisplayLogHints(15) + + isValid, catalogApps, err := catalog.ValidateCatalogApps(ctx, cliFlags.InstallCatalogApps) + if !isValid { + return fmt.Errorf("catalog apps validation failed: %w", err) } - err = service.CreateCluster(cmd.Context()) + err = ValidateProvidedFlags(cliFlags.GitProvider, cliFlags.DNSProvider) if err != nil { + progress.Error(err.Error()) + return fmt.Errorf("failed to validate provided flags: %w", err) + } + + provision := provision.Provisioner{} + + if err := provision.ProvisionManagementCluster(ctx, &cliFlags, catalogApps); err != nil { return fmt.Errorf("failed to create Civo management cluster: %w", err) } diff --git a/cmd/civo/create.go b/cmd/civo/create.go index a275aa69..815044a9 100644 --- a/cmd/civo/create.go +++ b/cmd/civo/create.go @@ -7,43 +7,14 @@ See the LICENSE file for more details. package civo import ( - "context" "fmt" "os" internalssh "github.com/konstructio/kubefirst-api/pkg/ssh" - "github.com/konstructio/kubefirst/internal/catalog" "github.com/konstructio/kubefirst/internal/progress" - "github.com/konstructio/kubefirst/internal/provision" - "github.com/konstructio/kubefirst/internal/types" "github.com/rs/zerolog/log" ) -type Service struct { - cliFlags *types.CliFlags -} - -func (s *Service) CreateCluster(ctx context.Context) error { - progress.DisplayLogHints(15) - - isValid, catalogApps, err := catalog.ValidateCatalogApps(ctx, s.cliFlags.InstallCatalogApps) - if !isValid { - return fmt.Errorf("catalog apps validation failed: %w", err) - } - - err = ValidateProvidedFlags(s.cliFlags.GitProvider, s.cliFlags.DNSProvider) - if err != nil { - progress.Error(err.Error()) - return fmt.Errorf("failed to validate provided flags: %w", err) - } - - if err := provision.ManagementCluster(s.cliFlags, catalogApps); err != nil { - return fmt.Errorf("failed to provision management cluster: %w", err) - } - - return nil -} - func ValidateProvidedFlags(gitProvider, dnsProvider string) error { progress.AddStep("Validate provided flags") diff --git a/cmd/digitalocean/command.go b/cmd/digitalocean/command.go index fbba97cc..fd4d0090 100644 --- a/cmd/digitalocean/command.go +++ b/cmd/digitalocean/command.go @@ -7,11 +7,14 @@ See the LICENSE file for more details. package digitalocean import ( + "errors" "fmt" "github.com/konstructio/kubefirst-api/pkg/constants" + "github.com/konstructio/kubefirst/internal/catalog" "github.com/konstructio/kubefirst/internal/common" "github.com/konstructio/kubefirst/internal/progress" + "github.com/konstructio/kubefirst/internal/provision" "github.com/konstructio/kubefirst/internal/utilities" "github.com/spf13/cobra" ) @@ -54,17 +57,33 @@ func Create() *cobra.Command { Short: "create the Kubefirst platform running on DigitalOcean Kubernetes", TraverseChildren: true, RunE: func(cmd *cobra.Command, _ []string) error { + ctx := cmd.Context() cliFlags, err := utilities.GetFlags(cmd, "digitalocean") if err != nil { progress.Error(err.Error()) return fmt.Errorf("failed to get flags: %w", err) } - digitaloceanService := Service{ - cliFlags: &cliFlags, + progress.DisplayLogHints(20) + + isValid, catalogApps, err := catalog.ValidateCatalogApps(ctx, cliFlags.InstallCatalogApps) + if err != nil { + return fmt.Errorf("catalog validation error: %w", err) } - if err := digitaloceanService.CreateCluster(cmd.Context()); err != nil { + if !isValid { + return errors.New("catalog did not pass a validation check") + } + + err = ValidateProvidedFlags(cliFlags.GitProvider, cliFlags.DNSProvider) + if err != nil { + progress.Error(err.Error()) + return fmt.Errorf("failed to validate provided flags: %w", err) + } + + provision := provision.Provisioner{} + + if err := provision.ProvisionManagementCluster(ctx, &cliFlags, catalogApps); err != nil { return fmt.Errorf("failed to create DigitalOcean management cluster: %w", err) } diff --git a/cmd/digitalocean/create.go b/cmd/digitalocean/create.go index e08a0049..596d6b2e 100644 --- a/cmd/digitalocean/create.go +++ b/cmd/digitalocean/create.go @@ -7,48 +7,14 @@ See the LICENSE file for more details. package digitalocean import ( - "context" - "errors" "fmt" "os" internalssh "github.com/konstructio/kubefirst-api/pkg/ssh" - "github.com/konstructio/kubefirst/internal/catalog" "github.com/konstructio/kubefirst/internal/progress" - "github.com/konstructio/kubefirst/internal/provision" - "github.com/konstructio/kubefirst/internal/types" "github.com/rs/zerolog/log" ) -type Service struct { - cliFlags *types.CliFlags -} - -func (s *Service) CreateCluster(ctx context.Context) error { - progress.DisplayLogHints(20) - - isValid, catalogApps, err := catalog.ValidateCatalogApps(ctx, s.cliFlags.InstallCatalogApps) - if err != nil { - return fmt.Errorf("catalog validation error: %w", err) - } - - if !isValid { - return errors.New("catalog did not pass a validation check") - } - - err = ValidateProvidedFlags(s.cliFlags.GitProvider, s.cliFlags.DNSProvider) - if err != nil { - progress.Error(err.Error()) - return fmt.Errorf("failed to validate provided flags: %w", err) - } - - if err := provision.ManagementCluster(s.cliFlags, catalogApps); err != nil { - return fmt.Errorf("failed to provision management cluster: %w", err) - } - - return nil -} - func ValidateProvidedFlags(gitProvider, dnsProvider string) error { progress.AddStep("Validate provided flags") diff --git a/cmd/google/command.go b/cmd/google/command.go index 54497587..3e9a88ca 100644 --- a/cmd/google/command.go +++ b/cmd/google/command.go @@ -10,8 +10,10 @@ import ( "fmt" "github.com/konstructio/kubefirst-api/pkg/constants" + "github.com/konstructio/kubefirst/internal/catalog" "github.com/konstructio/kubefirst/internal/common" "github.com/konstructio/kubefirst/internal/progress" + "github.com/konstructio/kubefirst/internal/provision" "github.com/konstructio/kubefirst/internal/utilities" "github.com/spf13/cobra" ) @@ -55,18 +57,29 @@ func Create() *cobra.Command { Short: "create the kubefirst platform running on GCP Kubernetes", TraverseChildren: true, RunE: func(cmd *cobra.Command, _ []string) error { + ctx := cmd.Context() cliFlags, err := utilities.GetFlags(cmd, "google") if err != nil { progress.Error(err.Error()) return fmt.Errorf("failed to get flags: %w", err) } - googleService := Service{ - cliFlags: &cliFlags, + progress.DisplayLogHints(20) + + isValid, catalogApps, err := catalog.ValidateCatalogApps(ctx, cliFlags.InstallCatalogApps) + if !isValid { + return fmt.Errorf("catalog apps validation failed: %w", err) } - err = googleService.CreateCluster(cmd.Context()) + err = ValidateProvidedFlags(cliFlags.GitProvider) if err != nil { + progress.Error(err.Error()) + return fmt.Errorf("validation of provided flags failed: %w", err) + } + + provision := provision.Provisioner{} + + if err := provision.ProvisionManagementCluster(ctx, &cliFlags, catalogApps); err != nil { progress.Error(err.Error()) return fmt.Errorf("failed to create google management cluster: %w", err) } diff --git a/cmd/google/create.go b/cmd/google/create.go index 846ca53c..db8b53d8 100644 --- a/cmd/google/create.go +++ b/cmd/google/create.go @@ -7,44 +7,15 @@ See the LICENSE file for more details. package google import ( - "context" "fmt" "os" internalssh "github.com/konstructio/kubefirst-api/pkg/ssh" - "github.com/konstructio/kubefirst/internal/catalog" "github.com/konstructio/kubefirst/internal/progress" - "github.com/konstructio/kubefirst/internal/provision" - "github.com/konstructio/kubefirst/internal/types" "github.com/rs/zerolog/log" _ "k8s.io/client-go/plugin/pkg/client/auth" // required for authentication ) -type Service struct { - cliFlags *types.CliFlags -} - -func (s *Service) CreateCluster(ctx context.Context) error { - progress.DisplayLogHints(20) - - isValid, catalogApps, err := catalog.ValidateCatalogApps(ctx, s.cliFlags.InstallCatalogApps) - if !isValid { - return fmt.Errorf("catalog apps validation failed: %w", err) - } - - err = ValidateProvidedFlags(s.cliFlags.GitProvider) - if err != nil { - progress.Error(err.Error()) - return fmt.Errorf("validation of provided flags failed: %w", err) - } - - if err := provision.ManagementCluster(s.cliFlags, catalogApps); err != nil { - return fmt.Errorf("failed to provision management cluster: %w", err) - } - - return nil -} - func ValidateProvidedFlags(gitProvider string) error { progress.AddStep("Validate provided flags") diff --git a/cmd/k3s/command.go b/cmd/k3s/command.go index 92b00c6b..99fb365d 100644 --- a/cmd/k3s/command.go +++ b/cmd/k3s/command.go @@ -7,9 +7,13 @@ See the LICENSE file for more details. package k3s import ( + "errors" "fmt" + "github.com/konstructio/kubefirst/internal/catalog" "github.com/konstructio/kubefirst/internal/common" + "github.com/konstructio/kubefirst/internal/progress" + "github.com/konstructio/kubefirst/internal/provision" "github.com/konstructio/kubefirst/internal/utilities" "github.com/spf13/cobra" ) @@ -45,16 +49,32 @@ func Create() *cobra.Command { Short: "create the kubefirst platform running on premise", TraverseChildren: true, RunE: func(cmd *cobra.Command, _ []string) error { + ctx := cmd.Context() cliFlags, err := utilities.GetFlags(cmd, "k3s") if err != nil { return fmt.Errorf("failed to get flags: %w", err) } - k3sService := Service{ - cliFlags: &cliFlags, + progress.DisplayLogHints(20) + + isValid, catalogApps, err := catalog.ValidateCatalogApps(ctx, cliFlags.InstallCatalogApps) + if err != nil { + return fmt.Errorf("validation of catalog apps failed: %w", err) + } + + if !isValid { + return errors.New("catalog validation failed") } - if err := k3sService.CreateCluster(cmd.Context()); err != nil { + err = ValidateProvidedFlags(cliFlags.GitProvider) + if err != nil { + progress.Error(err.Error()) + return fmt.Errorf("provided flags validation failed: %w", err) + } + + provision := provision.Provisioner{} + + if err := provision.ProvisionManagementCluster(ctx, &cliFlags, catalogApps); err != nil { return fmt.Errorf("failed to create k3s management cluster: %w", err) } diff --git a/cmd/k3s/create.go b/cmd/k3s/create.go index 219f4dc7..73723d84 100644 --- a/cmd/k3s/create.go +++ b/cmd/k3s/create.go @@ -7,49 +7,15 @@ See the LICENSE file for more details. package k3s import ( - "context" - "errors" "fmt" "github.com/rs/zerolog/log" internalssh "github.com/konstructio/kubefirst-api/pkg/ssh" - "github.com/konstructio/kubefirst/internal/catalog" "github.com/konstructio/kubefirst/internal/progress" - "github.com/konstructio/kubefirst/internal/provision" - "github.com/konstructio/kubefirst/internal/types" _ "k8s.io/client-go/plugin/pkg/client/auth" // required for k8s authentication ) -type Service struct { - cliFlags *types.CliFlags -} - -func (s *Service) CreateCluster(ctx context.Context) error { - progress.DisplayLogHints(20) - - isValid, catalogApps, err := catalog.ValidateCatalogApps(ctx, s.cliFlags.InstallCatalogApps) - if err != nil { - return fmt.Errorf("validation of catalog apps failed: %w", err) - } - - if !isValid { - return errors.New("catalog validation failed") - } - - err = ValidateProvidedFlags(s.cliFlags.GitProvider) - if err != nil { - progress.Error(err.Error()) - return fmt.Errorf("provided flags validation failed: %w", err) - } - - if err := provision.ManagementCluster(s.cliFlags, catalogApps); err != nil { - return fmt.Errorf("failed to provision management cluster: %w", err) - } - - return nil -} - func ValidateProvidedFlags(gitProvider string) error { progress.AddStep("Validate provided flags") diff --git a/cmd/launch.go b/cmd/launch.go index 88b23c5a..ce07adf4 100644 --- a/cmd/launch.go +++ b/cmd/launch.go @@ -10,6 +10,7 @@ import ( "fmt" "github.com/konstructio/kubefirst/internal/launch" + "github.com/konstructio/kubefirst/internal/progress" "github.com/spf13/cobra" ) @@ -35,8 +36,13 @@ func launchUp() *cobra.Command { Use: "up", Short: "launch new console and api instance", TraverseChildren: true, - Run: func(_ *cobra.Command, _ []string) { - launch.Up(additionalHelmFlags, false, true) + RunE: func(cmd *cobra.Command, _ []string) error { + if err := launch.Up(cmd.Context(), additionalHelmFlags, false, true); err != nil { + progress.Error(err.Error()) + return fmt.Errorf("failed to launch console and api: %w", err) + } + + return nil }, } diff --git a/cmd/root.go b/cmd/root.go index a173364e..d5899c60 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -47,6 +47,8 @@ func Execute() { SilenceUsage: true, } + output := rootCmd.ErrOrStderr() + rootCmd.AddCommand( aws.NewCommand(), azure.NewCommand(), @@ -74,9 +76,8 @@ func Execute() { common.CheckForVersionUpdate() progressPrinter.GetInstance() if err := rootCmd.Execute(); err != nil { - fmt.Println("Error occurred during command execution:", err) - fmt.Println("If a detailed error message was available, please make the necessary corrections before retrying.") - fmt.Println("You can re-run the last command to try the operation again.") + fmt.Fprintln(output, "If a detailed error message was available, please make the necessary corrections before retrying.") + fmt.Fprintln(output, "You can re-run the last command to try the operation again.") progress.Progress.Quit() } } diff --git a/cmd/vultr/command.go b/cmd/vultr/command.go index bbb16348..49efe307 100644 --- a/cmd/vultr/command.go +++ b/cmd/vultr/command.go @@ -7,11 +7,14 @@ See the LICENSE file for more details. package vultr import ( + "errors" "fmt" "github.com/konstructio/kubefirst-api/pkg/constants" + "github.com/konstructio/kubefirst/internal/catalog" "github.com/konstructio/kubefirst/internal/common" "github.com/konstructio/kubefirst/internal/progress" + "github.com/konstructio/kubefirst/internal/provision" "github.com/konstructio/kubefirst/internal/utilities" "github.com/spf13/cobra" ) @@ -54,18 +57,33 @@ func Create() *cobra.Command { Short: "Create the Kubefirst platform running on Vultr Kubernetes", TraverseChildren: true, RunE: func(cmd *cobra.Command, _ []string) error { + ctx := cmd.Context() cliFlags, err := utilities.GetFlags(cmd, "vultr") if err != nil { progress.Error(err.Error()) return fmt.Errorf("failed to get flags: %w", err) } - vultrService := Service{ - cliFlags: &cliFlags, + progress.DisplayLogHints(15) + + isValid, catalogApps, err := catalog.ValidateCatalogApps(ctx, cliFlags.InstallCatalogApps) + if err != nil { + return fmt.Errorf("catalog apps validation failed: %w", err) + } + + if !isValid { + return errors.New("catalog validation failed") } - err = vultrService.CreateCluster(cmd.Context()) + err = ValidateProvidedFlags(cliFlags.GitProvider, cliFlags.DNSProvider) if err != nil { + progress.Error(err.Error()) + return fmt.Errorf("invalid provided flags: %w", err) + } + + provision := provision.Provisioner{} + + if err := provision.ProvisionManagementCluster(ctx, &cliFlags, catalogApps); err != nil { progress.Error(err.Error()) return fmt.Errorf("failed to create vultr management cluster: %w", err) } diff --git a/cmd/vultr/create.go b/cmd/vultr/create.go index 9406c834..8ca75fdc 100644 --- a/cmd/vultr/create.go +++ b/cmd/vultr/create.go @@ -7,48 +7,14 @@ See the LICENSE file for more details. package vultr import ( - "context" - "errors" "fmt" "os" internalssh "github.com/konstructio/kubefirst-api/pkg/ssh" - "github.com/konstructio/kubefirst/internal/catalog" "github.com/konstructio/kubefirst/internal/progress" - "github.com/konstructio/kubefirst/internal/provision" - "github.com/konstructio/kubefirst/internal/types" "github.com/rs/zerolog/log" ) -type Service struct { - cliFlags *types.CliFlags -} - -func (s *Service) CreateCluster(ctx context.Context) error { - progress.DisplayLogHints(15) - - isValid, catalogApps, err := catalog.ValidateCatalogApps(ctx, s.cliFlags.InstallCatalogApps) - if err != nil { - return fmt.Errorf("catalog apps validation failed: %w", err) - } - - if !isValid { - return errors.New("catalog validation failed") - } - - err = ValidateProvidedFlags(s.cliFlags.GitProvider, s.cliFlags.DNSProvider) - if err != nil { - progress.Error(err.Error()) - return fmt.Errorf("invalid provided flags: %w", err) - } - - if err := provision.ManagementCluster(s.cliFlags, catalogApps); err != nil { - return fmt.Errorf("failed to provision management cluster: %w", err) - } - - return nil -} - func ValidateProvidedFlags(gitProvider, dnsProvider string) error { progress.AddStep("Validate provided flags") diff --git a/internal/launch/cmd.go b/internal/launch/cmd.go index bc2058a0..426680f3 100644 --- a/internal/launch/cmd.go +++ b/internal/launch/cmd.go @@ -35,13 +35,13 @@ import ( var consoleClusterName = "kubefirst-console" // Up -func Up(additionalHelmFlags []string, inCluster, useTelemetry bool) { +func Up(ctx context.Context, additionalHelmFlags []string, inCluster, useTelemetry bool) error { if viper.GetBool("launch.deployed") { message := `## Kubefirst console has already been deployed. To start over, run` + "`" + `kubefirst launch down` + "`" + `to completely remove the existing console.` progress.Success(message) - return + return nil } if !inCluster { @@ -50,9 +50,9 @@ Kubefirst console has already been deployed. To start over, run` + "`" + `kubefi homeDir, err := os.UserHomeDir() if err != nil { - progress.Error(fmt.Sprintf("unable to get user's home directory: %s", err)) - return + return fmt.Errorf("error getting user's home directory: %w", err) } + dir := fmt.Sprintf("%s/.k1/%s", homeDir, consoleClusterName) if _, err := os.Stat(dir); os.IsNotExist(err) { err := os.MkdirAll(dir, os.ModePerm) @@ -85,13 +85,11 @@ Kubefirst console has already been deployed. To start over, run` + "`" + `kubefi ) err = downloadManager.DownloadFile(k3dClient, k3dDownloadURL) if err != nil { - progress.Error(fmt.Sprintf("error while trying to download k3d: %s", err)) - return + return fmt.Errorf("error while trying to download k3d: %w", err) } err = os.Chmod(k3dClient, 0o755) if err != nil { - progress.Error(fmt.Sprintf("error changing permissions of k3d client: %s", err)) - return + return fmt.Errorf("error changing permissions of k3d client: %w", err) } } else { log.Info().Msg("k3d is already installed, continuing") @@ -113,13 +111,11 @@ Kubefirst console has already been deployed. To start over, run` + "`" + `kubefi helmDownloadTarGzPath := fmt.Sprintf("%s/helm.tar.gz", toolsDir) err = downloadManager.DownloadFile(helmDownloadTarGzPath, helmDownloadURL) if err != nil { - progress.Error(fmt.Sprintf("error while trying to download helm: %s", err)) - return + return fmt.Errorf("error while trying to download helm: %w", err) } helmTarDownload, err := os.Open(helmDownloadTarGzPath) if err != nil { - progress.Error(fmt.Sprintf("could not read helm download content: %s", err)) - return + return fmt.Errorf("could not read helm download content: %w", err) } downloadManager.ExtractFileFromTarGz( helmTarDownload, @@ -128,8 +124,7 @@ Kubefirst console has already been deployed. To start over, run` + "`" + `kubefi ) err = os.Chmod(helmClient, 0o755) if err != nil { - progress.Error(fmt.Sprintf("error changing permissions of helm client: %s", err)) - return + return fmt.Errorf("error changing permissions of helm client: %w", err) } os.Remove(helmDownloadTarGzPath) } else { @@ -150,13 +145,11 @@ Kubefirst console has already been deployed. To start over, run` + "`" + `kubefi ) err = downloadManager.DownloadFile(mkcertClient, mkcertDownloadURL) if err != nil { - progress.Error(fmt.Sprintf("error while trying to download mkcert: %s", err)) - return + return fmt.Errorf("error while trying to download mkcert: %w", err) } err = os.Chmod(mkcertClient, 0o755) if err != nil { - progress.Error(fmt.Sprintf("error changing permissions of mkcert client: %s", err)) - return + return fmt.Errorf("error changing permissions of mkcert client: %w", err) } } else { log.Info().Msg("mkcert is already installed, continuing") @@ -182,8 +175,7 @@ Kubefirst console has already been deployed. To start over, run` + "`" + `kubefi fmt.Sprintf("%s/kubeconfig", dir), ) if err != nil { - progress.Error(fmt.Sprintf("error creating k3d cluster: %s", err)) - return + return fmt.Errorf("error creating k3d cluster: %w", err) } log.Info().Msg("k3d cluster for Kubefirst console and API created successfully") @@ -191,8 +183,7 @@ Kubefirst console has already been deployed. To start over, run` + "`" + `kubefi // Wait for traefik kcfg, err := k8s.CreateKubeConfig(false, kubeconfigPath) if err != nil { - progress.Error(fmt.Sprintf("error creating kubernetes client: %s", err)) - return + return fmt.Errorf("error creating kubernetes client: %w", err) } log.Info().Msg("Waiting for traefik...") @@ -204,13 +195,11 @@ Kubefirst console has already been deployed. To start over, run` + "`" + `kubefi 240, ) if err != nil { - progress.Error(fmt.Sprintf("error looking for traefik: %s", err)) - return + return fmt.Errorf("error looking for traefik: %w", err) } _, err = k8s.WaitForDeploymentReady(kcfg.Clientset, traefikDeployment, 120) if err != nil { - progress.Error(fmt.Sprintf("error waiting for traefik: %s", err)) - return + return fmt.Errorf("error waiting for traefik: %w", err) } } @@ -226,16 +215,14 @@ Kubefirst console has already been deployed. To start over, run` + "`" + `kubefi kubeconfigPath, ) if err != nil { - progress.Error(fmt.Sprintf("error getting kubeconfig: %s", err)) - return + return fmt.Errorf("error getting kubeconfig: %w", err) } } // Establish Kubernetes client for console cluster kcfg, err := k8s.CreateKubeConfig(false, kubeconfigPath) if err != nil { - progress.Error(fmt.Sprintf("error creating kubernetes client: %s", err)) - return + return fmt.Errorf("error creating kubernetes client: %w", err) } // Determine if helm chart repository has already been added @@ -247,8 +234,7 @@ Kubefirst console has already been deployed. To start over, run` + "`" + `kubefi "yaml", ) if err != nil { - progress.Error(fmt.Sprintf("error listing current helm repositories: %s", err)) - return + return fmt.Errorf("error listing current helm repositories: %w", err) } var existingHelmRepositories []helm.Repo @@ -256,8 +242,7 @@ Kubefirst console has already been deployed. To start over, run` + "`" + `kubefi err = yaml.Unmarshal([]byte(res), &existingHelmRepositories) if err != nil { - progress.Error(fmt.Sprintf("could not get existing helm repositories: %s", err)) - return + return fmt.Errorf("could not get existing helm repositories: %w", err) } for _, repo := range existingHelmRepositories { @@ -276,8 +261,7 @@ Kubefirst console has already been deployed. To start over, run` + "`" + `kubefi helmChartRepoURL, ) if err != nil { - progress.Error(fmt.Sprintf("error adding helm chart repository: %s", err)) - return + return fmt.Errorf("error adding helm chart repository: %w", err) } log.Info().Msg("Added Kubefirst helm chart repository") } else { @@ -291,8 +275,7 @@ Kubefirst console has already been deployed. To start over, run` + "`" + `kubefi "update", ) if err != nil { - progress.Error(fmt.Sprintf("error updating helm chart repository: %s", err)) - return + return fmt.Errorf("error updating helm chart repository: %w", err) } log.Info().Msg("Kubefirst helm chart repository updated") @@ -307,8 +290,7 @@ Kubefirst console has already been deployed. To start over, run` + "`" + `kubefi "-A", ) if err != nil { - progress.Error(fmt.Sprintf("error listing current helm releases: %s", err)) - return + return fmt.Errorf("error listing current helm releases: %w", err) } var existingHelmReleases []helm.Release @@ -316,8 +298,7 @@ Kubefirst console has already been deployed. To start over, run` + "`" + `kubefi err = yaml.Unmarshal([]byte(res), &existingHelmReleases) if err != nil { - progress.Error(fmt.Sprintf("could not get existing helm releases: %s", err)) - return + return fmt.Errorf("could not get existing helm releases: %w", err) } for _, release := range existingHelmReleases { if release.Name == helmChartName { @@ -384,10 +365,9 @@ Kubefirst console has already been deployed. To start over, run` + "`" + `kubefi installFlags = append(installFlags, "--create-namespace") // Install helm chart - a, b, err := shell.ExecShellReturnStrings(helmClient, installFlags...) + _, _, err := shell.ExecShellReturnStrings(helmClient, installFlags...) if err != nil { - progress.Error(fmt.Sprintf("error installing helm chart: %s %s %s", err, a, b)) - return + return fmt.Errorf("error installing helm chart: %w", err) } log.Info().Msg("Kubefirst console helm chart installed successfully") @@ -409,14 +389,12 @@ Kubefirst console has already been deployed. To start over, run` + "`" + `kubefi 240, ) if err != nil { - progress.Error(fmt.Sprintf("error looking for kubefirst api: %s", err)) - return + return fmt.Errorf("error looking for kubefirst api: %w", err) } _, err = k8s.WaitForDeploymentReady(kcfg.Clientset, apiDeployment, 300) if err != nil { - progress.Error(fmt.Sprintf("error waiting for kubefirst api: %s", err)) - return + return fmt.Errorf("error waiting for kubefirst api: %w", err) } // Generate certificate for console @@ -424,8 +402,7 @@ Kubefirst console has already been deployed. To start over, run` + "`" + `kubefi if _, err := os.Stat(sslPemDir); os.IsNotExist(err) { err := os.MkdirAll(sslPemDir, os.ModePerm) if err != nil { - progress.Error(fmt.Sprintf("error creating directory for certificates: %s", err)) - return + return fmt.Errorf("error creating directory for certificates: %w", err) } } log.Info().Msg("Certificate directory created") @@ -434,8 +411,7 @@ Kubefirst console has already been deployed. To start over, run` + "`" + `kubefi if _, err := os.Stat(mkcertPemDir); os.IsNotExist(err) { err := os.MkdirAll(mkcertPemDir, os.ModePerm) if err != nil { - progress.Error(fmt.Sprintf("error creating directory for certificates: %s", err)) - return + return fmt.Errorf("error creating directory for certificates: %w", err) } } @@ -453,27 +429,24 @@ Kubefirst console has already been deployed. To start over, run` + "`" + `kubefi fullAppAddress, ) if err != nil { - progress.Error(fmt.Sprintf("error generating certificate for console: %s", err)) - return + return fmt.Errorf("error generating certificate for console: %w", err) } // * read certificate files certPem, err := os.ReadFile(fmt.Sprintf("%s/%s-cert.pem", mkcertPemDir, "kubefirst-console")) if err != nil { - progress.Error(fmt.Sprintf("error reading certificate for console: %s", err)) - return + return fmt.Errorf("error reading certificate for console: %w", err) } keyPem, err := os.ReadFile(fmt.Sprintf("%s/%s-key.pem", mkcertPemDir, "kubefirst-console")) if err != nil { - progress.Error(fmt.Sprintf("error reading key for console: %s", err)) - return + return fmt.Errorf("error reading key for console: %w", err) } - _, err = kcfg.Clientset.CoreV1().Secrets(namespace).Get(context.Background(), "kubefirst-console-tls", metav1.GetOptions{}) + _, err = kcfg.Clientset.CoreV1().Secrets(namespace).Get(ctx, "kubefirst-console-tls", metav1.GetOptions{}) if err == nil { log.Info().Msg(fmt.Sprintf("kubernetes secret %q already created - skipping", "kubefirst-console")) } else if strings.Contains(err.Error(), "not found") { - _, err = kcfg.Clientset.CoreV1().Secrets(namespace).Create(context.Background(), &v1.Secret{ + _, err = kcfg.Clientset.CoreV1().Secrets(namespace).Create(ctx, &v1.Secret{ Type: "kubernetes.io/tls", ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("%s-tls", "kubefirst-console"), @@ -485,8 +458,7 @@ Kubefirst console has already been deployed. To start over, run` + "`" + `kubefi }, }, metav1.CreateOptions{}) if err != nil { - progress.Error(fmt.Sprintf("error creating kubernetes secret for cert: %s", err)) - return + return fmt.Errorf("error creating kubernetes secret for cert: %w", err) } time.Sleep(5 * time.Second) log.Info().Msg("Created Kubernetes Secret for certificate") @@ -519,6 +491,8 @@ Kubefirst console has already been deployed. To start over, run` + "`" + `kubefi ### #### :tada: Success` + "`Your kubefirst platform provisioner is ready`") } + + return nil } // Down destroys a k3d cluster for Kubefirst console and API diff --git a/internal/provision/provision.go b/internal/provision/provision.go index 201b3e11..905b6fb4 100644 --- a/internal/provision/provision.go +++ b/internal/provision/provision.go @@ -7,6 +7,7 @@ See the LICENSE file for more details. package provision import ( + "context" "errors" "fmt" "os" @@ -56,7 +57,9 @@ func CreateMgmtClusterRequest(gitAuth apiTypes.GitAuth, cliFlags types.CliFlags, return nil } -func ManagementCluster(cliFlags *types.CliFlags, catalogApps []apiTypes.GitopsCatalogApp) error { +type Provisioner struct{} + +func (p *Provisioner) ProvisionManagementCluster(ctx context.Context, cliFlags *types.CliFlags, catalogApps []apiTypes.GitopsCatalogApp) error { clusterSetupComplete := viper.GetBool("kubefirst-checks.cluster-install-complete") if clusterSetupComplete { err := fmt.Errorf("this cluster install process has already completed successfully") @@ -101,7 +104,10 @@ func ManagementCluster(cliFlags *types.CliFlags, catalogApps []apiTypes.GitopsCa isK1Debug := strings.ToLower(os.Getenv("K1_LOCAL_DEBUG")) == "true" if !k3dClusterCreationComplete && !isK1Debug { - launch.Up(nil, true, cliFlags.UseTelemetry) + if err := launch.Up(ctx, nil, true, cliFlags.UseTelemetry); err != nil { + progress.Error(err.Error()) + return fmt.Errorf("failed to launch k3d cluster: %w", err) + } } err = utils.IsAppAvailable(fmt.Sprintf("%s/api/proxyHealth", cluster.GetConsoleIngressURL()), "kubefirst api")