WIP: Good progress on better sync
This commit is contained in:
parent
c67a9c84e4
commit
eb7abefc89
@ -4,6 +4,15 @@ repositories:
|
|||||||
url: oci://registry-1.docker.io/bitnamicharts
|
url: oci://registry-1.docker.io/bitnamicharts
|
||||||
|
|
||||||
releases:
|
releases:
|
||||||
|
- name: postgresql-server-2
|
||||||
|
chart: postgresql
|
||||||
|
repository: bitnami-oci
|
||||||
|
namespace: postgresql-server
|
||||||
|
version: latest
|
||||||
|
values:
|
||||||
|
- ./values/postgresql.yaml
|
||||||
|
secrets:
|
||||||
|
- ./secrets/postgresql.yaml
|
||||||
- name: postgresql-server
|
- name: postgresql-server
|
||||||
chart: postgresql
|
chart: postgresql
|
||||||
repository: bitnami-oci
|
repository: bitnami-oci
|
||||||
@ -25,4 +34,5 @@ clusters:
|
|||||||
- age16svfskd8x75g62f5uwpmgqzth52rr3wgv9m6rxchqv6v6kzmzf0qvhr2pk
|
- age16svfskd8x75g62f5uwpmgqzth52rr3wgv9m6rxchqv6v6kzmzf0qvhr2pk
|
||||||
provider: flux
|
provider: flux
|
||||||
releases:
|
releases:
|
||||||
|
- postgresql-server-2
|
||||||
- postgresql-server
|
- postgresql-server
|
||||||
|
@ -83,14 +83,14 @@ func Reconcile(definedWorkdirPath, sshKeyPath string, conf *config.Config, dry b
|
|||||||
sops := sopshelper.NewSops()
|
sops := sopshelper.NewSops()
|
||||||
|
|
||||||
for _, release := range conf.Releases {
|
for _, release := range conf.Releases {
|
||||||
release.InitRelease()
|
|
||||||
|
|
||||||
err := release.VersionHandler(workdirPath, hh)
|
err := release.VersionHandler(workdirPath, hh)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
release.ValuesHandler(configPath)
|
if err := release.ValuesHandler(configPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if err := release.SecretsHandler(configPath, sops); err != nil {
|
if err := release.SecretsHandler(configPath, sops); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -111,12 +111,12 @@ func Reconcile(definedWorkdirPath, sshKeyPath string, conf *config.Config, dry b
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
lockfile, err := diffReleases.Resolve(currentRepositories, clusterWorkdirPath)
|
lockfile, diffRepos, err := diffReleases.Resolve(currentRepositories, clusterWorkdirPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := provider.SyncState(*diffReleases); err != nil {
|
if err := provider.SyncState(diffReleases, diffRepos); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"git.badhouseplants.net/allanger/shoebill/pkg/repository"
|
"git.badhouseplants.net/allanger/shoebill/pkg/repository"
|
||||||
release_v2beta1 "github.com/fluxcd/helm-controller/api/v2beta1"
|
release_v2beta1 "github.com/fluxcd/helm-controller/api/v2beta1"
|
||||||
helmrepo_v1beta2 "github.com/fluxcd/source-controller/api/v1beta2"
|
helmrepo_v1beta2 "github.com/fluxcd/source-controller/api/v1beta2"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"sigs.k8s.io/yaml"
|
"sigs.k8s.io/yaml"
|
||||||
@ -34,51 +35,20 @@ func FluxProvider(path, sopsBin string, gh githelper.Githelper) Provider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: This function is ugly as hell, I need to do something about it
|
// TODO: This function is ugly as hell, I need to do something about it
|
||||||
func (f *Flux) SyncState(diff diff.Diff) error {
|
func (f *Flux) SyncState(releasesDiffs diff.ReleasesDiffs, repoDiffs diff.RepositoriesDiffs) error {
|
||||||
entity := "repository"
|
entity := "repository"
|
||||||
srcDirPath := fmt.Sprintf("%s/src", f.path)
|
srcDirPath := fmt.Sprintf("%s/src", f.path)
|
||||||
// It should containe either release or repository as a prefix, because it's how files are called
|
// It should containe either release or repository as a prefix, because it's how files are called
|
||||||
entiryFilePath := fmt.Sprintf("%s/%s-", srcDirPath, entity)
|
entiryFilePath := fmt.Sprintf("%s/%s-", srcDirPath, entity)
|
||||||
|
|
||||||
for _, repo := range diff.DeletedRepositories {
|
for _, repository := range repoDiffs {
|
||||||
if err := os.Remove(entiryFilePath + repo.Name + ".yaml"); err != nil {
|
switch repository.Action {
|
||||||
return err
|
case diff.ACTION_ADD:
|
||||||
}
|
manifest, err := GenerateRepository(repository.Wished)
|
||||||
|
|
||||||
message := `chore(repository): Removed a repo: %s
|
|
||||||
A repo has been removed from the cluster:
|
|
||||||
Name: %s
|
|
||||||
URL: %s
|
|
||||||
`
|
|
||||||
if err := f.gh.AddAllAndCommit(f.path, fmt.Sprintf(message, repo.Name, repo.Name, repo.URL)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, repo := range diff.UpdatedRepositories {
|
|
||||||
manifest, err := GenerateRepository(repo)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := os.WriteFile(entiryFilePath+repo.Name+".yaml", manifest, os.ModeExclusive); err != nil {
|
file, err := os.Create(entiryFilePath + repository.Wished.Name + ".yaml")
|
||||||
return err
|
|
||||||
}
|
|
||||||
message := `chore(repository): Update a repo: %s
|
|
||||||
|
|
||||||
A repo has been updated:
|
|
||||||
Name: %s
|
|
||||||
URL: %s
|
|
||||||
`
|
|
||||||
if err := f.gh.AddAllAndCommit(f.path, fmt.Sprintf(message, repo.Name, repo.Name, repo.URL)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, repo := range diff.AddedRepositories {
|
|
||||||
manifest, err := GenerateRepository(repo)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
file, err := os.Create(entiryFilePath + repo.Name + ".yaml")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -91,27 +61,67 @@ func (f *Flux) SyncState(diff diff.Diff) error {
|
|||||||
Name: %s
|
Name: %s
|
||||||
URL: %s
|
URL: %s
|
||||||
`
|
`
|
||||||
if err := f.gh.AddAllAndCommit(f.path, fmt.Sprintf(message, repo.Name, repo.Name, repo.URL)); err != nil {
|
if err := f.gh.AddAllAndCommit(f.path, fmt.Sprintf(message, repository.Wished.Name, repository.Wished.Name, repository.Wished.URL)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case diff.ACTION_PRESERVE:
|
||||||
|
case diff.ACTION_UPDATE:
|
||||||
|
manifest, err := GenerateRepository(repository.Wished)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := os.WriteFile(entiryFilePath+repository.Wished.Name+".yaml", manifest, os.ModeExclusive); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
message := `chore(repository): Update a repo: %s
|
||||||
|
|
||||||
|
A repo has been updated:
|
||||||
|
Name: %s
|
||||||
|
URL: %s
|
||||||
|
`
|
||||||
|
if err := f.gh.AddAllAndCommit(f.path, fmt.Sprintf(message, repository.Wished.Name, repository.Wished.Name, repository.Wished.URL)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
case diff.ACTION_DELETE:
|
||||||
|
if err := os.Remove(entiryFilePath + repository.Current.Name + ".yaml"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
message := `chore(repository): Removed a repo: %s
|
||||||
|
A repo has been removed from the cluster:
|
||||||
|
Name: %s
|
||||||
|
URL: %s
|
||||||
|
`
|
||||||
|
if err := f.gh.AddAllAndCommit(f.path, fmt.Sprintf(message, repository.Current.Name, repository.Current.Name, repository.Current.URL)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unknown action is requests: %s", repository.Action)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
entity = "release"
|
entity = "release"
|
||||||
entiryFilePath = fmt.Sprintf("%s/%s-", srcDirPath, entity)
|
entiryFilePath = fmt.Sprintf("%s/%s-", srcDirPath, entity)
|
||||||
|
for _, release := range releasesDiffs {
|
||||||
|
if err := SyncValues(release.Current, release.Wished, srcDirPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Added are simply copying all the values
|
if err := SyncSecrets(release.Current, release.Wished, f.path, f.sopsBin); err != nil {
|
||||||
for _, release := range diff.AddedReleases {
|
|
||||||
if err := SyncValues(release, srcDirPath); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := SyncSecrets(release, srcDirPath, f.path, f.sopsBin); err != nil {
|
|
||||||
return err
|
switch release.Action {
|
||||||
}
|
case diff.ACTION_ADD:
|
||||||
manifest, err := GenerateRelease(release)
|
manifest, err := GenerateRelease(release.Wished)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
file, err := os.Create(entiryFilePath + release.Release + ".yaml")
|
file, err := os.Create(entiryFilePath + release.Wished.Release + ".yaml")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
||||||
@ -127,24 +137,17 @@ func (f *Flux) SyncState(diff diff.Diff) error {
|
|||||||
Version: %s
|
Version: %s
|
||||||
Chart: %s/%s
|
Chart: %s/%s
|
||||||
`
|
`
|
||||||
if err := f.gh.AddAllAndCommit(f.path, fmt.Sprintf(message, release.Release, release.Release, release.Namespace, release.Version, release.Repository, release.Release)); err != nil {
|
if err := f.gh.AddAllAndCommit(f.path, fmt.Sprintf(message, release.Wished.Release, release.Wished.Release, release.Wished.Namespace, release.Wished.Version, release.Wished.Repository, release.Wished.Release)); err != nil {
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, release := range diff.UpdatedReleases {
|
|
||||||
SyncValues(release, srcDirPath)
|
|
||||||
|
|
||||||
if err := SyncSecrets(release, srcDirPath, f.path, f.sopsBin); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
manifest, err := GenerateRelease(release)
|
case diff.ACTION_UPDATE:
|
||||||
|
manifest, err := GenerateRelease(release.Wished)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.WriteFile(entiryFilePath+release.Release+".yaml", manifest, os.ModeExclusive); err != nil {
|
if err := os.WriteFile(entiryFilePath+release.Wished.Release+".yaml", manifest, os.ModeExclusive); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,34 +159,14 @@ func (f *Flux) SyncState(diff diff.Diff) error {
|
|||||||
Version: %s
|
Version: %s
|
||||||
Chart: %s/%s
|
Chart: %s/%s
|
||||||
`
|
`
|
||||||
if err := f.gh.AddAllAndCommit(f.path, fmt.Sprintf(message, release.Release, release.Release, release.Namespace, release.Version, release.Repository, release.Release)); err != nil {
|
if err := f.gh.AddAllAndCommit(f.path, fmt.Sprintf(message, release.Wished.Release, release.Wished.Release, release.Wished.Namespace, release.Wished.Version, release.Wished.Repository, release.Wished.Release)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for _, release := range diff.DeletedReleases {
|
case diff.ACTION_DELETE:
|
||||||
if err := os.Remove(entiryFilePath + release.Release + ".yaml"); err != nil {
|
if err := os.Remove(entiryFilePath + release.Current.Release + ".yaml"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
files, err := filepath.Glob(fmt.Sprintf("%s/values/%s*", srcDirPath, release.Release))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, f := range files {
|
|
||||||
if err := os.Remove(f); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
files, err = filepath.Glob(fmt.Sprintf("%s/secrets/%s*", srcDirPath, release.Release))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, f := range files {
|
|
||||||
if err := os.Remove(f); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
message := `chore(release): Remove a release: %s
|
message := `chore(release): Remove a release: %s
|
||||||
|
|
||||||
A release has been removed from the cluster:
|
A release has been removed from the cluster:
|
||||||
@ -192,10 +175,13 @@ func (f *Flux) SyncState(diff diff.Diff) error {
|
|||||||
Version: %s
|
Version: %s
|
||||||
Chart: %s/%s
|
Chart: %s/%s
|
||||||
`
|
`
|
||||||
if err := f.gh.AddAllAndCommit(f.path, fmt.Sprintf(message, release.Release, release.Release, release.Namespace, release.Version, release.Repository, release.Release)); err != nil {
|
if err := f.gh.AddAllAndCommit(f.path, fmt.Sprintf(message, release.Current.Release, release.Current.Release, release.Current.Namespace, release.Current.Version, release.Current.Repository, release.Current.Release)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unknown action is requests: %s", release.Action)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -248,7 +234,7 @@ func GenerateRelease(release *release.Release) ([]byte, error) {
|
|||||||
CRDs: release_v2beta1.Create,
|
CRDs: release_v2beta1.Create,
|
||||||
CreateNamespace: true,
|
CreateNamespace: true,
|
||||||
},
|
},
|
||||||
TargetNamespace: "release-namespace",
|
TargetNamespace: release.Namespace,
|
||||||
ValuesFrom: []release_v2beta1.ValuesReference{},
|
ValuesFrom: []release_v2beta1.ValuesReference{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -273,117 +259,141 @@ func GenerateRelease(release *release.Release) ([]byte, error) {
|
|||||||
return yaml.Marshal(&fluxRelease)
|
return yaml.Marshal(&fluxRelease)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SyncValues(release *release.Release, path string) error {
|
func SyncValues(currentRelease, wishedRelease *release.Release, secDirPath string) error {
|
||||||
for values := range release.DestValues {
|
valuesDirPath := fmt.Sprintf("%s/values", secDirPath)
|
||||||
|
if currentRelease != nil {
|
||||||
|
for _, value := range currentRelease.DestValues {
|
||||||
|
valuesFilePath := fmt.Sprintf("%s/%s", valuesDirPath, value.DestPath)
|
||||||
|
logrus.Infof("trying to remove values file: %s", valuesFilePath)
|
||||||
|
if err := os.RemoveAll(valuesFilePath); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
for _, valueFile := range release.Values {
|
}
|
||||||
|
}
|
||||||
|
if wishedRelease != nil {
|
||||||
|
for _, value := range wishedRelease.DestValues {
|
||||||
// Prepare a dir for values
|
// Prepare a dir for values
|
||||||
valuesPath := fmt.Sprintf("%s/%s", path, "values")
|
valuesPath := fmt.Sprintf("%s/%s", secDirPath, "values")
|
||||||
if err := os.Mkdir(valuesPath, os.ModePerm); err != nil {
|
valuesFilePath := fmt.Sprintf("%s/%s", valuesDirPath, value.DestPath)
|
||||||
|
logrus.Infof("trying to create values file: %s", valuesFilePath)
|
||||||
|
if err := os.MkdirAll(valuesPath, os.ModePerm); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
var valuesFile *os.File
|
||||||
destFileName := fmt.Sprintf("%s/%s-%s", valuesPath, release.Release, filepath.Base(valueFile))
|
if _, err := os.Stat(valuesFilePath); err == nil {
|
||||||
var dstValues *os.File
|
valuesFile, err = os.Open(valuesFilePath)
|
||||||
var srcValues *os.File
|
|
||||||
var err error
|
|
||||||
valueData, err := os.ReadFile(valueFile)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer srcValues.Close()
|
defer valuesFile.Close()
|
||||||
if _, err = os.Stat(destFileName); err == nil {
|
|
||||||
dstValues, err = os.Open(destFileName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer dstValues.Close()
|
|
||||||
} else if errors.Is(err, os.ErrNotExist) {
|
} else if errors.Is(err, os.ErrNotExist) {
|
||||||
dstValues, err = os.Create(destFileName)
|
valuesFile, err = os.Create(valuesFilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
defer dstValues.Close()
|
defer valuesFile.Close()
|
||||||
} else {
|
} else {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := os.WriteFile(destFileName, valueData, os.ModeExclusive); err != nil {
|
|
||||||
return nil
|
k8sConfigMapObj := corev1.ConfigMap{
|
||||||
|
TypeMeta: v1.TypeMeta{
|
||||||
|
Kind: "ConfigMap",
|
||||||
|
APIVersion: "v1",
|
||||||
|
},
|
||||||
|
ObjectMeta: v1.ObjectMeta{
|
||||||
|
Name: value.DestPath,
|
||||||
|
Namespace: "flux-system",
|
||||||
|
Labels: map[string]string{
|
||||||
|
"shoebill-release": wishedRelease.Release,
|
||||||
|
"shoebill-chart": wishedRelease.Chart,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Data: map[string]string{
|
||||||
|
value.DestPath: string(value.Data),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = io.Copy(dstValues, srcValues)
|
valuesFileData, err := yaml.Marshal(k8sConfigMapObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := os.WriteFile(valuesFilePath, valuesFileData, os.ModeAppend); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func SyncSecrets(release *release.Release, destPath, path, sopsBin string) error {
|
func SyncSecrets(currentRelease, wishedRelease *release.Release, workdirPath, sopsBin string) error {
|
||||||
secretsPath := fmt.Sprintf("%s/%s", destPath, "secrets")
|
secretsDirPath := fmt.Sprintf("%s/src/secrets", workdirPath)
|
||||||
|
if currentRelease != nil {
|
||||||
|
for _, secrets := range currentRelease.DestSecrets {
|
||||||
|
secretsFilePath := fmt.Sprintf("%s/%s", secretsDirPath, secrets.DestPath)
|
||||||
|
logrus.Infof("trying to remove secrets file: %s", secretsFilePath)
|
||||||
|
if err := os.RemoveAll(secretsFilePath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if wishedRelease != nil {
|
||||||
|
for _, secrets := range wishedRelease.DestSecrets {
|
||||||
// Prepare a dir for secrets
|
// Prepare a dir for secrets
|
||||||
if err := os.RemoveAll(secretsPath); err != nil {
|
secretsPath := fmt.Sprintf("%s/%s", workdirPath, "secrets")
|
||||||
|
secretsFilePath := fmt.Sprintf("%s/%s", secretsDirPath, secrets.DestPath)
|
||||||
|
logrus.Infof("trying to create secrets file: %s", secretsFilePath)
|
||||||
|
if err := os.MkdirAll(secretsPath, os.ModePerm); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := os.Mkdir(secretsPath, os.ModePerm); err != nil {
|
var secretsFile *os.File
|
||||||
return err
|
if _, err := os.Stat(secretsFilePath); err == nil {
|
||||||
}
|
secretsFile, err = os.Open(secretsFilePath)
|
||||||
|
|
||||||
for srcPath, data := range release.UnencryptedSecrets {
|
|
||||||
destFileName := fmt.Sprintf("%s/%s-%s", secretsPath, release.Release, filepath.Base(srcPath))
|
|
||||||
var dstSecrets *os.File
|
|
||||||
var err error
|
|
||||||
|
|
||||||
if _, err = os.Stat(destFileName); err == nil {
|
|
||||||
dstSecrets, err = os.Open(destFileName)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer dstSecrets.Close()
|
defer secretsFile.Close()
|
||||||
} else if errors.Is(err, os.ErrNotExist) {
|
} else if errors.Is(err, os.ErrNotExist) {
|
||||||
dstSecrets, err = os.Create(destFileName)
|
secretsFile, err = os.Create(secretsFilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
defer dstSecrets.Close()
|
defer secretsFile.Close()
|
||||||
} else {
|
} else {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
filename := fmt.Sprintf("%s-%s", release.Release, filepath.Base(srcPath))
|
|
||||||
k8sSecretObj := corev1.Secret{
|
k8sSecretObj := corev1.Secret{
|
||||||
TypeMeta: v1.TypeMeta{
|
TypeMeta: v1.TypeMeta{
|
||||||
Kind: "Secret",
|
Kind: "Secret",
|
||||||
APIVersion: "v1",
|
APIVersion: "v1",
|
||||||
},
|
},
|
||||||
ObjectMeta: v1.ObjectMeta{
|
ObjectMeta: v1.ObjectMeta{
|
||||||
Name: filename,
|
Name: secrets.DestPath,
|
||||||
Namespace: "flux-system",
|
Namespace: "flux-system",
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"shoebill-release": release.Release,
|
"shoebill-release": wishedRelease.Release,
|
||||||
"shoebill-chart": release.Chart,
|
"shoebill-chart": wishedRelease.Chart,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Data: map[string][]byte{
|
Data: map[string][]byte{
|
||||||
filename: data,
|
secrets.DestPath: secrets.Data,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
secretFile, err := yaml.Marshal(k8sSecretObj)
|
|
||||||
|
secretsFileData, err := yaml.Marshal(k8sSecretObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.WriteFile(destFileName, secretFile, os.ModeExclusive); err != nil {
|
if err := os.WriteFile(secretsFilePath, secretsFileData, os.ModeAppend); err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// I have to use the sops binary here, because they do not provide a go package that can be used for encryption :(
|
// I have to use the sops binary here, because they do not provide a go package that can be used for encryption :(
|
||||||
sopsConfPath := fmt.Sprintf("%s/.sops.yaml", path)
|
sopsConfPath := fmt.Sprintf("%s/.sops.yaml", workdirPath)
|
||||||
cmd := exec.Command(sopsBin, "--encrypt", "--in-place", "--config", sopsConfPath, destFileName)
|
cmd := exec.Command(sopsBin, "--encrypt", "--in-place", "--config", sopsConfPath, secretsFilePath)
|
||||||
stderr, err := cmd.StderrPipe()
|
stderr, err := cmd.StderrPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -399,5 +409,6 @@ func SyncSecrets(release *release.Release, destPath, path, sopsBin string) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Provider interface {
|
type Provider interface {
|
||||||
SyncState(diff diff.Diff) error
|
SyncState(diff.ReleasesDiffs, diff.RepositoriesDiffs) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProvider(provider, path, sopsBin string, gh githelper.Githelper) (Provider, error) {
|
func NewProvider(provider, path, sopsBin string, gh githelper.Githelper) (Provider, error) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package diff
|
package diff
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"git.badhouseplants.net/allanger/shoebill/pkg/lockfile"
|
"git.badhouseplants.net/allanger/shoebill/pkg/lockfile"
|
||||||
@ -9,138 +10,170 @@ import (
|
|||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Diff struct {
|
type ReleasesDiff struct {
|
||||||
AddedReleases release.Releases
|
Action string
|
||||||
DeletedReleases release.Releases
|
Current *release.Release
|
||||||
UpdatedReleases release.Releases
|
Wished *release.Release
|
||||||
PreservedReleases release.Releases
|
|
||||||
AddedRepositories repository.Repositories
|
|
||||||
DeletedRepositories repository.Repositories
|
|
||||||
UpdatedRepositories repository.Repositories
|
|
||||||
PreservedRepositories repository.Repositories
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ReleasesDiffs []*ReleasesDiff
|
||||||
|
|
||||||
|
type RepositoriesDiff struct {
|
||||||
|
Action string
|
||||||
|
Current *repository.Repository
|
||||||
|
Wished *repository.Repository
|
||||||
|
}
|
||||||
|
|
||||||
|
type RepositoriesDiffs []*RepositoriesDiff
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
ACTION_PRESERVE = "preserve"
|
||||||
ACTION_ADD = "add"
|
ACTION_ADD = "add"
|
||||||
ACTION_UPDATE = "update"
|
ACTION_UPDATE = "update"
|
||||||
ACTION_DELETE = "delete"
|
ACTION_DELETE = "delete"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO(@allanger): Naming should be better
|
// TODO(@allanger): Naming should be better
|
||||||
func DiffReleases(src, dest release.Releases) (*Diff, error) {
|
func DiffReleases(currentReleases, wishedReleases release.Releases) (ReleasesDiffs, error) {
|
||||||
diff := &Diff{}
|
newDiff := ReleasesDiffs{}
|
||||||
|
|
||||||
for _, rSrc := range src {
|
for _, currentRelease := range currentReleases {
|
||||||
found := false
|
found := false
|
||||||
for _, rDest := range dest {
|
for _, wishedRelease := range wishedReleases {
|
||||||
if rSrc.Release == rDest.Release {
|
if currentRelease.Release == wishedRelease.Release {
|
||||||
found = true
|
found = true
|
||||||
if reflect.DeepEqual(rSrc, rDest) {
|
if reflect.DeepEqual(currentRelease, wishedRelease) {
|
||||||
diff.PreservedReleases = append(diff.PreservedReleases, rSrc)
|
newDiff = append(newDiff, &ReleasesDiff{
|
||||||
|
Action: ACTION_PRESERVE,
|
||||||
|
Current: currentRelease,
|
||||||
|
Wished: wishedRelease,
|
||||||
|
})
|
||||||
|
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
if err := rDest.RepositoryObj.KindFromUrl(); err != nil {
|
if err := wishedRelease.RepositoryObj.KindFromUrl(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
diff.UpdatedReleases = append(diff.UpdatedReleases, rDest)
|
newDiff = append(newDiff, &ReleasesDiff{
|
||||||
|
Action: ACTION_UPDATE,
|
||||||
|
Current: currentRelease,
|
||||||
|
Wished: wishedRelease,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logrus.Info(rSrc.Release)
|
|
||||||
if !found {
|
if !found {
|
||||||
logrus.Info(rSrc.Release)
|
newDiff = append(newDiff, &ReleasesDiff{
|
||||||
|
Action: ACTION_DELETE,
|
||||||
|
Current: currentRelease,
|
||||||
|
Wished: nil,
|
||||||
|
})
|
||||||
|
|
||||||
// for i, entry := range lockFile {
|
|
||||||
// if entry.Release == rSrc.Release {
|
|
||||||
// lockFile[i] = lockFile[len(lockFile)-1]
|
|
||||||
// lockFile = lockFile[:len(lockFile)-1]
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
diff.DeletedReleases = append(diff.DeletedReleases, rSrc)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, rDest := range dest {
|
for _, wishedRelease := range wishedReleases {
|
||||||
found := false
|
found := false
|
||||||
for _, rSrc := range src {
|
for _, rSrc := range currentReleases {
|
||||||
if rSrc.Release == rDest.Release {
|
if rSrc.Release == wishedRelease.Release {
|
||||||
found = true
|
found = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
if err := rDest.RepositoryObj.KindFromUrl(); err != nil {
|
if err := wishedRelease.RepositoryObj.KindFromUrl(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
diff.AddedReleases = append(diff.AddedReleases, rDest)
|
newDiff = append(newDiff, &ReleasesDiff{
|
||||||
|
Action: ACTION_ADD,
|
||||||
|
Current: nil,
|
||||||
|
Wished: wishedRelease,
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return diff, nil
|
return newDiff, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (diff *Diff) Resolve(repositories repository.Repositories, path string) (lockfile.LockFile, error) {
|
func (diff ReleasesDiffs) Resolve(currentRepositories repository.Repositories, path string) (lockfile.LockFile, RepositoriesDiffs, error) {
|
||||||
lockfile := lockfile.LockFile{}
|
lockfile := lockfile.LockFile{}
|
||||||
reposWished := repository.Repositories{}
|
wishedRepos := repository.Repositories{}
|
||||||
|
repoDiffs := RepositoriesDiffs{}
|
||||||
|
|
||||||
for _, p := range diff.PreservedReleases {
|
for _, diff := range diff {
|
||||||
logrus.Infof("preserving %s", p.Release)
|
switch diff.Action {
|
||||||
lockfile = append(lockfile, p.LockEntry())
|
case ACTION_ADD:
|
||||||
reposWished = append(reposWished, p.RepositoryObj)
|
logrus.Infof("adding %s", diff.Wished.Release)
|
||||||
|
lockfile = append(lockfile, diff.Wished.LockEntry())
|
||||||
|
wishedRepos = append(wishedRepos, diff.Wished.RepositoryObj)
|
||||||
|
case ACTION_PRESERVE:
|
||||||
|
logrus.Infof("preserving %s", diff.Wished.Release)
|
||||||
|
lockfile = append(lockfile, diff.Wished.LockEntry())
|
||||||
|
wishedRepos = append(wishedRepos, diff.Wished.RepositoryObj)
|
||||||
|
case ACTION_UPDATE:
|
||||||
|
logrus.Infof("updating %s", diff.Wished.Release)
|
||||||
|
lockfile = append(lockfile, diff.Wished.LockEntry())
|
||||||
|
wishedRepos = append(wishedRepos, diff.Wished.RepositoryObj)
|
||||||
|
case ACTION_DELETE:
|
||||||
|
logrus.Infof("removing %s", diff.Current.Release)
|
||||||
|
default:
|
||||||
|
return nil, nil, fmt.Errorf("unknown action is requests: %s", diff.Action)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, a := range diff.AddedReleases {
|
|
||||||
logrus.Infof("adding %s", a.Release)
|
|
||||||
lockfile = append(lockfile, a.LockEntry())
|
|
||||||
reposWished = append(reposWished, a.RepositoryObj)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, u := range diff.UpdatedReleases {
|
|
||||||
logrus.Infof("updating %s", u.Release)
|
|
||||||
lockfile = append(lockfile, u.LockEntry())
|
|
||||||
reposWished = append(reposWished, u.RepositoryObj)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, d := range diff.DeletedReleases {
|
|
||||||
logrus.Infof("removing %s", d.Release)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Repo Wished is the list of all repos that are required by the current setup
|
// Repo Wished is the list of all repos that are required by the current setup
|
||||||
|
|
||||||
// Existing repos are all the repos in the lockfile
|
// Existing repos are all the repos in the lockfile
|
||||||
for _, repoExisting := range repositories {
|
for _, currentRepo := range currentRepositories {
|
||||||
found := false
|
found := false
|
||||||
i := 0
|
i := 0
|
||||||
for _, repoWished := range reposWished {
|
for _, wishedRepo := range wishedRepos {
|
||||||
// If there is the same repo in the wished repos and in the lockfile
|
// If there is the same repo in the wished repos and in the lockfile
|
||||||
// We need either to udpate, or preserve. If it can't be found, just remove
|
// We need either to udpate, or preserve. If it can't be found, just remove
|
||||||
// from the reposWished slice
|
// from the reposWished slice
|
||||||
if repoWished.Name == repoExisting.Name {
|
if wishedRepo.Name == currentRepo.Name {
|
||||||
// If !found, should be gone from the repo
|
// If !found, should be gone from the repo
|
||||||
found = true
|
found = true
|
||||||
if err := repoWished.ValidateURL(); err != nil {
|
if err := wishedRepo.ValidateURL(); err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
if err := repoWished.KindFromUrl(); err != nil {
|
if err := wishedRepo.KindFromUrl(); err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(reposWished, repoExisting) {
|
if !reflect.DeepEqual(wishedRepos, currentRepo) {
|
||||||
diff.UpdatedRepositories = append(diff.UpdatedRepositories, repoWished)
|
repoDiffs = append(repoDiffs, &RepositoriesDiff{
|
||||||
|
Action: ACTION_UPDATE,
|
||||||
|
Current: currentRepo,
|
||||||
|
Wished: wishedRepo,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
diff.PreservedRepositories = append(diff.PreservedRepositories, repoWished)
|
repoDiffs = append(repoDiffs, &RepositoriesDiff{
|
||||||
|
Action: ACTION_PRESERVE,
|
||||||
|
Current: currentRepo,
|
||||||
|
Wished: wishedRepo,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
// Delete the
|
|
||||||
} else {
|
} else {
|
||||||
reposWished[i] = repoWished
|
wishedRepos[i] = wishedRepo
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
reposWished = reposWished[:i]
|
wishedRepos = wishedRepos[:i]
|
||||||
if !found {
|
if !found {
|
||||||
diff.DeletedRepositories = append(diff.DeletedRepositories, repoExisting)
|
repoDiffs = append(repoDiffs, &RepositoriesDiff{
|
||||||
|
Action: ACTION_DELETE,
|
||||||
|
Current: currentRepo,
|
||||||
|
Wished: nil,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for _, addedRepo := range wishedRepos {
|
||||||
|
repoDiffs = append(repoDiffs, &RepositoriesDiff{
|
||||||
|
Action: ACTION_ADD,
|
||||||
|
Current: nil,
|
||||||
|
Wished: addedRepo,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
diff.AddedRepositories = append(diff.AddedRepositories, reposWished...)
|
return lockfile, repoDiffs, nil
|
||||||
|
|
||||||
return lockfile, nil
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package release
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
@ -30,9 +31,8 @@ type Release struct {
|
|||||||
Secrets []string
|
Secrets []string
|
||||||
// Private fields that should be pupulated during the run-time
|
// Private fields that should be pupulated during the run-time
|
||||||
RepositoryObj *repository.Repository `yaml:"-"`
|
RepositoryObj *repository.Repository `yaml:"-"`
|
||||||
UnencryptedSecrets map[string][]byte `yaml:"-"`
|
DestValues ValuesHolders `yaml:"-"`
|
||||||
DestValues []ValuesHolder `yaml:"-"`
|
DestSecrets ValuesHolders `yaml:"-"`
|
||||||
DestSecrets []string `yaml:"-"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ValuesHolder struct {
|
type ValuesHolder struct {
|
||||||
@ -41,12 +41,17 @@ type ValuesHolder struct {
|
|||||||
Data []byte
|
Data []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type Releases []*Release
|
type ValuesHolders []ValuesHolder
|
||||||
|
|
||||||
// Preare the release object
|
func (vhs ValuesHolders) ToStrings() []string {
|
||||||
func (r *Release) InitRelease() {
|
values := []string{}
|
||||||
r.UnencryptedSecrets = map[string][]byte{}
|
for _, vh := range vhs {
|
||||||
|
values = append(values, vh.DestPath)
|
||||||
}
|
}
|
||||||
|
return values
|
||||||
|
}
|
||||||
|
|
||||||
|
type Releases []*Release
|
||||||
|
|
||||||
// RepositoryObjFromName gather the whole repository object by its name
|
// RepositoryObjFromName gather the whole repository object by its name
|
||||||
func (r *Release) RepositoryObjFromName(repos repository.Repositories) error {
|
func (r *Release) RepositoryObjFromName(repos repository.Repositories) error {
|
||||||
@ -80,15 +85,21 @@ func (r *Release) VersionHandler(dir string, hh helmhelper.Helmhelper) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Release) ValuesHandler(dir string) {
|
func (r *Release) ValuesHandler(dir string) error {
|
||||||
for i := range r.Values {
|
for i := range r.Values {
|
||||||
r.Values[i] = fmt.Sprintf("%s/%s", dir, strings.ReplaceAll(r.Values[i], "./", ""))
|
r.Values[i] = fmt.Sprintf("%s/%s", dir, strings.ReplaceAll(r.Values[i], "./", ""))
|
||||||
destValues := fmt.Sprintf("%s-%s-%s", r.Namespace, r.Release, filepath.Base(r.Values[i]))
|
destValues := fmt.Sprintf("%s-%s-%s", r.Namespace, r.Release, filepath.Base(r.Values[i]))
|
||||||
|
valuesData, err := os.ReadFile(r.Values[i])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
r.DestValues = append(r.DestValues, ValuesHolder{
|
r.DestValues = append(r.DestValues, ValuesHolder{
|
||||||
SrcPath: r.Values[i],
|
SrcPath: r.Values[i],
|
||||||
DestPath: destValues,
|
DestPath: destValues,
|
||||||
|
Data: valuesData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Release) SecretsHandler(dir string, sops sopshelper.SopsHelper) error {
|
func (r *Release) SecretsHandler(dir string, sops sopshelper.SopsHelper) error {
|
||||||
@ -99,8 +110,11 @@ func (r *Release) SecretsHandler(dir string, sops sopshelper.SopsHelper) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
destSecrets := fmt.Sprintf("%s-%s-%s", r.Namespace, r.Release, filepath.Base(r.Secrets[i]))
|
destSecrets := fmt.Sprintf("%s-%s-%s", r.Namespace, r.Release, filepath.Base(r.Secrets[i]))
|
||||||
r.DestSecrets = append(r.DestSecrets, destSecrets)
|
r.DestSecrets = append(r.DestSecrets, ValuesHolder{
|
||||||
r.UnencryptedSecrets[path] = res
|
SrcPath: path,
|
||||||
|
DestPath: destSecrets,
|
||||||
|
Data: res,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -153,8 +167,8 @@ func (r *Release) LockEntry() *lockfile.LockEntry {
|
|||||||
Namespace: r.Namespace,
|
Namespace: r.Namespace,
|
||||||
RepoUrl: r.RepositoryObj.URL,
|
RepoUrl: r.RepositoryObj.URL,
|
||||||
RepoName: r.RepositoryObj.Name,
|
RepoName: r.RepositoryObj.Name,
|
||||||
Values: r.DestValues,
|
Values: r.DestValues.ToStrings(),
|
||||||
Secrets: r.DestSecrets,
|
Secrets: r.DestSecrets.ToStrings(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user