diff --git a/.sops.yaml b/.sops.yaml new file mode 100644 index 0000000..bae22e0 --- /dev/null +++ b/.sops.yaml @@ -0,0 +1,5 @@ +creation_rules: + - path_regex: examples/.*.yaml + key_groups: + - age: + - age1htrz6hfc29ww5mypa3hy3ds6558ydgjletsrahj3h3mrgc2xgcwqpe2c7p diff --git a/README.md b/README.md index c4c3b00..2c557fe 100644 --- a/README.md +++ b/README.md @@ -2,3 +2,19 @@ A templater for the gitops setup +## Age keys for development + +### Source + +``` +# created: 2024-07-25T16:12:51+02:00 +# public key: age1htrz6hfc29ww5mypa3hy3ds6558ydgjletsrahj3h3mrgc2xgcwqpe2c7p +AGE-SECRET-KEY-1SZRD3TU328L8LHZGNT6WTG6J5GPSJS693CD5P9ZCKD3776DNG5HQ54Y0NF +``` + +### Destination +``` +# created: 2024-07-25T16:13:14+02:00 +# public key: age1hcpgy4yy4psp6y2jt8waemzgg7crtlpxf3a48l6jvl6zmxll3vjsxj75vu +AGE-SECRET-KEY-1SXVFW2PM6WDC2P68EZQ4L2MVVQHC337FDRCRNLNJA4UAK82ATDFSKNG9PV +``` diff --git a/cmd/root.go b/cmd/root.go deleted file mode 100644 index 7ccfc00..0000000 --- a/cmd/root.go +++ /dev/null @@ -1,47 +0,0 @@ -package cmd - -import ( - "context" - "fmt" - "os" - - "git.badhouseplants.net/allanger/shoebill/internal/build" - "github.com/spf13/cobra" -) - -var fullVersion = fmt.Sprintf("%s - %s", build.Version, build.CommitHash) -var longDescription = `--- -shoebill is just GitOps with a glottal T - -It's a tool that is supposed to help engineers follow the GitOps practies - without fighting with GitOps being inapplicable to the real world. - -Yeah, I quite hate this GitOps obsession, but since it's already there, - I think it makes sense to make it work. - ---- -Information about the build: -Version: %s (build on %s) - ---- -` - -var ( - rootCmd = &cobra.Command{ - Use: "shoebill", - Short: "shoebill – GitOps without pain, kinda", - Long: fmt.Sprintf(longDescription, fullVersion, build.BuildTime), - SilenceErrors: true, - SilenceUsage: true, - Version: build.Version, - } -) - -func Execute(ctx context.Context) error { - rootCmd.PersistentFlags().Bool("server", false, "Set to true, if you want to start it in the deamon mode") - if err := rootCmd.ExecuteContext(ctx); err != nil { - fmt.Fprintf(os.Stderr, "Whoops. There was an error while executing your CLI '%s'", err) - os.Exit(1) - } - return nil -} diff --git a/cmd/sync.go b/cmd/sync.go deleted file mode 100644 index 589d626..0000000 --- a/cmd/sync.go +++ /dev/null @@ -1,52 +0,0 @@ -package cmd - -import ( - "git.badhouseplants.net/allanger/shoebill/internal/controller" - "github.com/sirupsen/logrus" - "github.com/spf13/cobra" -) - -var ( - sync = &cobra.Command{ - Use: "sync", - Short: "sync does something", - Long: ``, - Run: syncCmd, - } -) - -func init() { - sync.Flags().StringP("config", "c", "config.yaml", "A path to the configuration file") - sync.Flags().String("workdir", "", "A path to the workdir. On the moment of running, it should be an empty dir") - sync.Flags().String("ssh-key", "", "A path to the pricate ssh key") - sync.Flags().Bool("dry-run", false, "If set to false, will not push changes to git") - sync.Flags().String("diff", "main", "If values us set, will show helm diffs for not preserved charts, values will be taken from the target branch") - sync.Flags().String("sops-bin", "/usr/bin/sops", "A path to the sops binary in your system") - - rootCmd.AddCommand(sync) -} - -func syncCmd(cmd *cobra.Command, args []string) { - config := cmd.Flag("config").Value.String() - workdir := cmd.Flag("workdir").Value.String() - sshKey := cmd.Flag("ssh-key").Value.String() - sopsBin := cmd.Flag("sops-bin").Value.String() - dryRun, err := cmd.Flags().GetBool("dry-run") - diff, err := cmd.Flags().GetString("diff") - if err != nil { - logrus.Fatal(err) - } - - configObj, err := controller.ReadTheConfig(config) - if err != nil { - logrus.Fatal(err) - } - configObj.SopsBin = sopsBin - - err = controller.Sync(workdir, sshKey, configObj, dryRun, diff) - if err != nil { - logrus.Fatal(err) - } - - logrus.Info("your config is synced") -} diff --git a/examples/merge-files/giops.config.yaml b/examples/merge-files/giops.config.yaml deleted file mode 100644 index 82a4de6..0000000 --- a/examples/merge-files/giops.config.yaml +++ /dev/null @@ -1,28 +0,0 @@ ---- -import: - - ./repos-oci.yaml - - ./repos.yaml -repos: - - name: jetstack - url: https://charts.jetstack.io - - name: bitnami-oci - url: oci://registry-1.docker.io/bitnamicharts - -releases: - - name: cert-manager - chart: jetstack - repo: jetstack - version: latest - namespace: cert-manager - - name: postgresql-server - chart: postgresql - repo: bitnami-oci - namespace: postgresql-server - version: latest - -clusters: - - name: cluster-1 - git: git@git.badhouseplants.net:giant-swarm-task/cluster-1.git - releases: - - cert-manager - - postgresql-server diff --git a/examples/merge-files/repos-oci.yaml b/examples/merge-files/repos-oci.yaml deleted file mode 100644 index f2791d9..0000000 --- a/examples/merge-files/repos-oci.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -repos: - - name: bitnami-oci - url: oci://registry-1.docker.io/bitnamicharts diff --git a/examples/merge-files/repos.yaml b/examples/merge-files/repos.yaml deleted file mode 100644 index 07bf8fa..0000000 --- a/examples/merge-files/repos.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -repos: - - name: jetstack - url: https://charts.jetstack.io diff --git a/examples/one-config/.sops.yaml b/examples/one-config/.sops.yaml deleted file mode 100644 index 613e3a4..0000000 --- a/examples/one-config/.sops.yaml +++ /dev/null @@ -1,5 +0,0 @@ -creation_rules: - - path_regex: secrets/.*.yaml - key_groups: - - age: - - age16svfskd8x75g62f5uwpmgqzth52rr3wgv9m6rxchqv6v6kzmzf0qvhr2pk diff --git a/examples/one-config/giops.config.yaml b/examples/one-config/giops.config.yaml deleted file mode 100644 index 676fd18..0000000 --- a/examples/one-config/giops.config.yaml +++ /dev/null @@ -1,38 +0,0 @@ ---- -repositories: - - name: bitnami-oci - url: oci://registry-1.docker.io/bitnamicharts - -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 - chart: postgresql - repository: bitnami-oci - namespace: postgresql-server - version: latest - values: - - ./values/postgresql.yaml - secrets: - - ./secrets/postgresql.yaml - -clusters: - - name: cluster-shoebill-test - git: git@git.badhouseplants.net:allanger/shoebill-test.git - dotsops: | - creation_rules: - - path_regex: secrets/.*.yaml - key_groups: - - age: - - age16svfskd8x75g62f5uwpmgqzth52rr3wgv9m6rxchqv6v6kzmzf0qvhr2pk - provider: flux - releases: - - postgresql-server-2 - - postgresql-server diff --git a/examples/one-config/helmfile.yaml b/examples/one-config/helmfile.yaml deleted file mode 100644 index 1432ced..0000000 --- a/examples/one-config/helmfile.yaml +++ /dev/null @@ -1,140 +0,0 @@ ---- -repositories: - - name: fluxcd-community - url: https://fluxcd-community.github.io/helm-charts - - -releases: - # --------------------------------- - # -- FLUX - # --------------------------------- - - name: flux - namespace: flux-system - installed: true - createNamespace: true - chart: fluxcd-community/flux2 - - - <<: *metrics-server - installed: true - namespace: kube-system - createNamespace: false - - - <<: *istio-base - installed: true - namespace: istio-system - createNamespace: false - - - <<: *istio-gateway - installed: true - namespace: istio-system - createNamespace: false - - - <<: *istiod - installed: true - namespace: istio-system - createNamespace: false - - - <<: *cert-manager - installed: true - namespace: cert-manager - createNamespace: false - - - <<: *minio - installed: true - namespace: minio-service - createNamespace: false - - - <<: *openvpn - installed: true - namespace: openvpn-service - createNamespace: false - - - <<: *metallb - installed: true - namespace: metallb-system - createNamespace: true - - - <<: *drone - installed: true - namespace: drone-service - createNamespace: false - - - <<: *drone-runner-docker - installed: true - namespace: drone-service - createNamespace: false - - - <<: *longhorn - installed: true - namespace: longhorn-system - createNamespace: false - - - <<: *argocd - installed: true - namespace: argo-system - createNamespace: false - - - <<: *nrodionov - installed: true - namespace: nrodionov-application - createNamespace: false - - - <<: *minecraft - installed: true - namespace: minecraft-application - createNamespace: false - - - <<: *gitea - installed: true - namespace: gitea-service - createNamespace: false - - - <<: *funkwhale - installed: true - namespace: funkwhale-application - createNamespace: false - - - <<: *prometheus - installed: true - namespace: monitoring-system - createNamespace: true - - - <<: *loki - installed: false - namespace: monitoring-system - createNamespace: false - - - <<: *promtail - installed: false - namespace: monitoring-system - createNamespace: false - - - <<: *bitwarden - installed: true - namespace: bitwarden-application - createNamespace: true - - - <<: *redis - installed: true - namespace: database-service - createNamespace: true - - - <<: *postgres16 - installed: true - namespace: database-service - createNamespace: true - - - <<: *db-operator - installed: true - namespace: database-service - createNamespace: true - - - <<: *db-instances - installed: true - namespace: database-service - createNamespace: true - - - <<: *mysql - installed: true - namespace: database-service - createNamespace: true diff --git a/examples/one-config/keys.txt b/examples/one-config/keys.txt deleted file mode 100644 index bd734b9..0000000 --- a/examples/one-config/keys.txt +++ /dev/null @@ -1,3 +0,0 @@ -# created: 2023-09-25T10:45:28+02:00 -# public key: age16svfskd8x75g62f5uwpmgqzth52rr3wgv9m6rxchqv6v6kzmzf0qvhr2pk -AGE-SECRET-KEY-1Y3FGYSHKWSSZ3G8DJ3QD7WKE5J0TTYDWSSD95EXL4A308ZWW0L9SN99ASP diff --git a/examples/one-config/secrets/postgresql.yaml b/examples/one-config/secrets/postgresql.yaml deleted file mode 100644 index f76d3ad..0000000 --- a/examples/one-config/secrets/postgresql.yaml +++ /dev/null @@ -1,24 +0,0 @@ -global: - postgresql: - auth: - password: ENC[AES256_GCM,data:5QV6a1A=,iv:utR62wuLTzwihVwXXPw8DA2Ul7kfU1YgAKteRA+WKm0=,tag:EYuIa6TDmxaR0PSuaJBeBA==,type:str] -sops: - kms: [] - gcp_kms: [] - azure_kv: [] - hc_vault: [] - age: - - recipient: age16svfskd8x75g62f5uwpmgqzth52rr3wgv9m6rxchqv6v6kzmzf0qvhr2pk - enc: | - -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA2SUJpdUtYWjF3K1dzbGc3 - Z2U0UDVpWmVkYXVvT1V3UWVDM2VTQ1hBU1RBCmFZMlI4ZWxWTTdCd05lVFVCN2hN - QkZKRmlFVStXT2kxSVlUNmU0VkZCUDQKLS0tIEQ2aXZ0ZDVXcGc4RE1WMmtOaTV3 - TDloa0dHTFhyUWhid1V0aEFydmtQbU0Kwkw914se9cGEN4FKNphuJErdC1QlYqRQ - +CInCnoy8m0/MZNhehZ/JVReEys6KDNxJ7RhnoRfs7P7wfAgBg984A== - -----END AGE ENCRYPTED FILE----- - lastmodified: "2023-10-11T11:13:13Z" - mac: ENC[AES256_GCM,data:olaWkaoqqoStswMNNUY6IljoriMgpWxhQ4f0AiRkiujat7ySjuUlS/gwBO1FQp+iB1XGnZKznOWDmZn8XEoFY6q+2dgrtA+h5fTI/EshPgX8xONsGH25Chhg2ER1FMKj8jOYEzxSJfW9s3oKyFGXAH/OgLMpZBkq2uc+eM83J2w=,iv:3fs4BEeFuWU2Nd8yC9iM89a6sz11izIfx3fLI5+1eJU=,tag:Y6ESSNnm2t9zGHG57qrQaQ==,type:str] - pgp: [] - unencrypted_suffix: _unencrypted - version: 3.8.0 diff --git a/examples/one-config/values/postgresql.yaml b/examples/one-config/values/postgresql.yaml deleted file mode 100644 index 36f8d8b..0000000 --- a/examples/one-config/values/postgresql.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -global: - postgresql: - auth: - username: check - database: check diff --git a/examples/secrets.postgres.yaml b/examples/secrets.postgres.yaml new file mode 100644 index 0000000..0e5e1ac --- /dev/null +++ b/examples/secrets.postgres.yaml @@ -0,0 +1,24 @@ +global: + postgresql: + auth: + postgresPassword: ENC[AES256_GCM,data:PC+kyanM5L3/ztbA+LY=,iv:LEKwP9iImZdZ+TBfRrgkkwGefFFwSnWmxAWRoTgfzyE=,tag:YkxzpTwV6Dp4onPLmKBWdQ==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1htrz6hfc29ww5mypa3hy3ds6558ydgjletsrahj3h3mrgc2xgcwqpe2c7p + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBWTzFhdHZ6dDNnN3pGRU1V + b0NjWFpwZkRnZUhNMjEra2dsbGZMV1M3NTBrCm9nTnZ6aUpJOXMwN3NDME9XdStL + Y2dJQ1E5TDl0T2JuZFhuSmxVUU9Sd2cKLS0tIEV3KzU1M20zdFVPOGFibTVHVDM5 + YXUzdDl1WDlBeno3OHBDN0FqeVdFM0EKtEWO6z5zPK5kEoRqyNovxW67bdxc2evZ + 9EzpmzIjwVoW91Ji7CPO4so12SPd0fqZ1C2sOr8KHf6v88oWknTmTQ== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2024-07-25T15:20:34Z" + mac: ENC[AES256_GCM,data:8qvcmX0WeROQEiQkkoFk+mY8Ze0sePKLmCKeDwBqvLge/c3oDXzWf07qMmiErDxWtCME9eQpzZkjC9dTvBgYYpfHz24cBfoH4swlXkhPbk26iKYXQIOK1+1SSf6rtsmFjkjylmM1u4yRXuwJZ8pGCu5av1h0edo5jMJLWBS78cA=,iv:OImdF6MvYSliA/OapIGtIX3pbvUFKgfvNCQYBQmwwVc=,tag:qos90QWOn2p5QOZLZMtoOw==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.9.0 diff --git a/examples/values-config/shoebill.config.yaml b/examples/values-config/shoebill.config.yaml deleted file mode 100644 index a083bed..0000000 --- a/examples/values-config/shoebill.config.yaml +++ /dev/null @@ -1,20 +0,0 @@ ---- -repositories: - - name: bitnami-oci - url: oci://registry-1.docker.io/bitnamicharts - -releases: - - name: postgresql-server - chart: postgresql - repository: bitnami-oci - namespace: postgresql-server - version: latest - values: - - ./values/postgresql.yaml - -clusters: - - name: cluster-shoebill-test - git: git@git.badhouseplants.net:allanger/shoebill-test.git - provider: flux - releases: - - postgresql-server diff --git a/examples/values.postgres.yaml b/examples/values.postgres.yaml new file mode 100644 index 0000000..786c146 --- /dev/null +++ b/examples/values.postgres.yaml @@ -0,0 +1,12 @@ + +architecture: standalone + +auth: + database: postgres + +primary: + persistence: + size: 1Gi + +metrics: + enabled: false diff --git a/go.mod b/go.mod index e2b08b2..06dd455 100644 --- a/go.mod +++ b/go.mod @@ -9,13 +9,16 @@ replace ( ) require ( + github.com/alecthomas/kong v0.9.0 github.com/fluxcd/helm-controller/api v0.35.0 github.com/fluxcd/source-controller/api v1.0.1 github.com/getsops/sops/v3 v3.8.0 github.com/go-git/go-git/v5 v5.8.1 + github.com/go-logr/logr v1.2.4 + github.com/go-logr/zapr v1.2.4 github.com/sirupsen/logrus v1.9.3 - github.com/spf13/cobra v1.7.0 github.com/stretchr/testify v1.8.4 + go.uber.org/zap v1.24.0 gopkg.in/yaml.v2 v2.4.0 helm.sh/helm/v3 v3.12.2 k8s.io/api v0.29.0-alpha.0 @@ -93,7 +96,6 @@ require ( github.com/go-git/go-billy/v5 v5.4.1 // indirect github.com/go-gorp/gorp/v3 v3.0.5 // indirect github.com/go-jose/go-jose/v3 v3.0.0 // indirect - github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect @@ -176,6 +178,7 @@ require ( github.com/shopspring/decimal v1.3.1 // indirect github.com/skeema/knownhosts v1.2.0 // indirect github.com/spf13/cast v1.5.0 // indirect + github.com/spf13/cobra v1.7.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/urfave/cli v1.22.14 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect @@ -187,6 +190,8 @@ require ( go.opentelemetry.io/otel v1.14.0 // indirect go.opentelemetry.io/otel/trace v1.14.0 // indirect go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect + go.uber.org/atomic v1.10.0 // indirect + go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.13.0 // indirect golang.org/x/mod v0.10.0 // indirect golang.org/x/net v0.15.0 // indirect diff --git a/go.sum b/go.sum index 805acdb..e7e29d1 100644 --- a/go.sum +++ b/go.sum @@ -96,6 +96,10 @@ github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/O github.com/a8m/expect v1.0.0/go.mod h1:4IwSCMumY49ScypDnjNbYEjgVeqy1/U2cEs3Lat96eA= github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ= github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= +github.com/alecthomas/assert/v2 v2.6.0 h1:o3WJwILtexrEUk3cUVal3oiQY2tfgr/FHWiz/v2n4FU= +github.com/alecthomas/kong v0.9.0 h1:G5diXxc85KvoV2f0ZRVuMsi45IrBgx9zDNGNj165aPA= +github.com/alecthomas/kong v0.9.0/go.mod h1:Y47y5gKfHp1hDc7CH7OeXgLIpp+Q2m1Ni0L5s3bI8Os= +github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= @@ -134,6 +138,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.21.5 h1:CQBFElb0LS8RojMJlxRSo/HXipvT github.com/aws/aws-sdk-go-v2/service/sts v1.21.5/go.mod h1:VC7JDqsqiwXukYEDjoHh9U0fOJtNWh04FPQz4ct4GGU= github.com/aws/smithy-go v1.14.2 h1:MJU9hqBGbvWZdApzpvoF2WAIJDbtjK2NDJSiJP7HblQ= github.com/aws/smithy-go v1.14.2/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -276,6 +282,8 @@ github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= +github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= @@ -453,6 +461,7 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/vault/api v1.10.0 h1:/US7sIjWN6Imp4o/Rj1Ce2Nr5bki/AXi9vAW3p2tOJQ= github.com/hashicorp/vault/api v1.10.0/go.mod h1:jo5Y/ET+hNyz+JnKDt8XLAdKs+AM0G5W0Vp1IrFI8N8= +github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= @@ -773,10 +782,18 @@ go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93V go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -1063,6 +1080,7 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 07ac36b..06ab203 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -1,6 +1,7 @@ package controller import ( + "context" "fmt" "path/filepath" @@ -24,51 +25,49 @@ func ReadTheConfig(path string) (*config.Config, error) { return conf, nil } -// func cloneSnapshoot(gh githelper.Githelper, snapshotDir, snapshotBranch string) error { - // if err := gh.CloneRepo(snapshotBranch, snapshotUrl, false); err != nil { - // return err - // } - // return nil -// } +type SyncOptions struct { + Workdir string + SSHKey string + Dry bool + Config *config.Config + SopsBin string +} -func Sync(definedWorkdirPath, sshKeyPath string, conf *config.Config, dry bool, diffArg string) error { +type SyncController struct{} + +func Sync(ctx context.Context, opts *SyncOptions) error { // Start by creating a directory where everything should be happening - configPath := filepath.Dir(conf.ConfigPath) - workdirPath, err := workdir.CreateWorkdir(definedWorkdirPath) - if err != nil { - return err - } - + configPath := filepath.Dir(opts.Config.ConfigPath) // Prepare helm repositories - for _, repository := range conf.Repositories { + for _, repository := range opts.Config.Repositories { if err := repository.KindFromUrl(); err != nil { return err } } // Configure a git client - gh := githelper.NewGit(sshKeyPath) + gh := githelper.NewGit(opts.SSHKey) // if len(diffArg) > 0 { - // snapshotDir := fmt.Sprint("%s/.snapshot", workdirPath) - // cloneSnapshoot(gh, snapshotDir, diffArg) + // snapshotDir := fmt.Sprint("%s/.snapshot", workdirPath) + // cloneSnapshoot(gh, snapshotDir, diffArg) // } // The main logic starts here - for _, cluster := range conf.Clusters { + for _, cluster := range opts.Config.Clusters { // Create a dir for the cluster git repo - clusterWorkdirPath := fmt.Sprintf("%s/%s", workdirPath, cluster.Name) + clusterWorkdirPath := fmt.Sprintf("%s/%s", opts.Workdir, cluster.Name) // Init a gitops provider (Currently onle flux is supported) - provider, err := providers.NewProvider(cluster.Provider, clusterWorkdirPath, conf.SopsBin, gh) + provider, err := providers.NewProvider(cluster.Provider, clusterWorkdirPath, opts.SopsBin, gh) if err != nil { return err } - if err := cluster.CloneRepo(gh, clusterWorkdirPath, dry); err != nil { + if err := cluster.CloneRepo(gh, clusterWorkdirPath, opts.Dry); err != nil { return err } - if err := cluster.BootstrapRepo(gh, clusterWorkdirPath, dry); err != nil { + if err := cluster.BootstrapRepo(gh, clusterWorkdirPath, opts.Dry); err != nil { return err } @@ -83,7 +82,7 @@ func Sync(definedWorkdirPath, sshKeyPath string, conf *config.Config, dry bool, return err } - if err := conf.Releases.PopulateRepositories(conf.Repositories); err != nil { + if err := opts.Config.Releases.PopulateRepositories(opts.Config.Repositories); err != nil { return err } @@ -93,23 +92,12 @@ func Sync(definedWorkdirPath, sshKeyPath string, conf *config.Config, dry bool, // Init the sops client sops := sopshelper.NewSops() - for _, release := range conf.Releases { - err := release.VersionHandler(workdirPath, hh) + for _, release := range opts.Config.Releases { + err := release.VersionHandler(opts.Workdir, hh) if err != nil { return err } - if len(diffArg) > 0 { - _, err := hh.PullChart(workdirPath, release.ToHelmReleaseData()) - if err != nil { - return err - } - if err := hh.RenderChart(workdirPath, release.ToHelmReleaseData()); err != nil { - return err - } - - } - if err := release.ValuesHandler(configPath); err != nil { return err } @@ -119,20 +107,14 @@ func Sync(definedWorkdirPath, sshKeyPath string, conf *config.Config, dry bool, } } - releaseObj := release.FindReleaseByNames(cluster.Releases, conf.Releases) + releaseObj := release.FindReleaseByNames(cluster.Releases, opts.Config.Releases) cluster.PopulateReleases(releaseObj) - releasesCurrent, err := release.ReleasesFromLockfile(lockfileData, conf.Repositories) + releasesCurrent, err := release.ReleasesFromLockfile(lockfileData, opts.Config.Repositories) if err != nil { return err } - if len(diffArg) > 0 { - for _, releaseCurrent := range releasesCurrent { - hh.PullChart(workdirPath, releaseCurrent.ToHelmReleaseData()) - } - } - // Compare releases from the lockfile to ones from the current cluster config diffReleases, err := diff.DiffReleases(releasesCurrent, cluster.ReleasesObj) if err != nil { @@ -161,15 +143,15 @@ func Sync(definedWorkdirPath, sshKeyPath string, conf *config.Config, dry bool, if _, err := gh.AddAllAndCommit(clusterWorkdirPath, "Update the lockfile"); err != nil { return err } - if !dry { + if !opts.Dry { if err := gh.Push(clusterWorkdirPath); err != nil { return err } } } - if !dry { - if err := workdir.RemoveWorkdir(workdirPath); err != nil { + if !opts.Dry { + if err := workdir.RemoveWorkdir(opts.Workdir); err != nil { return err } } diff --git a/internal/utils/workdir/workdir.go b/internal/utils/workdir/workdir.go index 55ab37b..5d3705e 100644 --- a/internal/utils/workdir/workdir.go +++ b/internal/utils/workdir/workdir.go @@ -1,9 +1,19 @@ package workdir -import "os" +import ( + "context" + "os" -func CreateWorkdir(path string) (workdir string, err error) { + "github.com/go-logr/logr" +) + +func CreateWorkdir(ctx context.Context, path string) (workdir string, err error) { + log, err := logr.FromContext(ctx) + if err != nil { + return "", err + } if len(path) > 0 { + log.Info("Creating a new directory", "path", path) // Create a dir using the path if err := os.Mkdir(path, 0777); err != nil { return path, err @@ -11,6 +21,7 @@ func CreateWorkdir(path string) (workdir string, err error) { // TODO(@allanger): I've got a feeling that it doesn't have to look that bad workdir = path } else { + log.Info("Path is not set, creating a temporary directory") // Create a temporary dir workdir, err = os.MkdirTemp("", "shoebill") if err != nil { diff --git a/main.go b/main.go index d26347f..59285b1 100644 --- a/main.go +++ b/main.go @@ -2,14 +2,82 @@ package main import ( "context" + "fmt" - "git.badhouseplants.net/allanger/shoebill/cmd" - "github.com/sirupsen/logrus" + "git.badhouseplants.net/allanger/shoebill/internal/controller" + "git.badhouseplants.net/allanger/shoebill/internal/utils/workdir" + "github.com/alecthomas/kong" + "github.com/go-logr/logr" + "github.com/go-logr/zapr" + "go.uber.org/zap" ) -func main() { - ctx := context.Background() - if err := cmd.Execute(ctx); err != nil { - logrus.Fatal(err) - } +type Sync struct { + Config string `short:"c" default:"config.yaml" help:"A path to the configuration file"` + Workdir string `short:"w" default:"" help:"A path to a workdir"` + SshKey string `help:"A path to the ssh key that should be used for git operations"` + DryRun bool `help:"Run the generation without pushing to repos"` + SopsBin string `default:"/usr/bin/sops" help:"A path to the sops binary"` +} + +var CLI struct { + Sync Sync `cmd:"" help:"Sync gitops configs"` +} + +func main() { + var log logr.Logger + zapLog, err := zap.NewDevelopment() + if err != nil { + panic(fmt.Sprintf("who watches the watchmen (%v)?", err)) + } + log = zapr.NewLogger(zapLog) + + ctx := logr.NewContext(context.Background(), log) + cmd := kong.Parse(&CLI) + switch cmd.Command() { + case "sync": + if err := syncCmd(ctx, CLI.Sync); err != nil { + log.Error(err, "Error occured during the execution") + } + default: + panic(cmd.Command()) + } + +} + +func syncCmd(ctx context.Context, args Sync) error { + log, err := logr.FromContext(ctx) + if err != nil { + return err + } + log.Info("Setting up the sync command") + + log.Info("Trying to read the config file", "path", args.Config) + configObj, err := controller.ReadTheConfig(args.Config) + if err != nil { + log.Error(err, "Couldn't read the config file") + return err + } + + log.Info("Preparing the workdir") + workdirPath, err := workdir.CreateWorkdir(ctx, args.Workdir) + if err != nil { + log.Error(err, "Couldn't prepare a working directory") + return err + } + + syncOptions := &controller.SyncOptions{ + SSHKey: args.SshKey, + Dry: args.DryRun, + Config: configObj, + Workdir: workdirPath, + SopsBin: args.SopsBin, + } + + if err := controller.Sync(ctx, syncOptions); err != nil { + log.Error(err, "Couldn't sync the config") + return err + } + + return nil } diff --git a/pkg/config/config.go b/pkg/config/config.go index 1493b14..e98dfce 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -6,7 +6,6 @@ import ( "git.badhouseplants.net/allanger/shoebill/pkg/cluster" "git.badhouseplants.net/allanger/shoebill/pkg/release" "git.badhouseplants.net/allanger/shoebill/pkg/repository" - "github.com/sirupsen/logrus" "gopkg.in/yaml.v2" ) @@ -21,7 +20,6 @@ type Config struct { // NewConfigFromFile populates the config struct from a configuration yaml file func NewConfigFromFile(path string) (*Config, error) { var config Config - logrus.Infof("readig the config file: %s", path) configFile, err := os.ReadFile(path) if err != nil { return nil, err diff --git a/pkg/lockfile/lockfile.go b/pkg/lockfile/lockfile.go index 568f021..90f91e3 100644 --- a/pkg/lockfile/lockfile.go +++ b/pkg/lockfile/lockfile.go @@ -19,8 +19,8 @@ type LockEntry struct { RepoUrl string RepoName string GitCommit string - Values []string - Secrets []string + Values map[string]string + Secrets map[string]string } type HashPerRelease struct { diff --git a/pkg/release/release.go b/pkg/release/release.go index 32e6139..ca24dfb 100644 --- a/pkg/release/release.go +++ b/pkg/release/release.go @@ -1,6 +1,8 @@ package release import ( + "crypto/sha1" + "encoding/base64" "fmt" "os" "path/filepath" @@ -36,9 +38,9 @@ type Release struct { } func (r *Release) ToHelmReleaseData() *helmhelper.ReleaseData { - // valuesData = + // valuesData = // for _, data := range r.DestValues { - + // } return &helmhelper.ReleaseData{ Name: r.Release, @@ -179,6 +181,20 @@ func ReleasesFromLockfile(lockfile lockfile.LockFile, repos repository.Repositor } func (r *Release) LockEntry() *lockfile.LockEntry { + valuesHashes := map[string]string{} + for _, valueHolder := range r.DestValues { + hasher := sha1.New() + hasher.Write(valueHolder.Data) + sha := base64.URLEncoding.EncodeToString(hasher.Sum(nil)) + valuesHashes[valueHolder.DestPath] = sha + } + secretHashes := map[string]string{} + for _, valueHolder := range r.DestSecrets { + hasher := sha1.New() + hasher.Write(valueHolder.Data) + sha := base64.URLEncoding.EncodeToString(hasher.Sum(nil)) + secretHashes[valueHolder.DestPath] = sha + } return &lockfile.LockEntry{ Chart: r.Chart, Release: r.Release, @@ -186,8 +202,8 @@ func (r *Release) LockEntry() *lockfile.LockEntry { Namespace: r.Namespace, RepoUrl: r.RepositoryObj.URL, RepoName: r.RepositoryObj.Name, - Values: r.DestValues.ToStrings(), - Secrets: r.DestSecrets.ToStrings(), + Values: valuesHashes, + Secrets: secretHashes, } } diff --git a/shoebill.yaml b/shoebill.yaml index 704119f..13370ba 100644 --- a/shoebill.yaml +++ b/shoebill.yaml @@ -49,20 +49,20 @@ releases: namespace: postgresql-server version: latest values: - - ./examples/one-config/values/postgresql.yaml + - ./examples/values.postgres.yaml secrets: - - ./examples/one-config/secrets/postgresql.yaml + - ./examples/secrets.postgres.yaml clusters: - - name: cluster-shoebill-test + - name: cluster-shoebill-tes git: git@git.badhouseplants.net:allanger/shoebill-test.git dotsops: | creation_rules: - path_regex: secrets/.*.yaml key_groups: - age: - - age16svfskd8x75g62f5uwpmgqzth52rr3wgv9m6rxchqv6v6kzmzf0qvhr2pk + - age1hcpgy4yy4psp6y2jt8waemzgg7crtlpxf3a48l6jvl6zmxll3vjsxj75vu provider: flux releases: - metrics-server @@ -70,5 +70,3 @@ clusters: - istio-ingressgateway - istiod - postgresql-server - -