diff --git a/Taskfile.yaml b/Taskfile.yaml index b76b8f0fa..cf58e0df5 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -22,3 +22,6 @@ tasks: - go test -v -run TestIsEKSDestroyedIntegration ./internal/aws || echo $? - go run . clean --destroy-buckets --destroy-confirm || echo $? - aws s3 sync $HOME/kubefirst/logs s3://$CICD_LOGS_BUCKET + integration-test-for-tls-localdev: + # GOFLAGS="-count=1" disable cache on tests + - GOFLAGS="-count=1" go test -v -run TestArgoCertificateIntegration ./internal/ssl diff --git a/cmd/createGithub.go b/cmd/createGithub.go index 92f0023a4..ceac3dcf9 100644 --- a/cmd/createGithub.go +++ b/cmd/createGithub.go @@ -99,13 +99,16 @@ var createGithubCmd = &cobra.Command{ progressPrinter.IncrementTracker("step-base", 1) gitopsRepo := fmt.Sprintf("git@github.com:%s/gitops.git", viper.GetString("github.owner")) - argocd.CreateInitialArgoCDRepository(gitopsRepo) - // clientset, err := k8s.GetClientSet(globalFlags.DryRun) - // if err != nil { - // log.Printf("Failed to get clientset for k8s : %s", err) - // return err - // } + botPrivateKey := viper.GetString("botprivatekey") + + argoCDConfig := argocd.GetArgoCDInitialCloudConfig(gitopsRepo, botPrivateKey) + + err = argocd.CreateInitialArgoCDRepository(config, argoCDConfig) + if err != nil { + return err + } + err = helm.InstallArgocd(globalFlags.DryRun) if err != nil { log.Println("Error installing argocd") diff --git a/cmd/destroyLocalGithub.go b/cmd/destroyLocalGithub.go index 254a8a9b1..265020c7c 100644 --- a/cmd/destroyLocalGithub.go +++ b/cmd/destroyLocalGithub.go @@ -30,7 +30,6 @@ var destroyLocalGithubCmd = &cobra.Command{ Short: "A brief description of your command", Long: `TDB`, RunE: func(cmd *cobra.Command, args []string) error { - fmt.Println("destroy-local-github called") config := configs.ReadConfig() destroyFlags, err := flagset.ProcessDestroyFlags(cmd) @@ -81,7 +80,6 @@ var destroyLocalGithubCmd = &cobra.Command{ log.Println("\nKUBEFIRST_GITHUB_AUTH_TOKEN set via OAuth") } - // todo: temporary code err = pkg.UpdateTerraformS3BackendForLocalhostAddress() if err != nil { return err @@ -92,33 +90,9 @@ var destroyLocalGithubCmd = &cobra.Command{ //* step 1.1 - open port-forward to state store and vault // todo --skip-git-terraform - // Vault port-forward - vaultStopChannel := make(chan struct{}, 1) - defer func() { - close(vaultStopChannel) - }() - k8s.OpenPortForwardPodWrapper( - pkg.VaultPodName, - pkg.VaultNamespace, - pkg.VaultPodPort, - pkg.VaultPodLocalPort, - vaultStopChannel, - ) - k8s.LoopUntilPodIsReady(globalFlags.DryRun) - minioStopChannel := make(chan struct{}, 1) - defer func() { - close(minioStopChannel) - }() - k8s.OpenPortForwardPodWrapper( - pkg.MinioPodName, - pkg.MinioNamespace, - pkg.MinioPodPort, - pkg.MinioPodLocalPort, - minioStopChannel, - ) - + // todo: remove it time.Sleep(20 * time.Second) //* step 1.3 - terraform destroy github diff --git a/cmd/local/connect.go b/cmd/local/connect.go index 683a2803f..cbdaeb6d8 100644 --- a/cmd/local/connect.go +++ b/cmd/local/connect.go @@ -2,14 +2,9 @@ package local import ( "fmt" - "github.com/kubefirst/kubefirst/internal/k8s" "github.com/kubefirst/kubefirst/internal/reports" "github.com/spf13/cobra" "log" - "os" - "os/signal" - "sync" - "syscall" ) func NewCommandConnect() *cobra.Command { @@ -27,69 +22,11 @@ func NewCommandConnect() *cobra.Command { func runConnect(cmd *cobra.Command, args []string) error { log.Println("opening Port Forward for console...") - // every port forward has its own closing control. when a channel is closed, the port forward is close. - vaultStopChannel := make(chan struct{}, 1) - argoStopChannel := make(chan struct{}, 1) - argoCDStopChannel := make(chan struct{}, 1) - chartmuseumStopChannel := make(chan struct{}, 1) - minioStopChannel := make(chan struct{}, 1) - minioConsoleStopChannel := make(chan struct{}, 1) - kubefirstConsoleStopChannel := make(chan struct{}, 1) - AtlantisStopChannel := make(chan struct{}, 1) - MetaphorFrontendDevelopmentStopChannel := make(chan struct{}, 1) - MetaphorGoDevelopmentStopChannel := make(chan struct{}, 1) - MetaphorDevelopmentStopChannel := make(chan struct{}, 1) - - // guarantee it will close the port forwards even on a process kill - defer func() { - close(vaultStopChannel) - close(argoStopChannel) - close(argoCDStopChannel) - close(chartmuseumStopChannel) - close(minioStopChannel) - close(minioConsoleStopChannel) - close(kubefirstConsoleStopChannel) - close(AtlantisStopChannel) - close(MetaphorFrontendDevelopmentStopChannel) - close(MetaphorGoDevelopmentStopChannel) - close(MetaphorDevelopmentStopChannel) - log.Println("leaving port-forward command, port forwards are now closed") - }() - - err := k8s.OpenPortForwardForLocal( - vaultStopChannel, - argoStopChannel, - argoCDStopChannel, - chartmuseumStopChannel, - minioStopChannel, - minioConsoleStopChannel, - kubefirstConsoleStopChannel, - AtlantisStopChannel, - MetaphorFrontendDevelopmentStopChannel, - MetaphorGoDevelopmentStopChannel, - MetaphorDevelopmentStopChannel, - ) - if err != nil { - return err - } - // style UI with local URLs fmt.Println(reports.StyleMessage(reports.LocalConnectSummary())) log.Println("Kubefirst port forward done") log.Println("hanging port forwards until ctrl+c is called") - // managing termination signal from the terminal - sigs := make(chan os.Signal, 1) - signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) - var wg sync.WaitGroup - wg.Add(1) - go func() { - <-sigs - wg.Done() - }() - - wg.Wait() - return nil } diff --git a/cmd/local/local.go b/cmd/local/local.go index 703573f44..382c7181a 100644 --- a/cmd/local/local.go +++ b/cmd/local/local.go @@ -1,7 +1,6 @@ package local import ( - "context" "fmt" "log" "sync" @@ -19,6 +18,7 @@ import ( "github.com/kubefirst/kubefirst/internal/k8s" "github.com/kubefirst/kubefirst/internal/metaphor" "github.com/kubefirst/kubefirst/internal/progressPrinter" + "github.com/kubefirst/kubefirst/internal/ssl" "github.com/kubefirst/kubefirst/internal/terraform" "github.com/kubefirst/kubefirst/internal/vault" "github.com/kubefirst/kubefirst/pkg" @@ -57,7 +57,11 @@ func NewCommand() *cobra.Command { // todo: get it from GH token , use it for console localCmd.Flags().StringVar(&adminEmail, "admin-email", "", "the email address for the administrator as well as for lets-encrypt certificate emails") localCmd.Flags().StringVar(&metaphorBranch, "metaphor-branch", "main", "metaphor application branch") - localCmd.Flags().StringVar(&gitOpsBranch, "gitops-branch", "main", "version/branch used on git clone") + // todo: UPDATE IT BEFORE MERGING + // todo: UPDATE IT BEFORE MERGING + // todo: UPDATE IT BEFORE MERGING + // todo: UPDATE IT BEFORE MERGING + localCmd.Flags().StringVar(&gitOpsBranch, "gitops-branch", "add-ingress-localhost", "version/branch used on git clone") localCmd.Flags().StringVar(&gitOpsRepo, "gitops-repo", "gitops", "") localCmd.Flags().StringVar(&templateTag, "template-tag", "", "when running a built version, and ldflag is set for the Kubefirst version, it will use this tag value to clone the templates (gitops and metaphor's)", @@ -94,8 +98,7 @@ func runLocal(cmd *cobra.Command, args []string) error { // todo need to add go channel to control when ngrok should close // and use context to handle closing the open goroutine/connection - go pkg.RunNgrok(context.TODO(), pkg.LocalAtlantisURL) - time.Sleep(5 * time.Second) + //go pkg.RunNgrok(context.TODO(), pkg.LocalAtlantisURL) if !viper.GetBool("kubefirst.done") { if viper.GetString("gitprovider") == "github" { @@ -155,6 +158,19 @@ func runLocal(cmd *cobra.Command, args []string) error { progressPrinter.IncrementTracker("step-base", 1) progressPrinter.IncrementTracker("step-github", 1) + // + // create local certs using MkCert tool + // + log.Println("installing CA from MkCert") + ssl.InstallCALocal(config) + log.Println("installing CA from MkCert done") + + log.Println("creating local certificates") + if err := ssl.CreateCertificatesForLocalWrapper(config); err != nil { + log.Println(err) + } + log.Println("creating local certificates done") + // add secrets to cluster // todo there is a secret condition in AddK3DSecrets to this not checked executionControl = viper.GetBool("kubernetes.vault.secret.created") @@ -172,9 +188,15 @@ func runLocal(cmd *cobra.Command, args []string) error { executionControl = viper.GetBool("argocd.initial-repository.created") if !executionControl { pkg.InformUser("create initial argocd repository", silentMode) - //Enterprise users need to be able to set the hostname for git. - gitopsRepo := fmt.Sprintf("git@%s:%s/gitops.git", viper.GetString("github.host"), viper.GetString("github.owner")) - err := argocd.CreateInitialArgoCDRepository(gitopsRepo) + // Enterprise users need to be able to set the hostname for git. + gitOpsRepo := fmt.Sprintf("git@%s:%s/gitops.git", viper.GetString("github.host"), viper.GetString("github.owner")) + + argoCDConfig := argocd.GetArgoCDInitialLocalConfig( + gitOpsRepo, + viper.GetString("botprivatekey"), + ) + + err := argocd.CreateInitialArgoCDRepository(config, argoCDConfig) if err != nil { log.Println("Error CreateInitialArgoCDRepository") return err @@ -215,20 +237,6 @@ func runLocal(cmd *cobra.Command, args []string) error { log.Println("already waited for argocd to be ready") } - // ArgoCD port-forward - argoCDStopChannel := make(chan struct{}, 1) - defer func() { - close(argoCDStopChannel) - }() - k8s.OpenPortForwardPodWrapper( - pkg.ArgoCDPodName, - pkg.ArgoCDNamespace, - pkg.ArgoCDPodPort, - pkg.ArgoCDPodLocalPort, - argoCDStopChannel, - ) - pkg.InformUser(fmt.Sprintf("port-forward to argocd is available at %s", viper.GetString("argocd.local.service")), silentMode) - // argocd pods are ready, get and set credentials executionControl = viper.GetBool("argocd.credentials.set") if !executionControl { @@ -264,36 +272,8 @@ func runLocal(cmd *cobra.Command, args []string) error { vault.WaitVaultToBeRunning(dryRun) } - // Vault port-forward - vaultStopChannel := make(chan struct{}, 1) - defer func() { - close(vaultStopChannel) - }() - k8s.OpenPortForwardPodWrapper( - pkg.VaultPodName, - pkg.VaultNamespace, - pkg.VaultPodPort, - pkg.VaultPodLocalPort, - vaultStopChannel, - ) - k8s.LoopUntilPodIsReady(dryRun) - minioStopChannel := make(chan struct{}, 1) - defer func() { - close(minioStopChannel) - }() - k8s.OpenPortForwardPodWrapper( - pkg.MinioPodName, - pkg.MinioNamespace, - pkg.MinioPodPort, - pkg.MinioPodLocalPort, - minioStopChannel, - ) - - // todo: can I remove it? - time.Sleep(20 * time.Second) - // configure vault with terraform executionControl = viper.GetBool("terraform.vault.apply.complete") if !executionControl { @@ -348,20 +328,8 @@ func runLocal(cmd *cobra.Command, args []string) error { progressPrinter.IncrementTracker("step-apps", 1) if !viper.GetBool("chartmuseum.host.resolved") { - // Chartmuseum port-forward - chartmuseumStopChannel := make(chan struct{}, 1) - defer func() { - close(chartmuseumStopChannel) - }() - k8s.OpenPortForwardPodWrapper( - pkg.ChartmuseumPodName, - pkg.ChartmuseumNamespace, - pkg.ChartmuseumPodPort, - pkg.ChartmuseumPodLocalPort, - chartmuseumStopChannel, - ) - pkg.AwaitHostNTimes("http://localhost:8181/health", 5, 5) + pkg.AwaitHostNTimes(pkg.ChartmuseumLocalURL+"/health", 5, 5) viper.Set("chartmuseum.host.resolved", true) viper.WriteConfig() } else { @@ -403,6 +371,7 @@ func runLocal(cmd *cobra.Command, args []string) error { // create a PR, atlantis will identify it's a Terraform change/file update and trigger atlantis plan // it's a goroutine since it can run in background + k8s.OpenAtlantisPortForward() var wg sync.WaitGroup wg.Add(1) go func() { diff --git a/cmd/local/postrun.go b/cmd/local/postrun.go index 4369bd78c..87daf4756 100644 --- a/cmd/local/postrun.go +++ b/cmd/local/postrun.go @@ -1,12 +1,14 @@ package local import ( + "fmt" "log" "os" "os/signal" "sync" "syscall" + "github.com/kubefirst/kubefirst/configs" "github.com/kubefirst/kubefirst/internal/k8s" "github.com/kubefirst/kubefirst/internal/reports" "github.com/kubefirst/kubefirst/pkg" @@ -20,55 +22,17 @@ func runPostLocal(cmd *cobra.Command, args []string) error { return nil } - // every port forward has its own closing control. when a channel is closed, the port forward is close. - vaultStopChannel := make(chan struct{}, 1) - argoStopChannel := make(chan struct{}, 1) - argoCDStopChannel := make(chan struct{}, 1) - chartmuseumStopChannel := make(chan struct{}, 1) - minioStopChannel := make(chan struct{}, 1) - minioConsoleStopChannel := make(chan struct{}, 1) - kubefirstConsoleStopChannel := make(chan struct{}, 1) - AtlantisStopChannel := make(chan struct{}, 1) - MetaphorFrontendDevelopmentStopChannel := make(chan struct{}, 1) - MetaphorGoDevelopmentStopChannel := make(chan struct{}, 1) - MetaphorDevelopmentStopChannel := make(chan struct{}, 1) + config := configs.ReadConfig() - // guarantee it will close the port forwards even on a process kill - defer func() { - close(vaultStopChannel) - close(argoStopChannel) - close(argoCDStopChannel) - close(chartmuseumStopChannel) - close(minioStopChannel) - close(minioConsoleStopChannel) - close(kubefirstConsoleStopChannel) - close(AtlantisStopChannel) - close(MetaphorFrontendDevelopmentStopChannel) - close(MetaphorGoDevelopmentStopChannel) - close(MetaphorDevelopmentStopChannel) - log.Println("leaving port-forward command, port forwards are now closed") - }() - - err := k8s.OpenPortForwardForLocal( - vaultStopChannel, - argoStopChannel, - argoCDStopChannel, - chartmuseumStopChannel, - minioStopChannel, - minioConsoleStopChannel, - kubefirstConsoleStopChannel, - AtlantisStopChannel, - MetaphorFrontendDevelopmentStopChannel, - MetaphorGoDevelopmentStopChannel, - MetaphorDevelopmentStopChannel, - ) - if err != nil { - return err + log.Println("storing certificates into application secrets namespace") + if err := k8s.CreateSecretsFromCertificatesForLocalWrapper(config); err != nil { + log.Println(err) } + log.Println("storing certificates into application secrets namespace done") log.Println("Starting the presentation of console and api for the handoff screen") - err = pkg.IsConsoleUIAvailable(pkg.KubefirstConsoleLocalURL) + err := pkg.IsConsoleUIAvailable(pkg.KubefirstConsoleLocalURL) if err != nil { log.Println(err) } @@ -79,7 +43,12 @@ func runPostLocal(cmd *cobra.Command, args []string) error { reports.LocalHandoffScreen(dryRun, silentMode) - log.Println("Kubefirst Console available at: http://localhost:9094", silentMode) + _, _, err = pkg.ExecShellReturnStrings(config.KubectlClientPath, "--kubeconfig", config.KubeConfigPath, "-n", "argocd", "apply", "-f", fmt.Sprintf("%s/gitops/ingressroute.yaml", config.K1FolderPath)) + if err != nil { + log.Printf("failed to create ingress route to argocd: %s", err) + } + + log.Printf("Kubefirst Console available at: %s", pkg.KubefirstConsoleLocalURLTLS) // managing termination signal from the terminal sigs := make(chan os.Signal, 1) diff --git a/cmd/local/prerun.go b/cmd/local/prerun.go index 74c786234..bb93e7148 100644 --- a/cmd/local/prerun.go +++ b/cmd/local/prerun.go @@ -1,7 +1,12 @@ package local import ( + "context" "fmt" + "log" + "net/http" + "time" + "github.com/dustin/go-humanize" "github.com/kubefirst/kubefirst/configs" "github.com/kubefirst/kubefirst/internal/addon" @@ -14,9 +19,6 @@ import ( "github.com/kubefirst/kubefirst/pkg" "github.com/spf13/cobra" "github.com/spf13/viper" - "log" - "net/http" - "time" ) func validateLocal(cmd *cobra.Command, args []string) error { @@ -77,6 +79,7 @@ func validateLocal(cmd *cobra.Command, args []string) error { viper.Set("argocd.local.service", pkg.ArgoCDLocalURL) viper.Set("vault.local.service", pkg.VaultLocalURL) + go pkg.RunNgrok(context.TODO(), pkg.LocalAtlantisURLTEMPORARY) // addons addon.AddAddon("github") @@ -118,7 +121,7 @@ func validateLocal(cmd *cobra.Command, args []string) error { ) } - progressPrinter.SetupProgress(6, silentMode) + progressPrinter.SetupProgress(4, silentMode) progressPrinter.AddTracker("step-0", "Process Parameters", 1) progressPrinter.AddTracker("step-download", pkg.DownloadDependencies, 3) diff --git a/configs/config.go b/configs/config.go index a02437e23..5a07e7d1e 100644 --- a/configs/config.go +++ b/configs/config.go @@ -40,12 +40,15 @@ type Config struct { NgrokClientPath string TerraformClientPath string K3dPath string + MkCertPath string + MkCertPemFilesPath string HostedZoneName string `env:"HOSTED_ZONE_NAME"` ClusterName string `env:"CLUSTER_NAME"` AwsRegion string `env:"AWS_REGION"` K3dVersion string + MkCertVersion string KubectlVersion string `env:"KUBECTL_VERSION" envDefault:"v1.20.0"` KubectlVersionM1 string TerraformVersion string @@ -122,16 +125,20 @@ func ReadConfig() *Config { config.HelmVersion = "v3.6.1" config.KubectlVersionM1 = "v1.21.14" config.K3dVersion = "v5.4.6" - config.InstallerEmail = "kubefirst-bot@kubefirst.com" + // certificates + config.MkCertPath = fmt.Sprintf("%s/tools/mkcert", config.K1FolderPath) + config.MkCertPemFilesPath = fmt.Sprintf("%s/tools/certs/", config.K1FolderPath) + config.MkCertVersion = "v1.4.4" + config.MetaphorTemplateURL = "https://github.com/kubefirst/metaphor-template.git" config.GitopsTemplateURL = "https://github.com/kubefirst/gitops-template-gh.git" // Local Configs URL - config.LocalArgoWorkflowsURL = "http://localhost:2746" - config.LocalVaultURL = "http://localhost:8200" - config.LocalArgoURL = "http://localhost:8080" - config.LocalAtlantisURL = "http://localhost:4141" + config.LocalArgoWorkflowsURL = "http://argo.localdev.me" + config.LocalVaultURL = "http://vault.localdev.me" + config.LocalArgoURL = "http://argocd.localdev.me" + config.LocalAtlantisURL = "http://atlantis.localdev.me" config.LocalChartmuseumURL = "http://localhost:8181" config.LocalMetaphorDev = "http://localhost:3000" diff --git a/internal/argocd/argocd.go b/internal/argocd/argocd.go index d2984cfbb..6a261ed07 100644 --- a/internal/argocd/argocd.go +++ b/internal/argocd/argocd.go @@ -23,8 +23,8 @@ import ( var ArgocdSecretClient coreV1Types.SecretInterface -// ConfigRepo - Sample config struct -type ConfigRepo struct { +// Config ArgoCD configuration +type Config struct { Configs struct { Repositories struct { RepoGitops struct { @@ -40,6 +40,24 @@ type ConfigRepo struct { } `yaml:"ssh-creds"` } `yaml:"credentialTemplates"` } `yaml:"configs"` + Server struct { + ExtraArgs []string `yaml:"extraArgs"` + Ingress struct { + Enabled string `yaml:"enabled"` + Annotations struct { + IngressKubernetesIoRewriteTarget string `yaml:"ingress.kubernetes.io/rewrite-target"` + IngressKubernetesIoBackendProtocol string `yaml:"ingress.kubernetes.io/backend-protocol"` + IngressKubernetesIoActionsSslRedirect string `yaml:"ingress.kubernetes.io/actions.ssl-redirect"` + } `yaml:"annotations"` + Hosts []string `yaml:"hosts"` + TLS []TLSConfig `yaml:"tls"` + } `yaml:"ingress"` + } `yaml:"server"` +} + +type TLSConfig struct { + Hosts []string `yaml:"hosts"` + SecretName string `yaml:"secretName"` } // SyncRetry tries to Sync ArgoCD as many times as requested by the attempts' parameter. On successful request, returns @@ -301,50 +319,43 @@ func ApplyRegistry(dryRun bool) error { func ApplyRegistryLocal(dryRun bool) error { config := configs.ReadConfig() - if viper.GetBool("argocd.registry.applied") { + if viper.GetBool("argocd.registry.applied") || dryRun { log.Println("skipped ApplyRegistryLocal - ") return nil } - if !dryRun { - _, _, err := pkg.ExecShellReturnStrings(config.KubectlClientPath, "--kubeconfig", config.KubeConfigPath, "-n", "argocd", "apply", "-f", fmt.Sprintf("%s/gitops/registry.yaml", config.K1FolderPath)) - if err != nil { - log.Printf("failed to execute localhost kubectl apply of registry-base: %s", err) - return err - } - time.Sleep(45 * time.Second) - viper.Set("argocd.registry.applied", true) - viper.WriteConfig() + _, _, err := pkg.ExecShellReturnStrings(config.KubectlClientPath, "--kubeconfig", config.KubeConfigPath, "-n", "argocd", "apply", "-f", fmt.Sprintf("%s/gitops/registry.yaml", config.K1FolderPath)) + if err != nil { + log.Printf("failed to execute localhost kubectl apply of registry-base: %s", err) + return err } + time.Sleep(45 * time.Second) + viper.Set("argocd.registry.applied", true) + viper.WriteConfig() + return nil } -// CreateInitialArgoCDRepository - Fill and create argocd-init-values.yaml for Github installs -func CreateInitialArgoCDRepository(githubURL string) error { - config := configs.ReadConfig() - - privateKey := viper.GetString("botprivatekey") - - argoConfig := ConfigRepo{} - argoConfig.Configs.Repositories.RepoGitops.URL = githubURL - argoConfig.Configs.Repositories.RepoGitops.Type = "git" - argoConfig.Configs.Repositories.RepoGitops.Name = "github-gitops" - argoConfig.Configs.CredentialTemplates.SSHCreds.URL = githubURL - argoConfig.Configs.CredentialTemplates.SSHCreds.SSHPrivateKey = privateKey +// CreateInitialArgoCDRepository - Fill and create `argocd-init-values.yaml` for GitHub installs. +// The `argocd-init-values.yaml` is applied during helm install. +func CreateInitialArgoCDRepository(config *configs.Config, argoConfig Config) error { argoCdRepoYaml, err := yaml2.Marshal(&argoConfig) if err != nil { - log.Printf("error: marshaling yaml for argo config %s", err) - return err + return fmt.Errorf("error: marshaling yaml for argo config %s", err) } err = os.WriteFile(fmt.Sprintf("%s/argocd-init-values.yaml", config.K1FolderPath), argoCdRepoYaml, 0644) if err != nil { - log.Printf("error: could not write argocd-init-values.yaml %s", err) - return err + return fmt.Errorf("error: could not write argocd-init-values.yaml %s", err) } viper.Set("argocd.initial-repository.created", true) - viper.WriteConfig() + + err = viper.WriteConfig() + if err != nil { + return err + } + return nil } @@ -436,3 +447,48 @@ func WaitArgoCDToBeReady(dryRun bool) { } } } + +// GetArgoCDInitialLocalConfig build a Config struct for local installation +func GetArgoCDInitialLocalConfig(gitOpsRepo string, botPrivateKey string) Config { + + argoCDConfig := Config{} + + // Repo config + argoCDConfig.Configs.Repositories.RepoGitops.URL = gitOpsRepo + argoCDConfig.Configs.Repositories.RepoGitops.Type = "git" + argoCDConfig.Configs.Repositories.RepoGitops.Name = "github-gitops" + + // Credentials + argoCDConfig.Configs.CredentialTemplates.SSHCreds.URL = gitOpsRepo + argoCDConfig.Configs.CredentialTemplates.SSHCreds.SSHPrivateKey = botPrivateKey + + // Ingress + argoCDConfig.Server.ExtraArgs = []string{"--insecure"} + argoCDConfig.Server.Ingress.Enabled = "true" + argoCDConfig.Server.Ingress.Annotations.IngressKubernetesIoRewriteTarget = "/" + argoCDConfig.Server.Ingress.Annotations.IngressKubernetesIoBackendProtocol = "HTTPS" + argoCDConfig.Server.Ingress.Annotations.IngressKubernetesIoActionsSslRedirect = `{"Type": "redirect", "RedirectConfig": { "Protocol": "HTTPS", "Port": "443", "StatusCode": "HTTP_301"}}` + argoCDConfig.Server.Ingress.Hosts = []string{"argocd.localdev.me"} + + argoCDConfig.Server.Ingress.TLS = []TLSConfig{ + { + Hosts: []string{"argocd.localdev.me"}, + SecretName: "argocd-tls", + }, + } + + return argoCDConfig +} + +// GetArgoCDInitialCloudConfig build a Config struct for Cloud installation +func GetArgoCDInitialCloudConfig(gitOpsRepo string, botPrivateKey string) Config { + + argoCDConfig := Config{} + argoCDConfig.Configs.Repositories.RepoGitops.URL = gitOpsRepo + argoCDConfig.Configs.Repositories.RepoGitops.Type = "git" + argoCDConfig.Configs.Repositories.RepoGitops.Name = "github-gitops" + argoCDConfig.Configs.CredentialTemplates.SSHCreds.URL = gitOpsRepo + argoCDConfig.Configs.CredentialTemplates.SSHCreds.SSHPrivateKey = botPrivateKey + + return argoCDConfig +} diff --git a/internal/downloadManager/download.go b/internal/downloadManager/download.go index 50c1afc2e..e014f82c2 100644 --- a/internal/downloadManager/download.go +++ b/internal/downloadManager/download.go @@ -27,23 +27,67 @@ func DownloadLocalTools(config *configs.Config) error { return err } - // https://github.com/k3d-io/k3d/releases/download/v5.4.6/k3d-linux-amd64 - k3dDownloadUrl := fmt.Sprintf( - "https://github.com/k3d-io/k3d/releases/download/%s/k3d-%s-%s", - config.K3dVersion, - config.LocalOs, - config.LocalArchitecture, - ) - err = downloadFile(config.K3dPath, k3dDownloadUrl) - if err != nil { - return err - } - err = os.Chmod(config.K3dPath, 0755) - if err != nil { + var wg sync.WaitGroup + errorChannel := make(chan error) + wgDone := make(chan bool) + wg.Add(2) + + go func() { + // https://github.com/k3d-io/k3d/releases/download/v5.4.6/k3d-linux-amd64 + k3dDownloadUrl := fmt.Sprintf( + "https://github.com/k3d-io/k3d/releases/download/%s/k3d-%s-%s", + config.K3dVersion, + config.LocalOs, + config.LocalArchitecture, + ) + err = downloadFile(config.K3dPath, k3dDownloadUrl) + if err != nil { + errorChannel <- err + return + } + err = os.Chmod(config.K3dPath, 0755) + if err != nil { + errorChannel <- err + return + } + wg.Done() + }() + + go func() { + // https://github.com/FiloSottile/mkcert/releases/download/v1.4.4/mkcert-v1.4.4-darwin-amd64 + mkCertDownloadUrl := fmt.Sprintf( + "https://github.com/FiloSottile/mkcert/releases/download/%s/mkcert-%s-%s-%s", + config.MkCertVersion, + config.MkCertVersion, + config.LocalOs, + config.LocalArchitecture, + ) + err = downloadFile(config.MkCertPath, mkCertDownloadUrl) + if err != nil { + errorChannel <- err + return + } + err = os.Chmod(config.MkCertPath, 0755) + if err != nil { + errorChannel <- err + return + } + wg.Done() + }() + + go func() { + wg.Wait() + close(wgDone) + }() + + select { + case <-wgDone: + log.Println("download finished") + return nil + case err = <-errorChannel: + close(errorChannel) return err } - - return nil } // DownloadTools prepare download folder, and download the required installation tools for download. The downloads diff --git a/internal/k3d/create.go b/internal/k3d/create.go index 04a9a6e88..7081e1b73 100644 --- a/internal/k3d/create.go +++ b/internal/k3d/create.go @@ -26,7 +26,9 @@ func CreateK3dCluster() error { "--agents-memory", "1024m", "--registry-create", "k3d-"+viper.GetString("cluster-name")+"-registry:63630", "--k3s-arg", `--kubelet-arg=eviction-hard=imagefs.available<1%,nodefs.available<1%@agent:*`, - "--k3s-arg", `--kubelet-arg=eviction-minimum-reclaim=imagefs.available=1%,nodefs.available=1%@agent:*`) + "--k3s-arg", `--kubelet-arg=eviction-minimum-reclaim=imagefs.available=1%,nodefs.available=1%@agent:*`, + "--port", "80:80@loadbalancer", + "--port", "443:443@loadbalancer") if err != nil { log.Println("error creating k3d cluster") return errors.New("error creating k3d cluster") diff --git a/internal/k8s/kubernetes.go b/internal/k8s/kubernetes.go index 5563d522b..d0c48dfdb 100644 --- a/internal/k8s/kubernetes.go +++ b/internal/k8s/kubernetes.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "io" + v1 "k8s.io/api/core/v1" "log" "net/http" "os" @@ -256,6 +257,7 @@ func WaitForNamespaceandPods(dryRun bool, config *configs.Config, namespace, pod } } +// todo: delete unused function func PatchSecret(k8sClient coreV1Types.SecretInterface, secretName, key, val string) { secret, err := k8sClient.Get(context.TODO(), secretName, metaV1.GetOptions{}) if err != nil { @@ -374,6 +376,7 @@ func (p *secret) patchSecret(k8sClient *kubernetes.Clientset, payload []PatchJso } // todo: deprecate the other functions +// this is used for local only (create/destroy) func LoopUntilPodIsReady(dryRun bool) { if dryRun { log.Printf("[#99] Dry-run mode, loopUntilPodIsReady skipped.") @@ -383,7 +386,7 @@ func LoopUntilPodIsReady(dryRun bool) { if len(token) == 0 { totalAttempts := 50 - url := "http://localhost:8200/v1/sys/health" + url := pkg.VaultLocalURL + "/v1/sys/health" for i := 0; i < totalAttempts; i++ { log.Printf("vault is not ready yet, sleeping and checking again, attempt (%d/%d)", i+1, totalAttempts) time.Sleep(10 * time.Second) @@ -458,3 +461,36 @@ func SetArgocdCreds(dryRun bool) { viper.Set("argocd.admin.username", "admin") viper.WriteConfig() } + +// CreateSecret creates a key for a specific namespace. +// +// namespace: namespace where secret will be created +// secretName: secret name to be stored at a Kubernetes object +// data: a single or collection of []bytes that will be stored as a Kubernetes secret +func CreateSecret(namespace string, secretName string, data map[string][]byte) error { + + // todo: method + clientset, err := GetClientSet(false) + if err != nil { + return err + } + + secret := v1.Secret{ + ObjectMeta: metaV1.ObjectMeta{ + Name: secretName, + Namespace: namespace, + }, + Data: data, + } + + _, err = clientset.CoreV1().Secrets(namespace).Create( + context.Background(), + &secret, + metaV1.CreateOptions{}, + ) + if err != nil { + return err + } + + return nil +} diff --git a/internal/k8s/wrappers.go b/internal/k8s/wrappers.go index 220e06c5a..ab6de5316 100644 --- a/internal/k8s/wrappers.go +++ b/internal/k8s/wrappers.go @@ -223,3 +223,39 @@ func OpenPortForwardServiceWrapper(serviceName string, namespace string, service //<-stopChannel return } + +func CreateSecretsFromCertificatesForLocalWrapper(config *configs.Config) error { + + for _, app := range pkg.GetCertificateAppList() { + + certFileName := config.MkCertPemFilesPath + app.AppName + "-cert.pem" // example: app-name-cert.pem + keyFileName := config.MkCertPemFilesPath + app.AppName + "-key.pem" // example: app-name-key.pem + + log.Printf("creating TLS k8s secret for %s...", app.AppName) + + // open file content + certContent, err := pkg.GetFileContent(certFileName) + if err != nil { + return err + } + + keyContent, err := pkg.GetFileContent(keyFileName) + if err != nil { + return err + } + + data := make(map[string][]byte) + data["tls.crt"] = certContent + data["tls.key"] = keyContent + + // save content into secret + err = CreateSecret(app.Namespace, app.AppName+"-tls", data) + if err != nil { + log.Println(err) + } + + log.Printf("creating TLS k8s secret for %s done", app.AppName) + } + + return nil +} diff --git a/internal/reports/section.go b/internal/reports/section.go index 23e8e3931..4f2bb012e 100644 --- a/internal/reports/section.go +++ b/internal/reports/section.go @@ -39,12 +39,12 @@ func PrintSectionRepoGitlab() []byte { return handOffData.Bytes() } -func PrintSectionOverview() []byte { +func PrintSectionOverview(kubefirstConsoleURL string) []byte { var handOffData bytes.Buffer handOffData.WriteString(strings.Repeat("-", 70)) handOffData.WriteString(fmt.Sprintf("\nCluster %q is up and running!:", viper.GetString("cluster-name"))) handOffData.WriteString("\nThis information is available at $HOME/.kubefirst ") - handOffData.WriteString("\n\nAccess the kubefirst-console from your browser at:\n http://localhost:9094\n") + handOffData.WriteString("\n\nAccess the kubefirst-console from your browser at:\n" + kubefirstConsoleURL + "\n") handOffData.WriteString("\nPress ESC to leave this screen and return to your shell.") return handOffData.Bytes() @@ -228,7 +228,7 @@ func HandoffScreen(dryRun bool, silentMode bool) { } var handOffData bytes.Buffer - handOffData.Write(PrintSectionOverview()) + handOffData.Write(PrintSectionOverview(pkg.KubefirstConsoleLocalURLCloud)) handOffData.Write(PrintSectionAws()) if viper.GetString("gitprovider") == "github" { handOffData.Write(PrintSectionRepoGithub()) @@ -248,7 +248,7 @@ func HandoffScreen(dryRun bool, silentMode bool) { } -// HandoffScreen - prints the handoff screen +// LocalHandoffScreen prints the handoff screen func LocalHandoffScreen(dryRun bool, silentMode bool) { // prepare data for the handoff report if dryRun { @@ -262,7 +262,7 @@ func LocalHandoffScreen(dryRun bool, silentMode bool) { } var handOffData bytes.Buffer - handOffData.Write(PrintSectionOverview()) + handOffData.Write(PrintSectionOverview(pkg.KubefirstConsoleLocalURLTLS)) handOffData.Write(PrintSectionRepoGithub()) handOffData.Write(PrintSectionVault()) handOffData.Write(PrintSectionArgoCD()) @@ -297,16 +297,14 @@ func LocalConnectSummary() string { localConnect.WriteString("\nKubefirst Local:\n") localConnect.WriteString(strings.Repeat("-", 70)) - localConnect.WriteString(fmt.Sprintf("\n\nKubefirst Console: %s\n", pkg.KubefirstConsoleLocalURL)) - localConnect.WriteString(fmt.Sprintf("Chart Museum: %s\n", pkg.ChartmuseumLocalURL)) - localConnect.WriteString(fmt.Sprintf("Argo: %s/workflows\n", pkg.ArgoLocalURL)) - localConnect.WriteString(fmt.Sprintf("ArgoCD: %s\n", pkg.ArgoCDLocalURL)) - localConnect.WriteString(fmt.Sprintf("Vault: %s\n", pkg.VaultLocalURL)) - localConnect.WriteString(fmt.Sprintf("Atlantis: %s\n", pkg.AtlantisLocalURL)) - localConnect.WriteString(fmt.Sprintf("Minio Console: %s\n", pkg.MinioConsoleURL)) - localConnect.WriteString(fmt.Sprintf("Metaphor Frontend: %s\n", pkg.MetaphorFrontendDevelopmentLocalURL)) - localConnect.WriteString(fmt.Sprintf("Metaphor Go: %s/app\n", pkg.MetaphorGoDevelopmentLocalURL)) - localConnect.WriteString(fmt.Sprintf("Metaphor: %s/app\n", pkg.MetaphorDevelopmentLocalURL)) + localConnect.WriteString(fmt.Sprintf("\n\nKubefirst Console UI: %s\n", pkg.KubefirstConsoleLocalURLTLS)) + localConnect.WriteString(fmt.Sprintf("ChartmuseumLocalURL: %s\n", pkg.ChartmuseumLocalURLTLS)) + localConnect.WriteString(fmt.Sprintf("Argo: %s\n", pkg.ArgoLocalURLTLS)) + localConnect.WriteString(fmt.Sprintf("ArgoCD: %s\n", pkg.ArgoCDLocalURLTLS)) + localConnect.WriteString(fmt.Sprintf("Vault: %s\n", pkg.VaultLocalURLTLS)) + localConnect.WriteString(fmt.Sprintf("Atlantis: %s\n", pkg.AtlantisLocalURLTLS)) + localConnect.WriteString(fmt.Sprintf("Minio: %s\n", pkg.MinioURLTLS)) + localConnect.WriteString(fmt.Sprintf("Minio Console: %s\n", pkg.MinioConsoleURLTLS)) return localConnect.String() } diff --git a/internal/ssl/ssl.go b/internal/ssl/ssl.go index ee216af4e..1bea69b60 100644 --- a/internal/ssl/ssl.go +++ b/internal/ssl/ssl.go @@ -241,3 +241,64 @@ func RestoreSSL(dryRun bool, includeMetaphorApps bool) error { viper.WriteConfig() return nil } + +func InstallCALocal(config *configs.Config) { + _, _, err := pkg.ExecShellReturnStrings(config.MkCertPath, "-install") + if err != nil { + log.Printf("failed to uninstall CA of mkCert: %s", err) + } +} + +// todo: make destroy call it +func UninstallCALocal(config *configs.Config) { + _, _, err := pkg.ExecShellReturnStrings(config.MkCertPath, "-uninstall") + if err != nil { + log.Printf("failed to uninstall CA of mkCert: %s", err) + } +} + +// CreateCertificatesForLocalWrapper groups a certification creation call into a wrapper. The provided application +// list is used to create SSL certificates for each of the provided application. +func CreateCertificatesForLocalWrapper(config *configs.Config) error { + + // create folder + // todo: check permission + err := os.Mkdir(config.MkCertPemFilesPath, 0755) + if err != nil && os.IsNotExist(err) { + return err + } + + for _, cert := range pkg.GetCertificateAppList() { + if err := createCertificateForLocal(config, cert); err != nil { + return err + } + } + + return nil +} + +// createCertificateForLocal issue certificates for a specific application. MkCert is the tool who is going to create +// the certificates, store them in files, and store the certificates in the host trusted store. +func createCertificateForLocal(config *configs.Config, app pkg.CertificateAppList) error { + + fullAppAddress := app.AppName + "." + pkg.LocalDNS // example: app-name.localdev.me + certFileName := config.MkCertPemFilesPath + app.AppName + "-cert.pem" // example: app-name-cert.pem + keyFileName := config.MkCertPemFilesPath + app.AppName + "-key.pem" // example: app-name-key.pem + + log.Printf("generating certificate %s.localdev.me on %s", app.AppName, config.MkCertPath) + + _, _, err := pkg.ExecShellReturnStrings( + config.MkCertPath, + "-cert-file", + certFileName, + "-key-file", + keyFileName, + pkg.LocalDNS, + fullAppAddress, + ) + if err != nil { + return fmt.Errorf("failed to generate %s SSL certificate using MkCert: %v", app.AppName, err) + } + + return nil +} diff --git a/internal/ssl/ssl_test.go b/internal/ssl/ssl_test.go new file mode 100644 index 000000000..bc42eb140 --- /dev/null +++ b/internal/ssl/ssl_test.go @@ -0,0 +1,69 @@ +package ssl + +import ( + "crypto/tls" + "testing" +) + +// todo: use URL constants for app addresses +func TestArgoCertificateIntegration(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test") + } + + const SSLPort = ":443" + + tests := []struct { + name string + address string + }{ + { + name: "argo", + address: "argo.localdev.me", + }, + { + name: "argocd", + address: "argocd.localdev.me", + }, + { + name: "atlantis", + address: "atlantis.localdev.me", + }, + { + name: "chartmuseum", + address: "chartmuseum.localdev.me", + }, + { + name: "vault", + address: "vault.localdev.me", + }, + { + name: "minio", + address: "minio.localdev.me", + }, + { + name: "minio-console", + address: "minio-console.localdev.me", + }, + { + name: "kubefirst", + address: "kubefirst-console.localdev.me", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + conn, err := tls.Dial("tcp", tt.address+SSLPort, nil) + if err != nil { + t.Logf("testing %s , address %s", tt.name, tt.address) + t.Error(err) + return + } + err = conn.VerifyHostname(tt.address) + if err != nil { + t.Error(err) + } + }) + } + +} diff --git a/pkg/constants.go b/pkg/constants.go index 6cb11f87e..a395cfe16 100644 --- a/pkg/constants.go +++ b/pkg/constants.go @@ -9,6 +9,7 @@ const ( GitHubHost = "github.com" LocalClusterName = "kubefirst" MinimumAvailableDiskSize = 10 // 10 GB + LocalDNS = "localdev.me" ) // SegmentIO constants @@ -37,7 +38,8 @@ const ( VaultNamespace = "vault" VaultPodPort = 8200 VaultPodLocalPort = 8200 - VaultLocalURL = "http://localhost:8200" + VaultLocalURL = "http://vault.localdev.me" + VaultLocalURLTLS = "https://vault.localdev.me" ) // Argo @@ -46,7 +48,7 @@ const ( ArgoNamespace = "argo" ArgoPodPort = 2746 ArgoPodLocalPort = 2746 - ArgoLocalURL = "http://localhost:2746" + ArgoLocalURLTLS = "https://argo.localdev.me" ) // ArgoCD @@ -55,7 +57,8 @@ const ( ArgoCDNamespace = "argocd" ArgoCDPodPort = 8080 ArgoCDPodLocalPort = 8080 - ArgoCDLocalURL = "http://localhost:8080" + ArgoCDLocalURL = "http://argocd.localdev.me" + ArgoCDLocalURLTLS = "https://argocd.localdev.me" ArgoCDLocalBaseURL = "https://localhost:8080/api/v1" ) @@ -65,7 +68,8 @@ const ( ChartmuseumNamespace = "chartmuseum" ChartmuseumPodPort = 8080 ChartmuseumPodLocalPort = 8181 - ChartmuseumLocalURL = "http://localhost:8181" + ChartmuseumLocalURL = "http://chartmuseum.localdev.me" + ChartmuseumLocalURLTLS = "https://chartmuseum.localdev.me" ) // Minio @@ -74,7 +78,8 @@ const ( MinioNamespace = "minio" MinioPodPort = 9000 MinioPodLocalPort = 9000 - MinioURL = "http://localhost:9000" + MinioURL = "http://minio.localdev.me" + MinioURLTLS = "https://minio.localdev.me" ) // Minio Console @@ -83,26 +88,31 @@ const ( MinioConsoleNamespace = "minio" MinioConsolePodPort = 9001 MinioConsolePodLocalPort = 9001 - MinioConsoleURL = "http://localhost:9001" + MinioConsoleURLTLS = "https://minio-console.localdev.me" ) // Kubefirst Console const ( - KubefirstConsolePodName = "kubefirst-console" - KubefirstConsoleNamespace = "kubefirst" - KubefirstConsolePodPort = 80 - KubefirstConsolePodLocalPort = 9094 - KubefirstConsoleLocalURL = "http://localhost:9094" + KubefirstConsolePodName = "kubefirst-console" + KubefirstConsoleNamespace = "kubefirst" + KubefirstConsolePodPort = 80 + KubefirstConsolePodLocalPort = 9094 + KubefirstConsoleLocalURLCloud = "http://localhost:9094" + KubefirstConsoleLocalURL = "http://kubefirst-console.localdev.me" + KubefirstConsoleLocalURLTLS = "https://kubefirst-console.localdev.me" ) // Atlantis const ( - AtlantisPodName = "atlantis-0" - AtlantisNamespace = "atlantis" - AtlantisPodPort = 4141 - AtlantisPodLocalPort = 4141 - AtlantisLocalURL = "http://localhost:4141" - LocalAtlantisURL = "localhost:4141" // todo: + AtlantisPodName = "atlantis-0" + AtlantisNamespace = "atlantis" + AtlantisPodPort = 4141 + AtlantisPodLocalPort = 4141 + AtlantisLocalURLTEST = "atlantis.localdev.me" + AtlantisLocalURL = "http://atlantis.localdev.me" + AtlantisLocalURLTLS = "https://atlantis.localdev.me" + LocalAtlantisURLTEMPORARY = "localhost:4141" // todo: + //LocalAtlantisURL = "atlantis.localdev.me" // todo: ) // MetaphorFrontendDevelopment diff --git a/pkg/helpers.go b/pkg/helpers.go index a87f3a838..18697cb7c 100644 --- a/pkg/helpers.go +++ b/pkg/helpers.go @@ -137,18 +137,7 @@ func DetokenizeDirectory(path string, fi os.FileInfo, err error) error { githubRepoOwner := viper.GetString("github.owner") githubOrg := viper.GetString("github.owner") githubUser := viper.GetString("github.user") - - //due to vouch proxy keep arm image in other repo than amd image we need a logic to solve this - //issue: https://github.com/vouch/vouch-proxy/issues/406 - //issue on k1: https://github.com/kubefirst/kubefirst/issues/724 - nodes_graviton := viper.GetBool("aws.nodes_graviton") - if nodes_graviton { - newContents = strings.Replace(newContents, "", "voucher/vouch-proxy", -1) - newContents = strings.Replace(newContents, "", "latest-arm", -1) - } else { - newContents = strings.Replace(newContents, "", "quay.io/vouch/vouch-proxy", -1) - newContents = strings.Replace(newContents, "", "0.36", -1) - } + ngrokUrl := viper.GetString("ngrok.url") githubToken := os.Getenv("KUBEFIRST_GITHUB_AUTH_TOKEN") @@ -159,6 +148,7 @@ func DetokenizeDirectory(path string, fi os.FileInfo, err error) error { newContents = strings.Replace(newContents, "", githubUser, -1) newContents = strings.Replace(newContents, "", githubToken, -1) newContents = strings.Replace(newContents, "", configs.K1Version, -1) + newContents = strings.Replace(newContents, "", ngrokUrl, -1) var repoPathHTTPS string var repoPathSSH string @@ -279,6 +269,7 @@ func DetokenizeDirectory(path string, fi os.FileInfo, err error) error { newContents = strings.Replace(newContents, "", config.LocalMetaphorProd, -1) newContents = strings.Replace(newContents, "", config.LocalMetaphorGoProd, -1) newContents = strings.Replace(newContents, "", config.LocalMetaphorFrontProd, -1) + newContents = strings.Replace(newContents, "", LocalDNS, -1) } else { newContents = strings.Replace(newContents, "", cloud, -1) newContents = strings.Replace(newContents, "", fmt.Sprintf("https://argo.%s", hostedZoneName), -1) @@ -491,7 +482,8 @@ func AwaitHostNTimes(url string, times int, gracePeriod time.Duration) { // file, newContent is the new content you want to replace. // // Example: -// err := replaceFileContent(vaultMainFile, "http://127.0.0.1:9000", "http://minio.minio.svc.cluster.local:9000") +// +// err := replaceFileContent(vaultMainFile, "http://127.0.0.1:9000", "http://minio.minio.svc.cluster.local:9000") func replaceFileContent(filPath string, oldContent string, newContent string) error { file, err := os.ReadFile(filPath) @@ -519,7 +511,7 @@ func UpdateTerraformS3BackendForK8sAddress() error { vaultMainFile := fmt.Sprintf("%s/gitops/terraform/vault/main.tf", config.K1FolderPath) if err := replaceFileContent( vaultMainFile, - "http://127.0.0.1:9000", + MinioURL, "http://minio.minio.svc.cluster.local:9000", ); err != nil { return err @@ -530,7 +522,7 @@ func UpdateTerraformS3BackendForK8sAddress() error { fullPathKubefirstGitHubFile := fmt.Sprintf("%s/gitops/terraform/users/kubefirst-github.tf", config.K1FolderPath) if err := replaceFileContent( fullPathKubefirstGitHubFile, - "http://127.0.0.1:9000", + MinioURL, "http://minio.minio.svc.cluster.local:9000", ); err != nil { return err @@ -540,7 +532,7 @@ func UpdateTerraformS3BackendForK8sAddress() error { fullPathRemoteBackendFile := fmt.Sprintf("%s/gitops/terraform/github/remote-backend.tf", config.K1FolderPath) if err := replaceFileContent( fullPathRemoteBackendFile, - "http://127.0.0.1:9000", + MinioURL, "http://minio.minio.svc.cluster.local:9000", ); err != nil { return err @@ -561,7 +553,7 @@ func UpdateTerraformS3BackendForLocalhostAddress() error { if err := replaceFileContent( vaultMainFile, "http://minio.minio.svc.cluster.local:9000", - "http://127.0.0.1:9000", + MinioURL, ); err != nil { return err } @@ -572,7 +564,7 @@ func UpdateTerraformS3BackendForLocalhostAddress() error { if err := replaceFileContent( fullPathKubefirstGitHubFile, "http://minio.minio.svc.cluster.local:9000", - "http://127.0.0.1:9000", + MinioURL, ); err != nil { return err } @@ -582,9 +574,9 @@ func UpdateTerraformS3BackendForLocalhostAddress() error { if err := replaceFileContent( fullPathRemoteBackendFile, "http://minio.minio.svc.cluster.local:9000", - "http://127.0.0.1:9000", + MinioURL, ); err != nil { - return err + log.Println(err) } } @@ -664,3 +656,64 @@ func OpenLogFile(path string) (*os.File, error) { } return logFile, nil } + +// GetFileContent receives a file path, and return its content. +func GetFileContent(filePath string) ([]byte, error) { + + // check if file exists + if _, err := os.Stat(filePath); err != nil && os.IsNotExist(err) { + return nil, err + } + + byteData, err := os.ReadFile(filePath) + if err != nil { + return nil, err + } + + return byteData, nil +} + +type CertificateAppList struct { + Namespace string + AppName string +} + +func GetCertificateAppList() []CertificateAppList { + + certificateAppList := []CertificateAppList{ + { + Namespace: "argo", + AppName: "argo", + }, + { + Namespace: "argocd", + AppName: "argocd", + }, + { + Namespace: "atlantis", + AppName: "atlantis", + }, + { + Namespace: "chartmuseum", + AppName: "chartmuseum", + }, + { + Namespace: "vault", + AppName: "vault", + }, + { + Namespace: "minio", + AppName: "minio", + }, + { + Namespace: "minio", + AppName: "minio-console", + }, + { + Namespace: "kubefirst", + AppName: "kubefirst-console", + }, + } + + return certificateAppList +} diff --git a/pkg/helpers_test.go b/pkg/helpers_test.go index 3dfbea763..3adf1e5a5 100644 --- a/pkg/helpers_test.go +++ b/pkg/helpers_test.go @@ -159,3 +159,75 @@ func TestValidateK1Folder(t *testing.T) { }) } } + +func TestGetFileContent(t *testing.T) { + + file, err := os.CreateTemp("", "testing.txt") + if err != nil { + t.Error(err) + } + defer func(name string) { + err := os.Remove(name) + if err != nil { + t.Error(err) + } + }(file.Name()) + + fileWithContent, err := os.CreateTemp("", "testing-with-content") + if err != nil { + t.Error(err) + } + _, err = fileWithContent.Write([]byte("some-content")) + if err != nil { + t.Error(err) + } + err = fileWithContent.Close() + if err != nil { + t.Error(err) + } + + defer func(name string) { + err := os.Remove(name) + if err != nil { + t.Error(err) + } + }(fileWithContent.Name()) + + tests := []struct { + name string + filePath string + want []byte + wantErr bool + }{ + { + name: "file doesn't exist", + filePath: "non-existent-file.ext", + want: nil, + wantErr: true, + }, + { + name: "file with no content, returns no content", + filePath: file.Name(), + want: []byte(""), + wantErr: false, + }, + { + name: "file with content, returns its content", + filePath: fileWithContent.Name(), + want: []byte("some-content"), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := GetFileContent(tt.filePath) + if (err != nil) != tt.wantErr { + t.Errorf("GetFileContent() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("GetFileContent() got = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/keys.go b/pkg/keys.go index 968513b88..0741a47f8 100644 --- a/pkg/keys.go +++ b/pkg/keys.go @@ -6,13 +6,13 @@ import ( "crypto/x509" "encoding/pem" "fmt" + "github.com/kubefirst/kubefirst/configs" "log" "os" "strings" "github.com/caarlos0/sshmarshal" goGitSsh "github.com/go-git/go-git/v5/plumbing/transport/ssh" - "github.com/kubefirst/kubefirst/configs" "github.com/spf13/viper" "golang.org/x/crypto/ed25519" "golang.org/x/crypto/ssh" @@ -20,7 +20,6 @@ import ( func CreateSshKeyPair() { - config := configs.ReadConfig() publicKey := viper.GetString("botpublickey") // generate GitLab keys @@ -58,26 +57,32 @@ func CreateSshKeyPair() { } publicKey = viper.GetString("botpublickey") - privateKey := viper.GetString("botprivatekey") - var argocdInitValuesYaml = []byte(fmt.Sprintf(` + // todo: break it into smaller function + if viper.GetString("gitprovider") != CloudK3d { + + config := configs.ReadConfig() + privateKey := viper.GetString("botprivatekey") + + var argocdInitValuesYaml = []byte(fmt.Sprintf(` configs: - repositories: - soft-serve-gitops: - url: ssh://soft-serve.soft-serve.svc.cluster.local:22/gitops - insecure: 'true' - type: gitClient - name: soft-serve-gitops - credentialTemplates: - ssh-creds: - url: ssh://soft-serve.soft-serve.svc.cluster.local:22 - sshPrivateKey: | - %s + repositories: + soft-serve-gitops: + url: ssh://soft-serve.soft-serve.svc.cluster.local:22/gitops + insecure: 'true' + type: gitClient + name: soft-serve-gitops + credentialTemplates: + ssh-creds: + url: ssh://soft-serve.soft-serve.svc.cluster.local:22 + sshPrivateKey: | + %s `, strings.ReplaceAll(privateKey, "\n", "\n "))) - err := os.WriteFile(fmt.Sprintf("%s/argocd-init-values.yaml", config.K1FolderPath), argocdInitValuesYaml, 0644) - if err != nil { - log.Panicf("error: could not write argocd-init-values.yaml %s", err) + err := os.WriteFile(fmt.Sprintf("%s/argocd-init-values.yaml", config.K1FolderPath), argocdInitValuesYaml, 0644) + if err != nil { + log.Panicf("error: could not write argocd-init-values.yaml %s", err) + } } } diff --git a/pkg/ngrok.go b/pkg/ngrok.go index e85bac806..5bf832426 100644 --- a/pkg/ngrok.go +++ b/pkg/ngrok.go @@ -14,6 +14,15 @@ import ( ) func RunNgrok(ctx context.Context, dest string) { + + // todo: use it when atlantis port forward missing port in address issued is fixed + //atlantisURL, err := url.Parse(dest) + //if err != nil { + // log.Println(err) + //} + // + //dest = atlantisURL.Host + ":80" + tunnel, err := ngrok.StartTunnel(ctx, config.HTTPEndpoint(), ngrok.WithAuthtokenFromEnv()) if err != nil { log.Println(err) @@ -21,6 +30,7 @@ func RunNgrok(ctx context.Context, dest string) { fmt.Println("tunnel created: ", tunnel.URL()) viper.Set("github.atlantis.webhook.url", tunnel.URL()+"/events") + viper.Set("ngrok.url", tunnel.URL()) viper.WriteConfig() for { @@ -32,6 +42,7 @@ func RunNgrok(ctx context.Context, dest string) { log.Println("accepted connection from", conn.RemoteAddr()) go func() { + err := handleConn(ctx, dest, conn) log.Println("connection closed:", err) }()