fix pre-commit and cleanup
This commit is contained in:
@@ -1,132 +1,132 @@
|
||||
package fluxhandler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/truecharts/public/clustertool/pkg/helper"
|
||||
"github.com/truecharts/public/clustertool/pkg/kubectlcmds"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/truecharts/public/clustertool/pkg/helper"
|
||||
"github.com/truecharts/public/clustertool/pkg/kubectlcmds"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Configure zerolog to output to stdout with a timestamp and log level
|
||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stdout}).With().Timestamp().Logger()
|
||||
// Configure zerolog to output to stdout with a timestamp and log level
|
||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stdout}).With().Timestamp().Logger()
|
||||
}
|
||||
|
||||
// FluxBootstrap initializes the FluxCD bootstrapping process if GITHUB_REPOSITORY is set in TalEnv.
|
||||
func FluxBootstrap(ctx context.Context) {
|
||||
if helper.TalEnv["GITHUB_REPOSITORY"] != "" {
|
||||
log.Info().Msg("GITHUB_Repository for Flux configured.")
|
||||
if helper.GetYesOrNo("Do you want to bootstrap FluxCD as well? (yes/no) [y/n]: ") {
|
||||
if err := bootstrapFluxCD(ctx); err != nil {
|
||||
log.Fatal().Err(err).Msg("Error during FluxCD bootstrap")
|
||||
if helper.GetYesOrNo("Do you want to retry? (yes/no) [y/n]: ") {
|
||||
if err2 := bootstrapFluxCD(ctx); err2 != nil {
|
||||
log.Fatal().Err(err2).Msg("Error during FluxCD bootstrap")
|
||||
}
|
||||
}
|
||||
}
|
||||
log.Info().Msg("FluxCD Bootstrapped successfully")
|
||||
}
|
||||
}
|
||||
if helper.TalEnv["GITHUB_REPOSITORY"] != "" {
|
||||
log.Info().Msg("GITHUB_Repository for Flux configured.")
|
||||
if helper.GetYesOrNo("Do you want to bootstrap FluxCD as well? (yes/no) [y/n]: ") {
|
||||
if err := bootstrapFluxCD(ctx); err != nil {
|
||||
log.Fatal().Err(err).Msg("Error during FluxCD bootstrap")
|
||||
if helper.GetYesOrNo("Do you want to retry? (yes/no) [y/n]: ") {
|
||||
if err2 := bootstrapFluxCD(ctx); err2 != nil {
|
||||
log.Fatal().Err(err2).Msg("Error during FluxCD bootstrap")
|
||||
}
|
||||
}
|
||||
}
|
||||
log.Info().Msg("FluxCD Bootstrapped successfully")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bootstrapFluxCD handles the entire FluxCD bootstrapping process.
|
||||
func bootstrapFluxCD(ctx context.Context) error {
|
||||
if err := checkGitRepo(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := checkGitRepo(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fluxPath := filepath.Join(helper.ClusterPath, "kubernetes", "flux-system", "flux")
|
||||
if err := setupFluxCD(ctx, fluxPath); err != nil {
|
||||
return err
|
||||
}
|
||||
fluxPath := filepath.Join(helper.ClusterPath, "kubernetes", "flux-system", "flux")
|
||||
if err := setupFluxCD(ctx, fluxPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
reposFilePath := "repositories"
|
||||
if err := setupRepositories(ctx, reposFilePath); err != nil {
|
||||
return err
|
||||
}
|
||||
reposFilePath := "repositories"
|
||||
if err := setupRepositories(ctx, reposFilePath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clusterEntryFile := filepath.Join(helper.ClusterPath, "kubernetes", "flux-entry.yaml")
|
||||
if err := kubectlcmds.KubectlApply(ctx, clusterEntryFile); err != nil {
|
||||
log.Error().Err(err).Str("path", clusterEntryFile).Msg("Error applying Kubernetes flux-entry manifest")
|
||||
return err
|
||||
}
|
||||
clusterEntryFile := filepath.Join(helper.ClusterPath, "kubernetes", "flux-entry.yaml")
|
||||
if err := kubectlcmds.KubectlApply(ctx, clusterEntryFile); err != nil {
|
||||
log.Error().Err(err).Str("path", clusterEntryFile).Msg("Error applying Kubernetes flux-entry manifest")
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkGitRepo verifies if the current directory is a valid Git repository.
|
||||
func checkGitRepo() error {
|
||||
isRepo, err := helper.IsCurrentDirGitRepo()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Error checking Git repository")
|
||||
return err
|
||||
}
|
||||
if !isRepo {
|
||||
errMsg := "Bootstrap: ERROR The current directory is not a Git repository. Cannot bootstrap fluxcd"
|
||||
log.Error().Msg(errMsg)
|
||||
return err
|
||||
}
|
||||
log.Info().Msg("Bootstrap: The current directory is a valid GIT repository, continuing...")
|
||||
return nil
|
||||
isRepo, err := helper.IsCurrentDirGitRepo()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Error checking Git repository")
|
||||
return err
|
||||
}
|
||||
if !isRepo {
|
||||
errMsg := "Bootstrap: ERROR The current directory is not a Git repository. Cannot bootstrap fluxcd"
|
||||
log.Error().Msg(errMsg)
|
||||
return err
|
||||
}
|
||||
log.Info().Msg("Bootstrap: The current directory is a valid GIT repository, continuing...")
|
||||
return nil
|
||||
}
|
||||
|
||||
// setupFluxCD handles the setup of FluxCD manifests.
|
||||
func setupFluxCD(ctx context.Context, fluxPath string) error {
|
||||
bootstrapFile := "bootstrap.yaml.ct"
|
||||
kustomFile := "kustomization.yaml"
|
||||
tmpFile := "placeholder"
|
||||
bootstrapFile := "bootstrap.yaml.ct"
|
||||
kustomFile := "kustomization.yaml"
|
||||
tmpFile := "placeholder"
|
||||
|
||||
log.Info().Msg("Bootstrap: Loading fluxcd onto the cluster...")
|
||||
log.Info().Msg("Bootstrap: Loading fluxcd onto the cluster...")
|
||||
|
||||
// Rename files for kustomize application
|
||||
if err := os.Rename(filepath.Join(fluxPath, kustomFile), filepath.Join(fluxPath, tmpFile)); err != nil {
|
||||
log.Error().Err(err).Msg("Error renaming kustomization file")
|
||||
return err
|
||||
}
|
||||
if err := os.Rename(filepath.Join(fluxPath, bootstrapFile), filepath.Join(fluxPath, kustomFile)); err != nil {
|
||||
log.Error().Err(err).Msg("Error renaming bootstrap file")
|
||||
return err
|
||||
}
|
||||
// Rename files for kustomize application
|
||||
if err := os.Rename(filepath.Join(fluxPath, kustomFile), filepath.Join(fluxPath, tmpFile)); err != nil {
|
||||
log.Error().Err(err).Msg("Error renaming kustomization file")
|
||||
return err
|
||||
}
|
||||
if err := os.Rename(filepath.Join(fluxPath, bootstrapFile), filepath.Join(fluxPath, kustomFile)); err != nil {
|
||||
log.Error().Err(err).Msg("Error renaming bootstrap file")
|
||||
return err
|
||||
}
|
||||
|
||||
if err := kubectlcmds.KubectlApplyKustomize(ctx, fluxPath); err != nil {
|
||||
log.Error().Err(err).Str("path", fluxPath).Msg("Error applying FluxCD manifest")
|
||||
return err
|
||||
}
|
||||
if err := kubectlcmds.KubectlApplyKustomize(ctx, fluxPath); err != nil {
|
||||
log.Error().Err(err).Str("path", fluxPath).Msg("Error applying FluxCD manifest")
|
||||
return err
|
||||
}
|
||||
|
||||
// Revert file renames
|
||||
if err := os.Rename(filepath.Join(fluxPath, kustomFile), filepath.Join(fluxPath, bootstrapFile)); err != nil {
|
||||
log.Error().Err(err).Msg("Error renaming kustomization file back")
|
||||
return err
|
||||
}
|
||||
if err := os.Rename(filepath.Join(fluxPath, tmpFile), filepath.Join(fluxPath, kustomFile)); err != nil {
|
||||
log.Error().Err(err).Msg("Error renaming placeholder file back")
|
||||
return err
|
||||
}
|
||||
// Revert file renames
|
||||
if err := os.Rename(filepath.Join(fluxPath, kustomFile), filepath.Join(fluxPath, bootstrapFile)); err != nil {
|
||||
log.Error().Err(err).Msg("Error renaming kustomization file back")
|
||||
return err
|
||||
}
|
||||
if err := os.Rename(filepath.Join(fluxPath, tmpFile), filepath.Join(fluxPath, kustomFile)); err != nil {
|
||||
log.Error().Err(err).Msg("Error renaming placeholder file back")
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// setupRepositories handles the setup of repository manifests.
|
||||
func setupRepositories(ctx context.Context, reposFilePath string) error {
|
||||
log.Info().Msg("Bootstrap: Loading git-repo manifests onto the cluster...")
|
||||
log.Info().Msg("Bootstrap: Loading git-repo manifests onto the cluster...")
|
||||
|
||||
gitRepoFile := filepath.Join(reposFilePath, "git", "this-repo.yaml")
|
||||
if err := kubectlcmds.KubectlApply(ctx, gitRepoFile); err != nil {
|
||||
log.Error().Err(err).Str("path", reposFilePath).Msg("Error applying repositories manifest")
|
||||
return err
|
||||
}
|
||||
gitRepoFile := filepath.Join(reposFilePath, "git", "this-repo.yaml")
|
||||
if err := kubectlcmds.KubectlApply(ctx, gitRepoFile); err != nil {
|
||||
log.Error().Err(err).Str("path", reposFilePath).Msg("Error applying repositories manifest")
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info().Msg("Bootstrap: Loading repositories flux-entry onto the cluster...")
|
||||
reposEntryFile := filepath.Join(reposFilePath, "flux-entry.yaml")
|
||||
if err := kubectlcmds.KubectlApply(ctx, reposEntryFile); err != nil {
|
||||
log.Error().Err(err).Str("path", reposEntryFile).Msg("Error applying repositories flux-entry manifest")
|
||||
return err
|
||||
}
|
||||
log.Info().Msg("Bootstrap: Loading repositories flux-entry onto the cluster...")
|
||||
reposEntryFile := filepath.Join(reposFilePath, "flux-entry.yaml")
|
||||
if err := kubectlcmds.KubectlApply(ctx, reposEntryFile); err != nil {
|
||||
log.Error().Err(err).Str("path", reposEntryFile).Msg("Error applying repositories flux-entry manifest")
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil
|
||||
}
|
||||
|
||||
+430
-430
@@ -1,565 +1,565 @@
|
||||
package fluxhandler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/truecharts/public/clustertool/pkg/helper"
|
||||
"helm.sh/helm/v3/pkg/action"
|
||||
"helm.sh/helm/v3/pkg/chart/loader"
|
||||
"helm.sh/helm/v3/pkg/cli"
|
||||
"helm.sh/helm/v3/pkg/cli/values"
|
||||
"helm.sh/helm/v3/pkg/getter"
|
||||
"helm.sh/helm/v3/pkg/registry"
|
||||
"helm.sh/helm/v3/pkg/release"
|
||||
"helm.sh/helm/v3/pkg/repo"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/truecharts/public/clustertool/pkg/helper"
|
||||
"helm.sh/helm/v3/pkg/action"
|
||||
"helm.sh/helm/v3/pkg/chart/loader"
|
||||
"helm.sh/helm/v3/pkg/cli"
|
||||
"helm.sh/helm/v3/pkg/cli/values"
|
||||
"helm.sh/helm/v3/pkg/getter"
|
||||
"helm.sh/helm/v3/pkg/registry"
|
||||
"helm.sh/helm/v3/pkg/release"
|
||||
"helm.sh/helm/v3/pkg/repo"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
func newDefaultRegistryClient(plainHTTP bool, settings *cli.EnvSettings) (*registry.Client, error) {
|
||||
opts := []registry.ClientOption{
|
||||
registry.ClientOptDebug(settings.Debug),
|
||||
registry.ClientOptEnableCache(true),
|
||||
registry.ClientOptWriter(os.Stdout),
|
||||
registry.ClientOptCredentialsFile(settings.RegistryConfig),
|
||||
}
|
||||
if plainHTTP {
|
||||
opts = append(opts, registry.ClientOptPlainHTTP())
|
||||
}
|
||||
opts := []registry.ClientOption{
|
||||
registry.ClientOptDebug(settings.Debug),
|
||||
registry.ClientOptEnableCache(true),
|
||||
registry.ClientOptWriter(os.Stdout),
|
||||
registry.ClientOptCredentialsFile(settings.RegistryConfig),
|
||||
}
|
||||
if plainHTTP {
|
||||
opts = append(opts, registry.ClientOptPlainHTTP())
|
||||
}
|
||||
|
||||
// Create a new registry client
|
||||
registryClient, err := registry.NewClient(opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return registryClient, nil
|
||||
// Create a new registry client
|
||||
registryClient, err := registry.NewClient(opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return registryClient, nil
|
||||
}
|
||||
|
||||
// HelmPull downloads a Helm chart from a repository
|
||||
func HelmPull(repo string, name string, version string, dest string, silent bool) error {
|
||||
settings := cli.New()
|
||||
actionConfig := new(action.Configuration)
|
||||
settings := cli.New()
|
||||
actionConfig := new(action.Configuration)
|
||||
|
||||
// Define logger based on the silent parameter
|
||||
var logger func(string, ...interface{})
|
||||
if silent {
|
||||
logger = noOpLog
|
||||
} else {
|
||||
logger = log.Printf
|
||||
}
|
||||
// Define logger based on the silent parameter
|
||||
var logger func(string, ...interface{})
|
||||
if silent {
|
||||
logger = noOpLog
|
||||
} else {
|
||||
logger = log.Printf
|
||||
}
|
||||
|
||||
// Initialize actionConfig with the appropriate logger
|
||||
if err := actionConfig.Init(settings.RESTClientGetter(), "", os.Getenv("HELM_DRIVER"), logger); err != nil {
|
||||
return fmt.Errorf("failed to initialize Helm action config: %w", err)
|
||||
}
|
||||
// Initialize actionConfig with the appropriate logger
|
||||
if err := actionConfig.Init(settings.RESTClientGetter(), "", os.Getenv("HELM_DRIVER"), logger); err != nil {
|
||||
return fmt.Errorf("failed to initialize Helm action config: %w", err)
|
||||
}
|
||||
|
||||
registryClient, err := newDefaultRegistryClient(false, settings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
actionConfig.RegistryClient = registryClient
|
||||
registryClient, err := newDefaultRegistryClient(false, settings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
actionConfig.RegistryClient = registryClient
|
||||
|
||||
client := action.NewPullWithOpts(action.WithConfig(actionConfig))
|
||||
client.Settings = settings
|
||||
client.RepoURL = repo
|
||||
client.Version = version
|
||||
client.DestDir = filepath.Join(helper.HelmCache, dest)
|
||||
client := action.NewPullWithOpts(action.WithConfig(actionConfig))
|
||||
client.Settings = settings
|
||||
client.RepoURL = repo
|
||||
client.Version = version
|
||||
client.DestDir = filepath.Join(helper.HelmCache, dest)
|
||||
|
||||
// Create cache directory
|
||||
if err := os.MkdirAll(client.DestDir, os.ModePerm); err != nil {
|
||||
return fmt.Errorf("❌ Failed to create cache directory: %s", err)
|
||||
}
|
||||
// Create cache directory
|
||||
if err := os.MkdirAll(client.DestDir, os.ModePerm); err != nil {
|
||||
return fmt.Errorf("❌ Failed to create cache directory: %s", err)
|
||||
}
|
||||
|
||||
switch repo {
|
||||
case "https://charts.truecharts.org",
|
||||
"https://library-charts.truecharts.org",
|
||||
"https://deps.truecharts.org":
|
||||
client.Keyring = helper.GpgDir + "/pubring.gpg"
|
||||
client.Verify = true
|
||||
case "https://charts.jetstack.io":
|
||||
client.Keyring = helper.GpgDir + "/certman.gpg"
|
||||
client.Verify = true
|
||||
default:
|
||||
// Do nothing for other repositories
|
||||
}
|
||||
switch repo {
|
||||
case "https://charts.truecharts.org",
|
||||
"https://library-charts.truecharts.org",
|
||||
"https://deps.truecharts.org":
|
||||
client.Keyring = helper.GpgDir + "/pubring.gpg"
|
||||
client.Verify = true
|
||||
case "https://charts.jetstack.io":
|
||||
client.Keyring = helper.GpgDir + "/certman.gpg"
|
||||
client.Verify = true
|
||||
default:
|
||||
// Do nothing for other repositories
|
||||
}
|
||||
|
||||
link := ""
|
||||
if strings.HasPrefix(repo, "http") {
|
||||
link = name
|
||||
repoName := cleanRepoURL(repo)
|
||||
updateHelmRepo(repoName, repo, silent)
|
||||
repo = repoName
|
||||
} else {
|
||||
link = repo + "/" + name
|
||||
client.RepoURL = ""
|
||||
}
|
||||
link := ""
|
||||
if strings.HasPrefix(repo, "http") {
|
||||
link = name
|
||||
repoName := cleanRepoURL(repo)
|
||||
updateHelmRepo(repoName, repo, silent)
|
||||
repo = repoName
|
||||
} else {
|
||||
link = repo + "/" + name
|
||||
client.RepoURL = ""
|
||||
}
|
||||
|
||||
output, err := client.Run(link)
|
||||
output, err := client.Run(link)
|
||||
|
||||
if err != nil {
|
||||
os.Remove(path.Join(dest, fmt.Sprintf("%s-%s.tgz", name, version)))
|
||||
return err
|
||||
}
|
||||
if !silent {
|
||||
log.Info().Msg("✅ Dependency Downloaded!")
|
||||
}
|
||||
if client.Keyring != "" && client.Keyring != "nil" {
|
||||
if !silent {
|
||||
log.Info().Msg("✅ Dependency Verified")
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
os.Remove(path.Join(dest, fmt.Sprintf("%s-%s.tgz", name, version)))
|
||||
return err
|
||||
}
|
||||
if !silent {
|
||||
log.Info().Msg("✅ Dependency Downloaded!")
|
||||
}
|
||||
if client.Keyring != "" && client.Keyring != "nil" {
|
||||
if !silent {
|
||||
log.Info().Msg("✅ Dependency Verified")
|
||||
}
|
||||
}
|
||||
|
||||
if output != "" {
|
||||
log.Info().Msgf("☸ Helm output: %s", output)
|
||||
}
|
||||
return nil
|
||||
if output != "" {
|
||||
log.Info().Msgf("☸ Helm output: %s", output)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func noOpLog(format string, v ...interface{}) {}
|
||||
|
||||
// HelmInstall installs a Helm chart with provided parameters
|
||||
func HelmInstall(repoURL string, chartName string, releaseName string, namespace string, valuesFile string, version string, dryRun bool, wait bool, silent bool) error {
|
||||
if dryRun {
|
||||
log.Info().Msg("dryRun not possible...")
|
||||
return nil
|
||||
}
|
||||
if dryRun {
|
||||
log.Info().Msg("dryRun not possible...")
|
||||
return nil
|
||||
}
|
||||
|
||||
settings := cli.New()
|
||||
actionConfig := new(action.Configuration)
|
||||
settings := cli.New()
|
||||
actionConfig := new(action.Configuration)
|
||||
|
||||
settings.SetNamespace(namespace)
|
||||
settings.SetNamespace(namespace)
|
||||
|
||||
var logger func(string, ...interface{})
|
||||
if silent {
|
||||
logger = noOpLog
|
||||
var logger func(string, ...interface{})
|
||||
if silent {
|
||||
logger = noOpLog
|
||||
|
||||
} else {
|
||||
logger = log.Printf
|
||||
}
|
||||
} else {
|
||||
logger = log.Printf
|
||||
}
|
||||
|
||||
if err := actionConfig.Init(settings.RESTClientGetter(), namespace,
|
||||
os.Getenv("HELM_DRIVER"), logger); err != nil {
|
||||
return fmt.Errorf("failed to initialize Helm action config: %w", err)
|
||||
}
|
||||
if err := actionConfig.Init(settings.RESTClientGetter(), namespace,
|
||||
os.Getenv("HELM_DRIVER"), logger); err != nil {
|
||||
return fmt.Errorf("failed to initialize Helm action config: %w", err)
|
||||
}
|
||||
|
||||
// Ensure namespace exists or create it
|
||||
if err := ensureNamespace(actionConfig, namespace); err != nil {
|
||||
return fmt.Errorf("failed to ensure namespace exists: %w", err)
|
||||
}
|
||||
// Ensure namespace exists or create it
|
||||
if err := ensureNamespace(actionConfig, namespace); err != nil {
|
||||
return fmt.Errorf("failed to ensure namespace exists: %w", err)
|
||||
}
|
||||
|
||||
var chartPath string
|
||||
var err error
|
||||
var chartPath string
|
||||
var err error
|
||||
|
||||
// Determine chart path based on chartName format
|
||||
if strings.HasPrefix(repoURL, "http://") || strings.HasPrefix(repoURL, "https://") || strings.HasPrefix(repoURL, "oci://") {
|
||||
// Handle HTTP or OCI URL
|
||||
err = HelmPull(repoURL, chartName, version, "", true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to pull chart %s: %w", chartName, err)
|
||||
}
|
||||
chartPath = path.Join(helper.HelmCache, fmt.Sprintf("%s-%s.tgz", chartName, version))
|
||||
// Determine chart path based on chartName format
|
||||
if strings.HasPrefix(repoURL, "http://") || strings.HasPrefix(repoURL, "https://") || strings.HasPrefix(repoURL, "oci://") {
|
||||
// Handle HTTP or OCI URL
|
||||
err = HelmPull(repoURL, chartName, version, "", true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to pull chart %s: %w", chartName, err)
|
||||
}
|
||||
chartPath = path.Join(helper.HelmCache, fmt.Sprintf("%s-%s.tgz", chartName, version))
|
||||
|
||||
} else {
|
||||
// Local chart path
|
||||
chartPath = repoURL
|
||||
}
|
||||
} else {
|
||||
// Local chart path
|
||||
chartPath = repoURL
|
||||
}
|
||||
|
||||
// Load the Helm chart using loader.Load
|
||||
chart, err := loader.Load(chartPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load chart: %w", err)
|
||||
}
|
||||
// Load the Helm chart using loader.Load
|
||||
chart, err := loader.Load(chartPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load chart: %w", err)
|
||||
}
|
||||
|
||||
// Set up Helm install action
|
||||
client := action.NewInstall(actionConfig)
|
||||
client.Namespace = namespace
|
||||
client.ReleaseName = releaseName
|
||||
client.DryRun = dryRun
|
||||
client.Version = version
|
||||
// Set up Helm install action
|
||||
client := action.NewInstall(actionConfig)
|
||||
client.Namespace = namespace
|
||||
client.ReleaseName = releaseName
|
||||
client.DryRun = dryRun
|
||||
client.Version = version
|
||||
|
||||
tempValuesName := releaseName + "tempvalues.yaml"
|
||||
tempValuesPath := path.Join(helper.HelmCache, tempValuesName)
|
||||
// Create values.yaml from chart.Values
|
||||
err = createValuesYAML(chart.Values, tempValuesPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating tempvalues.yaml: %w", err)
|
||||
}
|
||||
valueFiles := []string{tempValuesPath}
|
||||
tempValuesName := releaseName + "tempvalues.yaml"
|
||||
tempValuesPath := path.Join(helper.HelmCache, tempValuesName)
|
||||
// Create values.yaml from chart.Values
|
||||
err = createValuesYAML(chart.Values, tempValuesPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating tempvalues.yaml: %w", err)
|
||||
}
|
||||
valueFiles := []string{tempValuesPath}
|
||||
|
||||
// Get the directory part of the path
|
||||
directory := filepath.Dir(valuesFile)
|
||||
// Get the directory part of the path
|
||||
directory := filepath.Dir(valuesFile)
|
||||
|
||||
helmreleasePath := path.Join(directory, "helm-release.yaml")
|
||||
helmreleasePath := path.Join(directory, "helm-release.yaml")
|
||||
|
||||
helmRelease, err := LoadHelmRelease(helmreleasePath)
|
||||
if err != nil {
|
||||
helmRelease, err := LoadHelmRelease(helmreleasePath)
|
||||
if err != nil {
|
||||
|
||||
}
|
||||
tempHRValuesName := releaseName + "temphrvalues.yaml"
|
||||
tempHRValuesPath := path.Join(helper.HelmCache, tempHRValuesName)
|
||||
err = createValuesYAML(helmRelease.Spec.Values, tempHRValuesPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating temphrvalues.yaml: %w", err)
|
||||
}
|
||||
helper.EnvSubst(tempHRValuesPath, helper.TalEnv)
|
||||
valueFiles = append(valueFiles, tempHRValuesPath)
|
||||
}
|
||||
tempHRValuesName := releaseName + "temphrvalues.yaml"
|
||||
tempHRValuesPath := path.Join(helper.HelmCache, tempHRValuesName)
|
||||
err = createValuesYAML(helmRelease.Spec.Values, tempHRValuesPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating temphrvalues.yaml: %w", err)
|
||||
}
|
||||
helper.EnvSubst(tempHRValuesPath, helper.TalEnv)
|
||||
valueFiles = append(valueFiles, tempHRValuesPath)
|
||||
|
||||
if _, err := os.Stat(valuesFile); err == nil {
|
||||
valueFiles = append(valueFiles, valuesFile)
|
||||
if _, err := os.Stat(valuesFile); err == nil {
|
||||
valueFiles = append(valueFiles, valuesFile)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
overrideValuesPath := path.Join(directory, "bootstrap-values.yaml.ct")
|
||||
overrideValuesPath := path.Join(directory, "bootstrap-values.yaml.ct")
|
||||
|
||||
if _, err := os.Stat(overrideValuesPath); err == nil {
|
||||
valueFiles = append(valueFiles, overrideValuesPath)
|
||||
}
|
||||
if _, err := os.Stat(overrideValuesPath); err == nil {
|
||||
valueFiles = append(valueFiles, overrideValuesPath)
|
||||
}
|
||||
|
||||
// Prepare values for installation
|
||||
valOpts := &values.Options{
|
||||
ValueFiles: valueFiles, // Specify value file to merge
|
||||
}
|
||||
// Prepare values for installation
|
||||
valOpts := &values.Options{
|
||||
ValueFiles: valueFiles, // Specify value file to merge
|
||||
}
|
||||
|
||||
// Create getter to fetch values from file
|
||||
valProviders := getter.All(settings)
|
||||
// Create getter to fetch values from file
|
||||
valProviders := getter.All(settings)
|
||||
|
||||
// Merge values with chart's default values
|
||||
vals, err := valOpts.MergeValues(valProviders)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to merge values: %w", err)
|
||||
}
|
||||
// Merge values with chart's default values
|
||||
vals, err := valOpts.MergeValues(valProviders)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to merge values: %w", err)
|
||||
}
|
||||
|
||||
// Install the chart with merged values
|
||||
release, err := client.Run(chart, vals)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to install chart: %w", err)
|
||||
}
|
||||
// Install the chart with merged values
|
||||
release, err := client.Run(chart, vals)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to install chart: %w", err)
|
||||
}
|
||||
|
||||
if wait {
|
||||
waitForRelease(actionConfig, release.Name, client.Namespace)
|
||||
}
|
||||
if wait {
|
||||
waitForRelease(actionConfig, release.Name, client.Namespace)
|
||||
}
|
||||
|
||||
log.Printf("Installed Chart: %s in namespace: %s\n", release.Name, release.Namespace)
|
||||
log.Printf("Installed Chart values: %v\n", release.Config)
|
||||
log.Printf("Installed Chart: %s in namespace: %s\n", release.Name, release.Namespace)
|
||||
log.Printf("Installed Chart values: %v\n", release.Config)
|
||||
|
||||
return nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func ensureNamespace(actionConfig *action.Configuration, namespace string) error {
|
||||
// Check if the namespace exists
|
||||
exists, err := namespaceExists(actionConfig, namespace)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to check if namespace exists: %w", err)
|
||||
}
|
||||
// Check if the namespace exists
|
||||
exists, err := namespaceExists(actionConfig, namespace)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to check if namespace exists: %w", err)
|
||||
}
|
||||
|
||||
if !exists {
|
||||
// Create the namespace if it does not exist
|
||||
err := createNamespace(actionConfig, namespace)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create namespace: %w", err)
|
||||
}
|
||||
}
|
||||
if !exists {
|
||||
// Create the namespace if it does not exist
|
||||
err := createNamespace(actionConfig, namespace)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create namespace: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// HelmUpgrade upgrades a Helm release with provided parameters
|
||||
// HelmUpgrade upgrades a Helm release with provided parameters
|
||||
func HelmUpgrade(repoURL string, chartName string, releaseName string, namespace string, valuesFile string, version string, wait bool, silent bool) error {
|
||||
settings := cli.New()
|
||||
actionConfig := new(action.Configuration)
|
||||
settings := cli.New()
|
||||
actionConfig := new(action.Configuration)
|
||||
|
||||
settings.SetNamespace(namespace)
|
||||
settings.SetNamespace(namespace)
|
||||
|
||||
var logger func(string, ...interface{})
|
||||
if silent {
|
||||
logger = noOpLog
|
||||
} else {
|
||||
logger = log.Printf
|
||||
}
|
||||
var logger func(string, ...interface{})
|
||||
if silent {
|
||||
logger = noOpLog
|
||||
} else {
|
||||
logger = log.Printf
|
||||
}
|
||||
|
||||
if err := actionConfig.Init(settings.RESTClientGetter(), namespace,
|
||||
os.Getenv("HELM_DRIVER"), logger); err != nil {
|
||||
return fmt.Errorf("failed to initialize Helm action config: %w", err)
|
||||
}
|
||||
if err := actionConfig.Init(settings.RESTClientGetter(), namespace,
|
||||
os.Getenv("HELM_DRIVER"), logger); err != nil {
|
||||
return fmt.Errorf("failed to initialize Helm action config: %w", err)
|
||||
}
|
||||
|
||||
// Ensure namespace exists or create it
|
||||
if err := ensureNamespace(actionConfig, namespace); err != nil {
|
||||
return fmt.Errorf("failed to ensure namespace exists: %w", err)
|
||||
}
|
||||
// Ensure namespace exists or create it
|
||||
if err := ensureNamespace(actionConfig, namespace); err != nil {
|
||||
return fmt.Errorf("failed to ensure namespace exists: %w", err)
|
||||
}
|
||||
|
||||
var chartPath string
|
||||
var err error
|
||||
var chartPath string
|
||||
var err error
|
||||
|
||||
// Determine chart path based on chartName format
|
||||
if strings.HasPrefix(repoURL, "http://") || strings.HasPrefix(repoURL, "https://") || strings.HasPrefix(repoURL, "oci://") {
|
||||
// Handle HTTP or OCI URL
|
||||
err = HelmPull(repoURL, chartName, version, "", true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to pull chart %s: %w", chartName, err)
|
||||
}
|
||||
chartPath = path.Join(helper.HelmCache, fmt.Sprintf("%s-%s.tgz", chartName, version))
|
||||
// Determine chart path based on chartName format
|
||||
if strings.HasPrefix(repoURL, "http://") || strings.HasPrefix(repoURL, "https://") || strings.HasPrefix(repoURL, "oci://") {
|
||||
// Handle HTTP or OCI URL
|
||||
err = HelmPull(repoURL, chartName, version, "", true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to pull chart %s: %w", chartName, err)
|
||||
}
|
||||
chartPath = path.Join(helper.HelmCache, fmt.Sprintf("%s-%s.tgz", chartName, version))
|
||||
|
||||
} else {
|
||||
// Local chart path
|
||||
chartPath = repoURL
|
||||
}
|
||||
} else {
|
||||
// Local chart path
|
||||
chartPath = repoURL
|
||||
}
|
||||
|
||||
// Load the Helm chart using loader.Load
|
||||
chart, err := loader.Load(chartPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load chart: %w", err)
|
||||
}
|
||||
// Load the Helm chart using loader.Load
|
||||
chart, err := loader.Load(chartPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load chart: %w", err)
|
||||
}
|
||||
|
||||
// Set up Helm upgrade action
|
||||
client := action.NewUpgrade(actionConfig)
|
||||
client.Namespace = namespace
|
||||
client.Version = version
|
||||
// Set up Helm upgrade action
|
||||
client := action.NewUpgrade(actionConfig)
|
||||
client.Namespace = namespace
|
||||
client.Version = version
|
||||
|
||||
tempValuesName := releaseName + "tempvalues.yaml"
|
||||
tempValuesPath := path.Join(helper.HelmCache, tempValuesName)
|
||||
err = createValuesYAML(chart.Values, tempValuesPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating tempvalues.yaml: %w", err)
|
||||
}
|
||||
valueFiles := []string{tempValuesPath}
|
||||
tempValuesName := releaseName + "tempvalues.yaml"
|
||||
tempValuesPath := path.Join(helper.HelmCache, tempValuesName)
|
||||
err = createValuesYAML(chart.Values, tempValuesPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating tempvalues.yaml: %w", err)
|
||||
}
|
||||
valueFiles := []string{tempValuesPath}
|
||||
|
||||
// Get the directory part of the path
|
||||
directory := filepath.Dir(valuesFile)
|
||||
// Get the directory part of the path
|
||||
directory := filepath.Dir(valuesFile)
|
||||
|
||||
helmreleasePath := path.Join(directory, "helm-release.yaml")
|
||||
helmreleasePath := path.Join(directory, "helm-release.yaml")
|
||||
|
||||
helmRelease, err := LoadHelmRelease(helmreleasePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error loading helm-release.yaml: %w", err)
|
||||
}
|
||||
helmRelease, err := LoadHelmRelease(helmreleasePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error loading helm-release.yaml: %w", err)
|
||||
}
|
||||
|
||||
tempHRValuesName := releaseName + "temphrvalues.yaml"
|
||||
tempHRValuesPath := path.Join(helper.HelmCache, tempHRValuesName)
|
||||
err = createValuesYAML(helmRelease.Spec.Values, tempHRValuesPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating temphrvalues.yaml: %w", err)
|
||||
}
|
||||
helper.EnvSubst(tempHRValuesPath, helper.TalEnv)
|
||||
valueFiles = append(valueFiles, tempHRValuesPath)
|
||||
tempHRValuesName := releaseName + "temphrvalues.yaml"
|
||||
tempHRValuesPath := path.Join(helper.HelmCache, tempHRValuesName)
|
||||
err = createValuesYAML(helmRelease.Spec.Values, tempHRValuesPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating temphrvalues.yaml: %w", err)
|
||||
}
|
||||
helper.EnvSubst(tempHRValuesPath, helper.TalEnv)
|
||||
valueFiles = append(valueFiles, tempHRValuesPath)
|
||||
|
||||
if _, err := os.Stat(valuesFile); err == nil {
|
||||
valueFiles = append(valueFiles, valuesFile)
|
||||
}
|
||||
if _, err := os.Stat(valuesFile); err == nil {
|
||||
valueFiles = append(valueFiles, valuesFile)
|
||||
}
|
||||
|
||||
overrideValuesPath := path.Join(directory, "bootstrap-values.yaml.ct")
|
||||
overrideValuesPath := path.Join(directory, "bootstrap-values.yaml.ct")
|
||||
|
||||
if _, err := os.Stat(overrideValuesPath); err == nil {
|
||||
valueFiles = append(valueFiles, overrideValuesPath)
|
||||
}
|
||||
if _, err := os.Stat(overrideValuesPath); err == nil {
|
||||
valueFiles = append(valueFiles, overrideValuesPath)
|
||||
}
|
||||
|
||||
// Prepare values for upgrade
|
||||
valOpts := &values.Options{
|
||||
ValueFiles: valueFiles, // Specify value file to merge
|
||||
}
|
||||
// Prepare values for upgrade
|
||||
valOpts := &values.Options{
|
||||
ValueFiles: valueFiles, // Specify value file to merge
|
||||
}
|
||||
|
||||
// Create getter to fetch values from file
|
||||
valProviders := getter.All(settings)
|
||||
// Create getter to fetch values from file
|
||||
valProviders := getter.All(settings)
|
||||
|
||||
// Merge values with chart's default values
|
||||
vals, err := valOpts.MergeValues(valProviders)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to merge values: %w", err)
|
||||
}
|
||||
// Merge values with chart's default values
|
||||
vals, err := valOpts.MergeValues(valProviders)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to merge values: %w", err)
|
||||
}
|
||||
|
||||
// Perform the upgrade with merged values
|
||||
release, err := client.Run(releaseName, chart, vals)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to upgrade chart: %w", err)
|
||||
}
|
||||
// Perform the upgrade with merged values
|
||||
release, err := client.Run(releaseName, chart, vals)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to upgrade chart: %w", err)
|
||||
}
|
||||
|
||||
if wait {
|
||||
waitForRelease(actionConfig, release.Name, client.Namespace)
|
||||
}
|
||||
if wait {
|
||||
waitForRelease(actionConfig, release.Name, client.Namespace)
|
||||
}
|
||||
|
||||
log.Printf("Upgraded Chart: %s in namespace: %s\n", release.Name, release.Namespace)
|
||||
log.Printf("Upgraded Chart values: %v\n", release.Config)
|
||||
log.Printf("Upgraded Chart: %s in namespace: %s\n", release.Name, release.Namespace)
|
||||
log.Printf("Upgraded Chart values: %v\n", release.Config)
|
||||
|
||||
return nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func namespaceExists(actionConfig *action.Configuration, namespace string) (bool, error) {
|
||||
// Retrieve Kubernetes client set from actionConfig
|
||||
clientset, err := actionConfig.KubernetesClientSet()
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to get Kubernetes client set: %w", err)
|
||||
}
|
||||
// Retrieve Kubernetes client set from actionConfig
|
||||
clientset, err := actionConfig.KubernetesClientSet()
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to get Kubernetes client set: %w", err)
|
||||
}
|
||||
|
||||
// Use clientset to check if the namespace exists
|
||||
_, err = clientset.CoreV1().Namespaces().Get(context.Background(), namespace, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, nil // Namespace doesn't exist or other error occurred
|
||||
}
|
||||
return true, nil // Namespace exists
|
||||
// Use clientset to check if the namespace exists
|
||||
_, err = clientset.CoreV1().Namespaces().Get(context.Background(), namespace, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, nil // Namespace doesn't exist or other error occurred
|
||||
}
|
||||
return true, nil // Namespace exists
|
||||
}
|
||||
|
||||
func createNamespace(actionConfig *action.Configuration, namespace string) error {
|
||||
// Retrieve Kubernetes client set from actionConfig
|
||||
clientset, err := actionConfig.KubernetesClientSet()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get Kubernetes client set: %w", err)
|
||||
}
|
||||
// Retrieve Kubernetes client set from actionConfig
|
||||
clientset, err := actionConfig.KubernetesClientSet()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get Kubernetes client set: %w", err)
|
||||
}
|
||||
|
||||
// Create the namespace using clientset
|
||||
_, err = clientset.CoreV1().Namespaces().Create(context.Background(), &corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: namespace,
|
||||
},
|
||||
}, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "already exists") {
|
||||
// Create the namespace using clientset
|
||||
_, err = clientset.CoreV1().Namespaces().Create(context.Background(), &corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: namespace,
|
||||
},
|
||||
}, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "already exists") {
|
||||
|
||||
} else {
|
||||
return fmt.Errorf("failed to create namespace: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
return fmt.Errorf("failed to create namespace: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func createValuesYAML(values map[string]interface{}, fileName string) error {
|
||||
removeFileIfExists(fileName)
|
||||
// Marshal values map into YAML format
|
||||
data, err := yaml.Marshal(values)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
removeFileIfExists(fileName)
|
||||
// Marshal values map into YAML format
|
||||
data, err := yaml.Marshal(values)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write YAML data into the file
|
||||
err = ioutil.WriteFile(fileName, data, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Write YAML data into the file
|
||||
err = ioutil.WriteFile(fileName, data, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeFileIfExists(fileName string) error {
|
||||
// Check if the file exists
|
||||
_, err := os.Stat(fileName)
|
||||
if err == nil {
|
||||
// Delete the file
|
||||
err = os.Remove(fileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if !os.IsNotExist(err) {
|
||||
// Return other errors if the file check failed for a reason other than not existing
|
||||
return err
|
||||
}
|
||||
// Check if the file exists
|
||||
_, err := os.Stat(fileName)
|
||||
if err == nil {
|
||||
// Delete the file
|
||||
err = os.Remove(fileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if !os.IsNotExist(err) {
|
||||
// Return other errors if the file check failed for a reason other than not existing
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateHelmRepo(name string, url string, silent bool) error {
|
||||
// Create a Helm repository configuration
|
||||
repoConfig := &repo.Entry{
|
||||
Name: name,
|
||||
URL: url,
|
||||
}
|
||||
// Create a Helm repository configuration
|
||||
repoConfig := &repo.Entry{
|
||||
Name: name,
|
||||
URL: url,
|
||||
}
|
||||
|
||||
// Initialize Helm settings
|
||||
settings := cli.New()
|
||||
// Initialize Helm settings
|
||||
settings := cli.New()
|
||||
|
||||
// Create a repository object
|
||||
r, err := repo.NewChartRepository(repoConfig, getter.All(settings))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create chart repository: %w", err)
|
||||
}
|
||||
// Create a repository object
|
||||
r, err := repo.NewChartRepository(repoConfig, getter.All(settings))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create chart repository: %w", err)
|
||||
}
|
||||
|
||||
// Ensure the repository cache directory exists
|
||||
cacheDir := settings.RepositoryCache
|
||||
if err := os.MkdirAll(cacheDir, os.ModePerm); err != nil {
|
||||
return fmt.Errorf("failed to create cache directory: %w", err)
|
||||
}
|
||||
// Ensure the repository cache directory exists
|
||||
cacheDir := settings.RepositoryCache
|
||||
if err := os.MkdirAll(cacheDir, os.ModePerm); err != nil {
|
||||
return fmt.Errorf("failed to create cache directory: %w", err)
|
||||
}
|
||||
|
||||
// Download the latest index file
|
||||
if _, err := r.DownloadIndexFile(); err != nil {
|
||||
return fmt.Errorf("failed to download index file: %w", err)
|
||||
}
|
||||
// Download the latest index file
|
||||
if _, err := r.DownloadIndexFile(); err != nil {
|
||||
return fmt.Errorf("failed to download index file: %w", err)
|
||||
}
|
||||
|
||||
// Load existing repositories file or create a new one
|
||||
repoFile := settings.RepositoryConfig
|
||||
repoFileContent := repo.NewFile()
|
||||
if _, err := os.Stat(repoFile); err == nil {
|
||||
repoFileContent, err = repo.LoadFile(repoFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load repositories file: %w", err)
|
||||
}
|
||||
}
|
||||
// Load existing repositories file or create a new one
|
||||
repoFile := settings.RepositoryConfig
|
||||
repoFileContent := repo.NewFile()
|
||||
if _, err := os.Stat(repoFile); err == nil {
|
||||
repoFileContent, err = repo.LoadFile(repoFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load repositories file: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Update the repositories file with the new repository
|
||||
if !repoFileContent.Has(name) {
|
||||
repoFileContent.Update(repoConfig)
|
||||
}
|
||||
// Update the repositories file with the new repository
|
||||
if !repoFileContent.Has(name) {
|
||||
repoFileContent.Update(repoConfig)
|
||||
}
|
||||
|
||||
if err := repoFileContent.WriteFile(repoFile, 0644); err != nil {
|
||||
return fmt.Errorf("failed to write repositories file: %w", err)
|
||||
}
|
||||
if err := repoFileContent.WriteFile(repoFile, 0644); err != nil {
|
||||
return fmt.Errorf("failed to write repositories file: %w", err)
|
||||
}
|
||||
|
||||
if !silent {
|
||||
log.Info().Msgf("Successfully updated repository '%s' from %s\n", name, url)
|
||||
}
|
||||
return nil
|
||||
if !silent {
|
||||
log.Info().Msgf("Successfully updated repository '%s' from %s\n", name, url)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// cleanRepoURL performs the specified operations on the input URL
|
||||
func cleanRepoURL(url string) string {
|
||||
// Remove http:// or https:// prefix
|
||||
url = strings.TrimPrefix(url, "http://")
|
||||
url = strings.TrimPrefix(url, "https://")
|
||||
// Remove http:// or https:// prefix
|
||||
url = strings.TrimPrefix(url, "http://")
|
||||
url = strings.TrimPrefix(url, "https://")
|
||||
|
||||
// Remove charts. prefix if present
|
||||
url = strings.TrimPrefix(url, "charts.")
|
||||
// Remove charts. prefix if present
|
||||
url = strings.TrimPrefix(url, "charts.")
|
||||
|
||||
// Remove helm. prefix if present
|
||||
url = strings.TrimPrefix(url, "helm.")
|
||||
// Remove helm. prefix if present
|
||||
url = strings.TrimPrefix(url, "helm.")
|
||||
|
||||
// Remove everything after the last dot
|
||||
lastDotIndex := strings.LastIndex(url, ".")
|
||||
if lastDotIndex != -1 {
|
||||
url = url[:lastDotIndex]
|
||||
}
|
||||
// Remove everything after the last dot
|
||||
lastDotIndex := strings.LastIndex(url, ".")
|
||||
if lastDotIndex != -1 {
|
||||
url = url[:lastDotIndex]
|
||||
}
|
||||
|
||||
url = repoURL(url)
|
||||
url = repoURL(url)
|
||||
|
||||
return url
|
||||
return url
|
||||
}
|
||||
|
||||
func repoURL(url string) string {
|
||||
parts := strings.SplitN(url, "/", 2) // Split into two parts at the first "/"
|
||||
if len(parts) > 0 {
|
||||
url = parts[0]
|
||||
}
|
||||
parts := strings.SplitN(url, "/", 2) // Split into two parts at the first "/"
|
||||
if len(parts) > 0 {
|
||||
url = parts[0]
|
||||
}
|
||||
|
||||
return url
|
||||
return url
|
||||
}
|
||||
|
||||
func waitForRelease(actionConfig *action.Configuration, releaseName, namespace string) {
|
||||
statusClient := action.NewStatus(actionConfig)
|
||||
for {
|
||||
rel, err := statusClient.Run(releaseName)
|
||||
if err != nil {
|
||||
log.Info().Msgf("failed to get release status: %v", err)
|
||||
}
|
||||
if rel.Info.Status == release.StatusDeployed {
|
||||
log.Info().Msgf("Release %s is now deployed\n", releaseName)
|
||||
break
|
||||
}
|
||||
log.Info().Msgf("Waiting for release %s to be deployed (current status: %s)\n", releaseName, rel.Info.Status)
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
statusClient := action.NewStatus(actionConfig)
|
||||
for {
|
||||
rel, err := statusClient.Run(releaseName)
|
||||
if err != nil {
|
||||
log.Info().Msgf("failed to get release status: %v", err)
|
||||
}
|
||||
if rel.Info.Status == release.StatusDeployed {
|
||||
log.Info().Msgf("Release %s is now deployed\n", releaseName)
|
||||
break
|
||||
}
|
||||
log.Info().Msgf("Waiting for release %s to be deployed (current status: %s)\n", releaseName, rel.Info.Status)
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,200 +1,200 @@
|
||||
package fluxhandler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"gopkg.in/yaml.v3"
|
||||
"github.com/rs/zerolog/log"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type HelmChart struct {
|
||||
ChartPath string
|
||||
Retry bool
|
||||
Wait bool
|
||||
ChartPath string
|
||||
Retry bool
|
||||
Wait bool
|
||||
}
|
||||
|
||||
type SourceRef struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
Name string `yaml:"name,omitempty"`
|
||||
Namespace string `yaml:"namespace,omitempty"`
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
Name string `yaml:"name,omitempty"`
|
||||
Namespace string `yaml:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
type ChartSpec struct {
|
||||
Chart string `yaml:"chart,omitempty"`
|
||||
Version string `yaml:"version,omitempty"`
|
||||
SourceRef SourceRef `yaml:"sourceRef,omitempty"`
|
||||
Chart string `yaml:"chart,omitempty"`
|
||||
Version string `yaml:"version,omitempty"`
|
||||
SourceRef SourceRef `yaml:"sourceRef,omitempty"`
|
||||
}
|
||||
|
||||
type Chart struct {
|
||||
Spec ChartSpec `yaml:"spec,omitempty"`
|
||||
Spec ChartSpec `yaml:"spec,omitempty"`
|
||||
}
|
||||
|
||||
type Spec struct {
|
||||
Interval string `yaml:"interval,omitempty"`
|
||||
Chart Chart `yaml:"chart,omitempty"`
|
||||
ReleaseName string `yaml:"releaseName,omitempty"`
|
||||
Values map[string]interface{} `yaml:"values,omitempty"`
|
||||
Interval string `yaml:"interval,omitempty"`
|
||||
Chart Chart `yaml:"chart,omitempty"`
|
||||
ReleaseName string `yaml:"releaseName,omitempty"`
|
||||
Values map[string]interface{} `yaml:"values,omitempty"`
|
||||
}
|
||||
|
||||
type Metadata struct {
|
||||
Name string `yaml:"name,omitempty"`
|
||||
Namespace string `yaml:"namespace,omitempty"`
|
||||
Name string `yaml:"name,omitempty"`
|
||||
Namespace string `yaml:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
type HelmRelease struct {
|
||||
Metadata Metadata `yaml:"metadata,omitempty"`
|
||||
Spec Spec `yaml:"spec,omitempty"`
|
||||
Metadata Metadata `yaml:"metadata,omitempty"`
|
||||
Spec Spec `yaml:"spec,omitempty"`
|
||||
}
|
||||
|
||||
func LoadHelmRelease(filename string) (*HelmRelease, error) {
|
||||
// Read YAML file
|
||||
yamlFile, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read file: %w", err)
|
||||
}
|
||||
// Read YAML file
|
||||
yamlFile, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read file: %w", err)
|
||||
}
|
||||
|
||||
// Initialize HelmRelease struct
|
||||
config := &HelmRelease{}
|
||||
// Initialize HelmRelease struct
|
||||
config := &HelmRelease{}
|
||||
|
||||
// Unmarshal YAML into struct
|
||||
err = yaml.Unmarshal(yamlFile, config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal YAML: %w", err)
|
||||
}
|
||||
// Unmarshal YAML into struct
|
||||
err = yaml.Unmarshal(yamlFile, config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal YAML: %w", err)
|
||||
}
|
||||
|
||||
// Ensure Values is not nil
|
||||
if config.Spec.Values == nil {
|
||||
config.Spec.Values = make(map[string]interface{})
|
||||
}
|
||||
return config, nil
|
||||
// Ensure Values is not nil
|
||||
if config.Spec.Values == nil {
|
||||
config.Spec.Values = make(map[string]interface{})
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func InstallCharts(charts []HelmChart, HelmRepos map[string]*HelmRepo, async bool) {
|
||||
var wg sync.WaitGroup
|
||||
for _, chart := range charts {
|
||||
wg.Add(1)
|
||||
go func(chart HelmChart) {
|
||||
defer wg.Done()
|
||||
valuesFile := filepath.Join(chart.ChartPath, "values.yaml")
|
||||
helmreleaseFile := filepath.Join(chart.ChartPath, "helm-release.yaml")
|
||||
helmRelease, err := LoadHelmRelease(helmreleaseFile)
|
||||
if err != nil {
|
||||
log.Info().Msgf("ERROR LOADING helmRelease for: %v", chart)
|
||||
os.Exit(1)
|
||||
}
|
||||
if helmRelease == nil {
|
||||
log.Info().Msgf("ERROR Empty helmRelease for: %v", chart)
|
||||
os.Exit(1)
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
for _, chart := range charts {
|
||||
wg.Add(1)
|
||||
go func(chart HelmChart) {
|
||||
defer wg.Done()
|
||||
valuesFile := filepath.Join(chart.ChartPath, "values.yaml")
|
||||
helmreleaseFile := filepath.Join(chart.ChartPath, "helm-release.yaml")
|
||||
helmRelease, err := LoadHelmRelease(helmreleaseFile)
|
||||
if err != nil {
|
||||
log.Info().Msgf("ERROR LOADING helmRelease for: %v", chart)
|
||||
os.Exit(1)
|
||||
}
|
||||
if helmRelease == nil {
|
||||
log.Info().Msgf("ERROR Empty helmRelease for: %v", chart)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
releaseName := helmRelease.Metadata.Name
|
||||
if helmRelease.Spec.ReleaseName != "" {
|
||||
releaseName = helmRelease.Spec.ReleaseName
|
||||
}
|
||||
releaseName := helmRelease.Metadata.Name
|
||||
if helmRelease.Spec.ReleaseName != "" {
|
||||
releaseName = helmRelease.Spec.ReleaseName
|
||||
}
|
||||
|
||||
if HelmRepos[helmRelease.Spec.Chart.Spec.SourceRef.Name] == nil {
|
||||
log.Info().Msgf("ERROR Empty helmRepo for: ", helmRelease.Spec.Chart.Spec.SourceRef.Name)
|
||||
os.Exit(1)
|
||||
}
|
||||
if HelmRepos[helmRelease.Spec.Chart.Spec.SourceRef.Name] == nil {
|
||||
log.Info().Msgf("ERROR Empty helmRepo for: ", helmRelease.Spec.Chart.Spec.SourceRef.Name)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if HelmRepos[helmRelease.Spec.Chart.Spec.SourceRef.Name].Spec.URL == "" {
|
||||
log.Info().Msgf("ERROR Empty repoURL for: ", helmRelease.Spec.Chart.Spec.SourceRef.Name)
|
||||
os.Exit(1)
|
||||
}
|
||||
if HelmRepos[helmRelease.Spec.Chart.Spec.SourceRef.Name].Spec.URL == "" {
|
||||
log.Info().Msgf("ERROR Empty repoURL for: ", helmRelease.Spec.Chart.Spec.SourceRef.Name)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
log.Info().Msgf("Bootstrap: Installing %s\n", helmRelease.Metadata.Name)
|
||||
// We need to split install from dependency downloading, so we can parallel downloading
|
||||
if err := HelmInstall(HelmRepos[helmRelease.Spec.Chart.Spec.SourceRef.Name].Spec.URL, helmRelease.Spec.Chart.Spec.Chart, releaseName, helmRelease.Metadata.Namespace, valuesFile, helmRelease.Spec.Chart.Spec.Version, chart.Retry, chart.Wait, true); err != nil {
|
||||
if strings.Contains(err.Error(), "webhook") {
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||
if !async {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}(chart)
|
||||
if !async {
|
||||
wg.Wait()
|
||||
}
|
||||
}
|
||||
if async {
|
||||
wg.Wait()
|
||||
}
|
||||
log.Info().Msgf("Bootstrap: Installing %s\n", helmRelease.Metadata.Name)
|
||||
// We need to split install from dependency downloading, so we can parallel downloading
|
||||
if err := HelmInstall(HelmRepos[helmRelease.Spec.Chart.Spec.SourceRef.Name].Spec.URL, helmRelease.Spec.Chart.Spec.Chart, releaseName, helmRelease.Metadata.Namespace, valuesFile, helmRelease.Spec.Chart.Spec.Version, chart.Retry, chart.Wait, true); err != nil {
|
||||
if strings.Contains(err.Error(), "webhook") {
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||
if !async {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}(chart)
|
||||
if !async {
|
||||
wg.Wait()
|
||||
}
|
||||
}
|
||||
if async {
|
||||
wg.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
// UpgradeCharts upgrades Helm releases with provided Helm charts and repositories
|
||||
func UpgradeCharts(charts []HelmChart, HelmRepos map[string]*HelmRepo, async bool) {
|
||||
var wg sync.WaitGroup
|
||||
for _, chart := range charts {
|
||||
wg.Add(1)
|
||||
go func(chart HelmChart) {
|
||||
defer wg.Done()
|
||||
var wg sync.WaitGroup
|
||||
for _, chart := range charts {
|
||||
wg.Add(1)
|
||||
go func(chart HelmChart) {
|
||||
defer wg.Done()
|
||||
|
||||
// Determine paths
|
||||
valuesFile := filepath.Join(chart.ChartPath, "values.yaml")
|
||||
helmreleaseFile := filepath.Join(chart.ChartPath, "helm-release.yaml")
|
||||
// Determine paths
|
||||
valuesFile := filepath.Join(chart.ChartPath, "values.yaml")
|
||||
helmreleaseFile := filepath.Join(chart.ChartPath, "helm-release.yaml")
|
||||
|
||||
// Load Helm release
|
||||
helmRelease, err := LoadHelmRelease(helmreleaseFile)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error loading Helm release for chart at %s: %v\n", chart.ChartPath, err)
|
||||
if !async {
|
||||
os.Exit(1)
|
||||
}
|
||||
return
|
||||
}
|
||||
if helmRelease == nil {
|
||||
fmt.Fprintf(os.Stderr, "Empty Helm release for chart at %s\n", chart.ChartPath)
|
||||
if !async {
|
||||
os.Exit(1)
|
||||
}
|
||||
return
|
||||
}
|
||||
// Load Helm release
|
||||
helmRelease, err := LoadHelmRelease(helmreleaseFile)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error loading Helm release for chart at %s: %v\n", chart.ChartPath, err)
|
||||
if !async {
|
||||
os.Exit(1)
|
||||
}
|
||||
return
|
||||
}
|
||||
if helmRelease == nil {
|
||||
fmt.Fprintf(os.Stderr, "Empty Helm release for chart at %s\n", chart.ChartPath)
|
||||
if !async {
|
||||
os.Exit(1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Determine release name
|
||||
releaseName := helmRelease.Metadata.Name
|
||||
if helmRelease.Spec.ReleaseName != "" {
|
||||
releaseName = helmRelease.Spec.ReleaseName
|
||||
}
|
||||
// Determine release name
|
||||
releaseName := helmRelease.Metadata.Name
|
||||
if helmRelease.Spec.ReleaseName != "" {
|
||||
releaseName = helmRelease.Spec.ReleaseName
|
||||
}
|
||||
|
||||
// Determine chart name
|
||||
chartName := helmRelease.Spec.Chart.Spec.Chart
|
||||
// Determine chart name
|
||||
chartName := helmRelease.Spec.Chart.Spec.Chart
|
||||
|
||||
// Validate Helm repository
|
||||
repoName := helmRelease.Spec.Chart.Spec.SourceRef.Name
|
||||
repo, ok := HelmRepos[repoName]
|
||||
if !ok || repo.Spec.URL == "" {
|
||||
fmt.Fprintf(os.Stderr, "Empty or invalid Helm repository for %s\n", repoName)
|
||||
if !async {
|
||||
os.Exit(1)
|
||||
}
|
||||
return
|
||||
}
|
||||
// Validate Helm repository
|
||||
repoName := helmRelease.Spec.Chart.Spec.SourceRef.Name
|
||||
repo, ok := HelmRepos[repoName]
|
||||
if !ok || repo.Spec.URL == "" {
|
||||
fmt.Fprintf(os.Stderr, "Empty or invalid Helm repository for %s\n", repoName)
|
||||
if !async {
|
||||
os.Exit(1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Perform Helm upgrade
|
||||
log.Info().Msgf("Upgrading %s\n", helmRelease.Metadata.Name)
|
||||
err = HelmUpgrade(repo.Spec.URL, chartName, releaseName, helmRelease.Metadata.Namespace, valuesFile, helmRelease.Spec.Chart.Spec.Version, chart.Wait, true)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error upgrading %s: %v\n", helmRelease.Metadata.Name, err)
|
||||
if !async {
|
||||
os.Exit(1)
|
||||
}
|
||||
return
|
||||
}
|
||||
}(chart)
|
||||
// Perform Helm upgrade
|
||||
log.Info().Msgf("Upgrading %s\n", helmRelease.Metadata.Name)
|
||||
err = HelmUpgrade(repo.Spec.URL, chartName, releaseName, helmRelease.Metadata.Namespace, valuesFile, helmRelease.Spec.Chart.Spec.Version, chart.Wait, true)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error upgrading %s: %v\n", helmRelease.Metadata.Name, err)
|
||||
if !async {
|
||||
os.Exit(1)
|
||||
}
|
||||
return
|
||||
}
|
||||
}(chart)
|
||||
|
||||
if !async {
|
||||
wg.Wait()
|
||||
}
|
||||
}
|
||||
if !async {
|
||||
wg.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
if async {
|
||||
wg.Wait()
|
||||
}
|
||||
if async {
|
||||
wg.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,76 +1,76 @@
|
||||
package fluxhandler
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"gopkg.in/yaml.v3"
|
||||
"github.com/rs/zerolog/log"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type HelmRepoMetadata struct {
|
||||
Name string `yaml:"name,omitempty"`
|
||||
Namespace string `yaml:"namespace,omitempty"`
|
||||
Name string `yaml:"name,omitempty"`
|
||||
Namespace string `yaml:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
type HelmRepoSpec struct {
|
||||
Interval string `yaml:"interval,omitempty"`
|
||||
URL string `yaml:"url,omitempty"`
|
||||
Interval string `yaml:"interval,omitempty"`
|
||||
URL string `yaml:"url,omitempty"`
|
||||
}
|
||||
|
||||
type HelmRepo struct {
|
||||
Metadata HelmRepoMetadata `yaml:"metadata,omitempty"`
|
||||
Spec HelmRepoSpec `yaml:"spec,omitempty"`
|
||||
Metadata HelmRepoMetadata `yaml:"metadata,omitempty"`
|
||||
Spec HelmRepoSpec `yaml:"spec,omitempty"`
|
||||
}
|
||||
|
||||
// LoadAllHelmRepos loads all .yaml files under a directory into a map of HelmRepo structs,
|
||||
// ignoring kustomize.yaml and logging errors without stopping the entire process.
|
||||
func LoadAllHelmRepos(dirPath string) (map[string]*HelmRepo, error) {
|
||||
files, err := ioutil.ReadDir(dirPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
files, err := ioutil.ReadDir(dirPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
repos := make(map[string]*HelmRepo)
|
||||
repos := make(map[string]*HelmRepo)
|
||||
|
||||
for _, file := range files {
|
||||
if !file.IsDir() && strings.HasSuffix(file.Name(), ".yaml") {
|
||||
// Ignore kustomize.yaml file
|
||||
if file.Name() == "kustomize.yaml" {
|
||||
continue
|
||||
}
|
||||
filename := filepath.Join(dirPath, file.Name())
|
||||
repo, err := LoadHelmRepo(filename)
|
||||
if err != nil {
|
||||
// Log the error but continue processing other files
|
||||
log.Info().Msgf("Error loading repo from file %s: %v\n", file.Name(), err)
|
||||
continue
|
||||
}
|
||||
// Use metadata.name as the key in the map
|
||||
repos[repo.Metadata.Name] = repo
|
||||
}
|
||||
}
|
||||
for _, file := range files {
|
||||
if !file.IsDir() && strings.HasSuffix(file.Name(), ".yaml") {
|
||||
// Ignore kustomize.yaml file
|
||||
if file.Name() == "kustomize.yaml" {
|
||||
continue
|
||||
}
|
||||
filename := filepath.Join(dirPath, file.Name())
|
||||
repo, err := LoadHelmRepo(filename)
|
||||
if err != nil {
|
||||
// Log the error but continue processing other files
|
||||
log.Info().Msgf("Error loading repo from file %s: %v\n", file.Name(), err)
|
||||
continue
|
||||
}
|
||||
// Use metadata.name as the key in the map
|
||||
repos[repo.Metadata.Name] = repo
|
||||
}
|
||||
}
|
||||
|
||||
return repos, nil
|
||||
return repos, nil
|
||||
}
|
||||
|
||||
// LoadHelmRepo loads a single HelmRepo struct from a YAML file
|
||||
func LoadHelmRepo(filename string) (*HelmRepo, error) {
|
||||
// Read YAML file
|
||||
yamlFile, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Read YAML file
|
||||
yamlFile, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Initialize HelmRepo struct
|
||||
repo := &HelmRepo{}
|
||||
// Initialize HelmRepo struct
|
||||
repo := &HelmRepo{}
|
||||
|
||||
// Unmarshal YAML into struct
|
||||
err = yaml.Unmarshal(yamlFile, repo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Unmarshal YAML into struct
|
||||
err = yaml.Unmarshal(yamlFile, repo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return repo, nil
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
package fluxhandler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// check if a file exists
|
||||
func fileExists(filename string) bool {
|
||||
info, err := os.Stat(filename)
|
||||
if os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
return !info.IsDir()
|
||||
info, err := os.Stat(filename)
|
||||
if os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
return !info.IsDir()
|
||||
}
|
||||
|
||||
// createKsYaml creates ks.yaml file with Flux Kustomization
|
||||
func createKsYaml(path, parentFolder string) error {
|
||||
// Ensure the path uses forward slashes
|
||||
linuxPath := filepath.ToSlash(path)
|
||||
// Ensure the path uses forward slashes
|
||||
linuxPath := filepath.ToSlash(path)
|
||||
|
||||
content := fmt.Sprintf(`apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
content := fmt.Sprintf(`apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: %s
|
||||
@@ -36,125 +36,125 @@ spec:
|
||||
name: cluster
|
||||
|
||||
`, parentFolder, linuxPath)
|
||||
return ioutil.WriteFile(filepath.Join(path, "ks.yaml"), []byte(content), 0644)
|
||||
return ioutil.WriteFile(filepath.Join(path, "ks.yaml"), []byte(content), 0644)
|
||||
}
|
||||
|
||||
// createOrUpdateKustomizationYaml creates or updates kustomization.yaml file
|
||||
func createOrUpdateKustomizationYaml(path string) error {
|
||||
kustomizationPath := filepath.Join(path, "kustomization.yaml")
|
||||
var content string
|
||||
if fileExists(kustomizationPath) {
|
||||
// Read existing kustomization.yaml file
|
||||
data, err := ioutil.ReadFile(kustomizationPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
content = string(data)
|
||||
} else {
|
||||
content = `apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kustomizationPath := filepath.Join(path, "kustomization.yaml")
|
||||
var content string
|
||||
if fileExists(kustomizationPath) {
|
||||
// Read existing kustomization.yaml file
|
||||
data, err := ioutil.ReadFile(kustomizationPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
content = string(data)
|
||||
} else {
|
||||
content = `apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
`
|
||||
}
|
||||
}
|
||||
|
||||
// List all files and folders in the current directory
|
||||
files, err := ioutil.ReadDir(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// List all files and folders in the current directory
|
||||
files, err := ioutil.ReadDir(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Collect resources to add to kustomization.yaml
|
||||
var resources []string
|
||||
for _, file := range files {
|
||||
name := file.Name()
|
||||
// Ignore kustomization.yaml and ks.yaml files
|
||||
if name == "kustomization.yaml" || name == "ks.yaml" {
|
||||
continue
|
||||
}
|
||||
// Include only YAML files and directories
|
||||
if strings.HasSuffix(name, ".yaml") || file.IsDir() {
|
||||
if file.IsDir() && fileExists(filepath.Join(path, name, "ks.yaml")) {
|
||||
// Update folder entry to include ks.yaml
|
||||
name = fmt.Sprintf("%s/ks.yaml", name)
|
||||
}
|
||||
// Check if the file/folder is already listed
|
||||
if !strings.Contains(content, name) {
|
||||
if name == "namespace.yaml" {
|
||||
resources = append([]string{name}, resources...)
|
||||
} else {
|
||||
resources = append(resources, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Collect resources to add to kustomization.yaml
|
||||
var resources []string
|
||||
for _, file := range files {
|
||||
name := file.Name()
|
||||
// Ignore kustomization.yaml and ks.yaml files
|
||||
if name == "kustomization.yaml" || name == "ks.yaml" {
|
||||
continue
|
||||
}
|
||||
// Include only YAML files and directories
|
||||
if strings.HasSuffix(name, ".yaml") || file.IsDir() {
|
||||
if file.IsDir() && fileExists(filepath.Join(path, name, "ks.yaml")) {
|
||||
// Update folder entry to include ks.yaml
|
||||
name = fmt.Sprintf("%s/ks.yaml", name)
|
||||
}
|
||||
// Check if the file/folder is already listed
|
||||
if !strings.Contains(content, name) {
|
||||
if name == "namespace.yaml" {
|
||||
resources = append([]string{name}, resources...)
|
||||
} else {
|
||||
resources = append(resources, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update kustomization.yaml content
|
||||
for _, resource := range resources {
|
||||
content += fmt.Sprintf(" - %s\n", resource)
|
||||
}
|
||||
// Update kustomization.yaml content
|
||||
for _, resource := range resources {
|
||||
content += fmt.Sprintf(" - %s\n", resource)
|
||||
}
|
||||
|
||||
contentLines := strings.Split(content, "\n")
|
||||
for _, item := range contentLines {
|
||||
contentLines := strings.Split(content, "\n")
|
||||
for _, item := range contentLines {
|
||||
|
||||
if strings.HasSuffix(item, "/ks.yaml") {
|
||||
prefix := strings.TrimSuffix(item, "/ks.yaml")
|
||||
if strings.HasSuffix(item, "/ks.yaml") {
|
||||
prefix := strings.TrimSuffix(item, "/ks.yaml")
|
||||
|
||||
// Remove other resources with the same prefix from content
|
||||
var updatedContent []string
|
||||
for _, line := range contentLines {
|
||||
if line != prefix {
|
||||
updatedContent = append(updatedContent, line)
|
||||
}
|
||||
}
|
||||
contentLines = updatedContent
|
||||
}
|
||||
}
|
||||
content = strings.Join(contentLines, "\n")
|
||||
// Remove other resources with the same prefix from content
|
||||
var updatedContent []string
|
||||
for _, line := range contentLines {
|
||||
if line != prefix {
|
||||
updatedContent = append(updatedContent, line)
|
||||
}
|
||||
}
|
||||
contentLines = updatedContent
|
||||
}
|
||||
}
|
||||
content = strings.Join(contentLines, "\n")
|
||||
|
||||
// Write back the updated kustomization.yaml file
|
||||
return ioutil.WriteFile(kustomizationPath, []byte(content), 0644)
|
||||
// Write back the updated kustomization.yaml file
|
||||
return ioutil.WriteFile(kustomizationPath, []byte(content), 0644)
|
||||
}
|
||||
|
||||
// processDirectory processes each directory recursively
|
||||
func ProcessDirectory(path string) error {
|
||||
hasAppFolder := false
|
||||
hasKsYaml := false
|
||||
hasAppFolder := false
|
||||
hasKsYaml := false
|
||||
|
||||
// Check for "app" folder and "ks.yaml" file
|
||||
files, err := ioutil.ReadDir(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, file := range files {
|
||||
if file.IsDir() && file.Name() == "app" {
|
||||
hasAppFolder = true
|
||||
}
|
||||
if file.Name() == "ks.yaml" {
|
||||
hasKsYaml = true
|
||||
}
|
||||
}
|
||||
// Check for "app" folder and "ks.yaml" file
|
||||
files, err := ioutil.ReadDir(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, file := range files {
|
||||
if file.IsDir() && file.Name() == "app" {
|
||||
hasAppFolder = true
|
||||
}
|
||||
if file.Name() == "ks.yaml" {
|
||||
hasKsYaml = true
|
||||
}
|
||||
}
|
||||
|
||||
// Create ks.yaml if "app" folder exists and ks.yaml does not exist
|
||||
if hasAppFolder && !hasKsYaml {
|
||||
parentFolder := filepath.Base(path)
|
||||
if err := createKsYaml(path, parentFolder); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if !hasKsYaml { // Only create/update kustomization.yaml if ks.yaml does not exist
|
||||
// Create or update kustomization.yaml
|
||||
if err := createOrUpdateKustomizationYaml(path); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Create ks.yaml if "app" folder exists and ks.yaml does not exist
|
||||
if hasAppFolder && !hasKsYaml {
|
||||
parentFolder := filepath.Base(path)
|
||||
if err := createKsYaml(path, parentFolder); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if !hasKsYaml { // Only create/update kustomization.yaml if ks.yaml does not exist
|
||||
// Create or update kustomization.yaml
|
||||
if err := createOrUpdateKustomizationYaml(path); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Recurse into subdirectories
|
||||
for _, file := range files {
|
||||
if file.IsDir() {
|
||||
if err := ProcessDirectory(filepath.Join(path, file.Name())); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
// Recurse into subdirectories
|
||||
for _, file := range files {
|
||||
if file.IsDir() {
|
||||
if err := ProcessDirectory(filepath.Join(path, file.Name())); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,238 +1,238 @@
|
||||
package fluxhandler
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"github.com/truecharts/public/clustertool/pkg/helper"
|
||||
"golang.org/x/crypto/ssh"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"sigs.k8s.io/yaml"
|
||||
"github.com/truecharts/public/clustertool/pkg/helper"
|
||||
"golang.org/x/crypto/ssh"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// Define a struct to map the YAML content
|
||||
type Config struct {
|
||||
StringData map[string]string `yaml:"stringData"`
|
||||
StringData map[string]string `yaml:"stringData"`
|
||||
}
|
||||
|
||||
// CreateGitSecret generates a Kubernetes secret YAML file and a public key text file.
|
||||
func CreateGitSecret(gitURL string) error {
|
||||
if gitURL == "" {
|
||||
gitURL = "github.com"
|
||||
}
|
||||
if gitURL == "" {
|
||||
gitURL = "github.com"
|
||||
}
|
||||
|
||||
// Paths for files
|
||||
secretPath := filepath.Join(helper.ClusterPath, "kubernetes", "flux-system", "flux", "deploykey.secret.yaml")
|
||||
publicKeyPath := filepath.Join(".", "ssh-public-key.txt")
|
||||
// Paths for files
|
||||
secretPath := filepath.Join(helper.ClusterPath, "kubernetes", "flux-system", "flux", "deploykey.secret.yaml")
|
||||
publicKeyPath := filepath.Join(".", "ssh-public-key.txt")
|
||||
|
||||
// Check if secret YAML already exists
|
||||
if _, err := os.Stat(secretPath); os.IsNotExist(err) {
|
||||
// Generate ECDSA private key
|
||||
privateKey, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate ECDSA private key: %w", err)
|
||||
}
|
||||
// Check if secret YAML already exists
|
||||
if _, err := os.Stat(secretPath); os.IsNotExist(err) {
|
||||
// Generate ECDSA private key
|
||||
privateKey, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate ECDSA private key: %w", err)
|
||||
}
|
||||
|
||||
// Encode private key to PEM format
|
||||
privateKeyPEMBlock, err := pemBlockForKey(privateKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create PEM block for private key: %w", err)
|
||||
}
|
||||
// Encode private key to PEM format
|
||||
privateKeyPEMBlock, err := pemBlockForKey(privateKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create PEM block for private key: %w", err)
|
||||
}
|
||||
|
||||
// Generate OpenSSH formatted public key
|
||||
publicKey, err := publicKeyToOpenSSH(&privateKey.PublicKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate OpenSSH public key: %w", err)
|
||||
}
|
||||
// Generate OpenSSH formatted public key
|
||||
publicKey, err := publicKeyToOpenSSH(&privateKey.PublicKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate OpenSSH public key: %w", err)
|
||||
}
|
||||
|
||||
// Write public key to file
|
||||
err = os.WriteFile(publicKeyPath, []byte(publicKey), 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to write public key to file: %w", err)
|
||||
}
|
||||
log.Info().Msgf("Public key saved to: %s\n", publicKeyPath)
|
||||
// Write public key to file
|
||||
err = os.WriteFile(publicKeyPath, []byte(publicKey), 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to write public key to file: %w", err)
|
||||
}
|
||||
log.Info().Msgf("Public key saved to: %s\n", publicKeyPath)
|
||||
|
||||
// Generate known_hosts entry
|
||||
knownHosts := getKnownHostsEntry(gitURL)
|
||||
// Generate known_hosts entry
|
||||
knownHosts := getKnownHostsEntry(gitURL)
|
||||
|
||||
// Generate Kubernetes secret YAML content
|
||||
secret := map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Secret",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "deploy-key",
|
||||
"namespace": "flux-system",
|
||||
},
|
||||
"stringData": map[string]interface{}{
|
||||
"identity": string(privateKeyPEMBlock),
|
||||
"identity.pub": publicKey,
|
||||
"known_hosts": knownHosts,
|
||||
},
|
||||
"type": string(corev1.SecretTypeOpaque),
|
||||
}
|
||||
// Generate Kubernetes secret YAML content
|
||||
secret := map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Secret",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "deploy-key",
|
||||
"namespace": "flux-system",
|
||||
},
|
||||
"stringData": map[string]interface{}{
|
||||
"identity": string(privateKeyPEMBlock),
|
||||
"identity.pub": publicKey,
|
||||
"known_hosts": knownHosts,
|
||||
},
|
||||
"type": string(corev1.SecretTypeOpaque),
|
||||
}
|
||||
|
||||
secretYAML, err := yaml.Marshal(secret)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal secret to YAML: %w", err)
|
||||
}
|
||||
secretYAML, err := yaml.Marshal(secret)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal secret to YAML: %w", err)
|
||||
}
|
||||
|
||||
// Write Kubernetes secret YAML to file
|
||||
err = os.MkdirAll(filepath.Dir(secretPath), 0755)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create directories: %w", err)
|
||||
}
|
||||
err = os.WriteFile(secretPath, secretYAML, 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to write secret YAML to file: %w", err)
|
||||
}
|
||||
log.Info().Msgf("Kubernetes secret YAML saved to: %s\n", secretPath)
|
||||
} else {
|
||||
// Secret YAML already exists, check if public key file exists
|
||||
if _, err := os.Stat(publicKeyPath); os.IsNotExist(err) {
|
||||
// Public key file does not exist, generate from existing secret
|
||||
secretYAML, err := os.ReadFile(secretPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read existing secret YAML: %w", err)
|
||||
}
|
||||
// Write Kubernetes secret YAML to file
|
||||
err = os.MkdirAll(filepath.Dir(secretPath), 0755)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create directories: %w", err)
|
||||
}
|
||||
err = os.WriteFile(secretPath, secretYAML, 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to write secret YAML to file: %w", err)
|
||||
}
|
||||
log.Info().Msgf("Kubernetes secret YAML saved to: %s\n", secretPath)
|
||||
} else {
|
||||
// Secret YAML already exists, check if public key file exists
|
||||
if _, err := os.Stat(publicKeyPath); os.IsNotExist(err) {
|
||||
// Public key file does not exist, generate from existing secret
|
||||
secretYAML, err := os.ReadFile(secretPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read existing secret YAML: %w", err)
|
||||
}
|
||||
|
||||
var secret corev1.Secret
|
||||
if err := yaml.Unmarshal(secretYAML, &secret); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal secret YAML: %w", err)
|
||||
}
|
||||
var secret corev1.Secret
|
||||
if err := yaml.Unmarshal(secretYAML, &secret); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal secret YAML: %w", err)
|
||||
}
|
||||
|
||||
if ppk, ok := secret.StringData["identity.pub"]; ok {
|
||||
err = os.WriteFile(publicKeyPath, []byte(ppk), 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to write public key to file: %w", err)
|
||||
}
|
||||
log.Info().Msgf("Public key saved to: %s\n", publicKeyPath)
|
||||
} else {
|
||||
return fmt.Errorf("identity.pub not found in existing secret YAML")
|
||||
}
|
||||
} else {
|
||||
log.Info().Msgf("Public key file already exists: %s\n", publicKeyPath)
|
||||
}
|
||||
}
|
||||
if ppk, ok := secret.StringData["identity.pub"]; ok {
|
||||
err = os.WriteFile(publicKeyPath, []byte(ppk), 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to write public key to file: %w", err)
|
||||
}
|
||||
log.Info().Msgf("Public key saved to: %s\n", publicKeyPath)
|
||||
} else {
|
||||
return fmt.Errorf("identity.pub not found in existing secret YAML")
|
||||
}
|
||||
} else {
|
||||
log.Info().Msgf("Public key file already exists: %s\n", publicKeyPath)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateSshPatch() {
|
||||
log.Info().Msg("generating talospatch for flux ssh key...")
|
||||
// Paths to the YAML files
|
||||
secretPath := filepath.Join(helper.ClusterPath, "kubernetes", "flux-system", "flux", "deploykey.secret.yaml")
|
||||
sopsPatchPath := filepath.Join(helper.ClusterPath, "talos", "patches", "sopssecret.yaml")
|
||||
log.Info().Msg("generating talospatch for flux ssh key...")
|
||||
// Paths to the YAML files
|
||||
secretPath := filepath.Join(helper.ClusterPath, "kubernetes", "flux-system", "flux", "deploykey.secret.yaml")
|
||||
sopsPatchPath := filepath.Join(helper.ClusterPath, "talos", "patches", "sopssecret.yaml")
|
||||
|
||||
// Read the YAML file
|
||||
yamlFile, err := ioutil.ReadFile(secretPath)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("error: %v")
|
||||
}
|
||||
// Read the YAML file
|
||||
yamlFile, err := ioutil.ReadFile(secretPath)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("error: %v")
|
||||
}
|
||||
|
||||
// Unmarshal the YAML content into a Config struct
|
||||
var config Config
|
||||
err = yaml.Unmarshal(yamlFile, &config)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("error: %v")
|
||||
}
|
||||
// Unmarshal the YAML content into a Config struct
|
||||
var config Config
|
||||
err = yaml.Unmarshal(yamlFile, &config)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("error: %v")
|
||||
}
|
||||
|
||||
// Extract the stringData content and convert it to a multi-line string
|
||||
stringData, err := yaml.Marshal(config.StringData)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("error: %v")
|
||||
}
|
||||
// Extract the stringData content and convert it to a multi-line string
|
||||
stringData, err := yaml.Marshal(config.StringData)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("error: %v")
|
||||
}
|
||||
|
||||
// Convert byte array to string
|
||||
deployKeyData := string(stringData)
|
||||
// Convert byte array to string
|
||||
deployKeyData := string(stringData)
|
||||
|
||||
// Replace the placeholder in sopspath.yaml
|
||||
err = ReplacePlaceholder(sopsPatchPath, "REPLACEWITHDEPLOYKEY", indentYaml(deployKeyData, " "))
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("Failed to replace placeholder: %v")
|
||||
}
|
||||
// Replace the placeholder in sopspath.yaml
|
||||
err = ReplacePlaceholder(sopsPatchPath, "REPLACEWITHDEPLOYKEY", indentYaml(deployKeyData, " "))
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("Failed to replace placeholder: %v")
|
||||
}
|
||||
}
|
||||
|
||||
// indentYaml indents each line of the YAML string with the specified indentation.
|
||||
func indentYaml(yamlStr, indent string) string {
|
||||
lines := strings.Split(yamlStr, "\n")
|
||||
for i, line := range lines {
|
||||
if line != "" {
|
||||
lines[i] = indent + line
|
||||
}
|
||||
}
|
||||
return strings.Join(lines, "\n")
|
||||
lines := strings.Split(yamlStr, "\n")
|
||||
for i, line := range lines {
|
||||
if line != "" {
|
||||
lines[i] = indent + line
|
||||
}
|
||||
}
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
// ReplacePlaceholder replaces the placeholder in the file at the given path with the specified replacement string.
|
||||
func ReplacePlaceholder(filePath, placeholder, replacement string) error {
|
||||
data, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fileContent := string(data)
|
||||
fileContent = strings.Replace(fileContent, placeholder, replacement, -1)
|
||||
fileContent := string(data)
|
||||
fileContent = strings.Replace(fileContent, placeholder, replacement, -1)
|
||||
|
||||
return ioutil.WriteFile(filePath, []byte(fileContent), 0644)
|
||||
return ioutil.WriteFile(filePath, []byte(fileContent), 0644)
|
||||
}
|
||||
|
||||
// pemBlockForKey creates a PEM block for the given private key
|
||||
func pemBlockForKey(key *ecdsa.PrivateKey) ([]byte, error) {
|
||||
der, err := x509.MarshalECPrivateKey(key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal ECDSA private key: %w", err)
|
||||
}
|
||||
der, err := x509.MarshalECPrivateKey(key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal ECDSA private key: %w", err)
|
||||
}
|
||||
|
||||
block := &pem.Block{
|
||||
Type: "EC PRIVATE KEY",
|
||||
Bytes: der,
|
||||
}
|
||||
return pem.EncodeToMemory(block), nil
|
||||
block := &pem.Block{
|
||||
Type: "EC PRIVATE KEY",
|
||||
Bytes: der,
|
||||
}
|
||||
return pem.EncodeToMemory(block), nil
|
||||
}
|
||||
|
||||
// publicKeyToOpenSSH converts an ECDSA public key to OpenSSH format
|
||||
func publicKeyToOpenSSH(pub *ecdsa.PublicKey) (string, error) {
|
||||
pubKey, err := ssh.NewPublicKey(pub)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to convert ECDSA public key to SSH format: %w", err)
|
||||
}
|
||||
return string(ssh.MarshalAuthorizedKey(pubKey)), nil
|
||||
pubKey, err := ssh.NewPublicKey(pub)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to convert ECDSA public key to SSH format: %w", err)
|
||||
}
|
||||
return string(ssh.MarshalAuthorizedKey(pubKey)), nil
|
||||
}
|
||||
|
||||
// getKnownHostsEntry generates the known_hosts entry for the given URL
|
||||
func getKnownHostsEntry(url string) string {
|
||||
if url == "github.com" {
|
||||
return getGithubKnownHostsEntry()
|
||||
}
|
||||
return generateKnownHostsEntry(url)
|
||||
if url == "github.com" {
|
||||
return getGithubKnownHostsEntry()
|
||||
}
|
||||
return generateKnownHostsEntry(url)
|
||||
}
|
||||
|
||||
// getGithubKnownHostsEntry generates the known_hosts entry specifically for github.com
|
||||
func getGithubKnownHostsEntry() string {
|
||||
return "github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg="
|
||||
return "github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg="
|
||||
}
|
||||
|
||||
// generateKnownHostsEntry generates an SSH known_hosts entry for the given URL
|
||||
func generateKnownHostsEntry(url string) string {
|
||||
return fmt.Sprintf("%s ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=", url)
|
||||
return fmt.Sprintf("%s ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=", url)
|
||||
}
|
||||
|
||||
// encodeToBase64 encodes data to a base64 string
|
||||
func encodeToBase64(data []byte) string {
|
||||
return string(data)
|
||||
return string(data)
|
||||
}
|
||||
|
||||
// decodeBase64 decodes a base64 string
|
||||
func decodeBase64(data string) ([]byte, error) {
|
||||
return []byte(data), nil
|
||||
return []byte(data), nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user