diff --git a/.github/workflows/helm.yaml b/.github/workflows/helm.yaml new file mode 100644 index 00000000..539df24d --- /dev/null +++ b/.github/workflows/helm.yaml @@ -0,0 +1,61 @@ +name: Helm CI/CD + +on: + push: + branches: + - main + tags: + - v* + pull_request: + branches: + - main + paths: + - 'deploy/charts/**' + +env: + CHART_NAME: burrito + CHART_PATH: ./deploy/charts/burrito + CHART_REPO: ghcr.io/${{ github.repository_owner }}/charts + +jobs: + helm-render: + name: Helm Render + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Helm Render + run: helm template ${{ env.CHART_PATH }} + + helm-push: + name: Helm Push + runs-on: ubuntu-latest + needs: helm-render + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: GHCR Login + run: echo ${{ secrets.GITHUB_TOKEN }} | helm registry login ghcr.io -u ${{ github.repository_owner }} --password-stdin + + - name: Compute versions + shell: bash + run: | + CURRENT_VERSION=$(yq $CHART_PATH/Chart.yaml --expression .version) + if [[ ${{ github.event_name }} == 'pull_request' || ${{ github.event_name }} == 'push' && ${{ github.ref_type }} == 'branch' ]]; then + echo "VERSION=$(echo $CURRENT_VERSION-${{ github.sha }})" >> $GITHUB_ENV + echo "APP_VERSION=${{ github.sha }}" >> $GITHUB_ENV + elif [[ ${{ github.event_name }} == 'push' && ${{ github.ref_type }} == 'tag' ]]; then + echo "VERSION=$(echo ${{ github.ref_name }} | sed 's/v//')" >> $GITHUB_ENV + echo "APP_VERSION=${{ github.ref_name }}" >> $GITHUB_ENV + else + echo "Unsupported event type" + exit 1 + fi + + - name: Helm Package + run: helm package ${{ env.CHART_PATH }} -u --version ${{ env.VERSION }} --app-version ${{ env.APP_VERSION }} + + - name: Helm Push + run: helm push ./${{ env.CHART_NAME }}-${{ env.VERSION }}.tgz oci://ghcr.io/${{ github.repository_owner }}/charts diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 7a351336..d76380b3 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -13,11 +13,11 @@ jobs: runs-on: ubuntu-latest environment: production steps: - - name: Checkout uses: actions/checkout@v3 with: fetch-depth: 0 + - name: Fetch all tags run: git fetch --force --tags @@ -44,15 +44,26 @@ jobs: version: runs-on: ubuntu-latest environment: production + env: + CHART_PATH: ./deploy/charts/burrito steps: - name: Checkout uses: actions/checkout@v3 with: fetch-depth: 0 ref: main - - name: Bump version + + - name: Bump VERSION file run: | echo ${{ github.ref_name }} > VERSION + + - name: Bump Helm Chart versions + run: | + export CHART_VERSION=$(echo ${{ github.ref_name }} | sed 's/v//g') + export APP_VERSION=${{ github.ref_name }} + yq -i '.version = env(CHART_VERSION)' $CHART_PATH/Chart.yaml + yq -i '.appVersion = env(APP_VERSION)' $CHART_PATH/Chart.yaml + - name: Commit version to repository uses: stefanzweifel/git-auto-commit-action@v4 with: diff --git a/README.md b/README.md index 9082a289..61584e60 100644 --- a/README.md +++ b/README.md @@ -13,21 +13,21 @@ [`terraform`](https://www.terraform.io/) is a tremendous tool to manage your infrastructure in IaC. But, it does not come up with an out-of the box solution for managing [state drift](https://developer.hashicorp.com/terraform/tutorials/state/resource-drift). -Also, writing a CI/CD pipeline for terraform can be painful and depends on the tool you are using. +Also, writing a CI/CD pipeline for Terraform can be painful and depends on the tool you are using. -Finally, currently, there is no easy way to navigate your terraform state to truly understand the modifications it undergoes when running `terraform apply`. +Finally, currently, there is no easy way to navigate your Terraform state to truly understand the modifications it undergoes when running `terraform apply`. `burrito` aims to tackle those issues by: -- Planning continuously your terraform code and run applies if needed -- Offering an out of the box PR/MR integration so you do not have to write CI/CD pipelines for terraform ever again (not implemented yet) +- Planning continuously your Terraform code and run applies if needed +- Offering an out of the box PR/MR integration so you do not have to write CI/CD pipelines for Terraform ever again - Showing your state's modifications in a simple Web UI (not implemented yet) -## Demo +## Demo ![demo](./docs/assets/demo/demo.gif) -## Documenation +## Documentation To learn more about burrito [go to the complete documentation](https://padok-team.github.io/burrito/). diff --git a/cmd/controllers/start.go b/cmd/controllers/start.go index e78986f2..b2386cad 100644 --- a/cmd/controllers/start.go +++ b/cmd/controllers/start.go @@ -28,8 +28,8 @@ func buildControllersStartCmd(app *burrito.App) *cobra.Command { defaultWaitActionTimer, _ := time.ParseDuration("1m") defaultFailureGracePeriod, _ := time.ParseDuration("15s") + cmd.Flags().StringSliceVar(&app.Config.Controller.Namespaces, "namespaces", []string{"burrito-system"}, "list of namespaces to watch") cmd.Flags().StringSliceVar(&app.Config.Controller.Types, "types", []string{"layer", "repository", "pullrequest"}, "list of controllers to start") - cmd.Flags().DurationVar(&app.Config.Controller.Timers.DriftDetection, "drift-detection-period", defaultDriftDetectionTimer, "period between two plans. Must end with s, m or h.") cmd.Flags().DurationVar(&app.Config.Controller.Timers.OnError, "on-error-period", defaultOnErrorTimer, "period between two runners launch when an error occurred in the controllers. Must end with s, m or h.") cmd.Flags().DurationVar(&app.Config.Controller.Timers.WaitAction, "wait-action-period", defaultWaitActionTimer, "period between two runners when a layer is locked. Must end with s, m or h.") diff --git a/cmd/root.go b/cmd/root.go index 630e338d..2ce7c303 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -25,9 +25,10 @@ func buildBurritoCmd(app *burrito.App) *cobra.Command { }, } - cmd.Flags().StringVar(&app.Config.Redis.URL, "redis-url", "burrito-redis:6379", "the redis URL to connect to") - cmd.Flags().StringVar(&app.Config.Redis.Password, "redis-password", "", "the redis password") - cmd.Flags().IntVar(&app.Config.Redis.Database, "redis-database", 0, "the redis database") + cmd.PersistentFlags().StringVar(&app.Config.Redis.Hostname, "redis-host", "burrito-redis.burrito-system", "the redis host to connect to") + cmd.PersistentFlags().IntVar(&app.Config.Redis.ServerPort, "redis-port", 6379, "the port of the redis to connect to") + cmd.PersistentFlags().StringVar(&app.Config.Redis.Password, "redis-password", "", "the redis password") + cmd.PersistentFlags().IntVar(&app.Config.Redis.Database, "redis-database", 0, "the redis database") cmd.AddCommand(controllers.BuildControllersCmd(app)) cmd.AddCommand(runner.BuildRunnerCmd(app)) diff --git a/deploy/charts/burrito/.helmignore b/deploy/charts/burrito/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/deploy/charts/burrito/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/deploy/charts/burrito/Chart.yaml b/deploy/charts/burrito/Chart.yaml new file mode 100644 index 00000000..dad25c71 --- /dev/null +++ b/deploy/charts/burrito/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: burrito +description: A Helm chart for handling a complete burrito deployment +type: application +version: 0.1.0 +appVersion: "v0.1.0" diff --git a/deploy/charts/burrito/templates/config.yaml b/deploy/charts/burrito/templates/config.yaml new file mode 100644 index 00000000..ab7a8819 --- /dev/null +++ b/deploy/charts/burrito/templates/config.yaml @@ -0,0 +1,37 @@ +{{- if .Values.config.create }} + +{{- $config := .Values.config.burrito }} + +{{/* +Tenant Namespaces +*/}} +{{- $tenantNamespaces := list }} +{{- range $tenant := .Values.tenants }} +{{- $tenantNamespaces = append $tenantNamespaces $tenant.namespace.name }} +{{- end }} +{{- $_ := set $config.controller "namespaces" (default $tenantNamespaces $config.controller.namespaces) }} + +{{/* +Redis Hostname +*/}} +{{- if .Values.redis.enabled }} +{{- $_ := set $config.redis "hostname" (printf "%s.%s" "burrito-redis" .Release.Namespace) }} +{{- end }} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: burrito-config + labels: + app.kubernetes.io/name: burrito-config + {{- toYaml .Values.global.metadata.labels | nindent 4 }} + {{- with (mergeOverwrite (deepCopy .Values.global.metadata.annotations) .Values.config.annotations) }} + annotations: + {{- range $key, $value := . }} + {{ $key }}: {{ $value | quote }} + {{- end }} + {{- end }} +data: + config.yaml: |- + {{- toYaml $config | nindent 4 }} +{{- end }} diff --git a/deploy/charts/burrito/templates/controllers.yaml b/deploy/charts/burrito/templates/controllers.yaml new file mode 100644 index 00000000..aaca1cb6 --- /dev/null +++ b/deploy/charts/burrito/templates/controllers.yaml @@ -0,0 +1,121 @@ +{{ $configChecksum := (include (print $.Template.BasePath "/config.yaml") . | sha256sum) }} +{{ $sshKnownHostsChecksum := (include (print $.Template.BasePath "/ssh-known-hosts.yaml") . | sha256sum) }} + +{{- with mergeOverwrite (deepCopy .Values.global) .Values.controllers }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: burrito-controllers + annotations: + {{- toYaml .metadata.annotations | nindent 4 }} + labels: + {{- toYaml .metadata.labels | nindent 4 }} +spec: + {{- if not .deployment.autoscaling.enabled }} + replicas: {{ .deployment.replicas }} + {{- end }} + selector: + matchLabels: + {{- toYaml .metadata.labels | nindent 6 }} + template: + metadata: + annotations: + checksum/burrito-config: {{ $configChecksum }} + checksum/burrito-ssh-known-hosts: {{ $sshKnownHostsChecksum }} + {{- toYaml .deployment.podAnnotations | nindent 8 }} + labels: + {{- toYaml .metadata.labels | nindent 8 }} + spec: + {{- with .deployment.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: burrito-controllers + securityContext: + {{- toYaml .deployment.podSecurityContext | nindent 8 }} + containers: + - name: burrito + command: + {{- toYaml .deployment.command | nindent 12 }} + args: + {{- toYaml .deployment.args | nindent 12 }} + securityContext: + {{- toYaml .deployment.securityContext | nindent 12 }} + image: "{{ .deployment.image.repository }}:{{ .deployment.image.tag | default $.Chart.AppVersion }}" + imagePullPolicy: {{ .deployment.image.pullPolicy }} + ports: + {{- toYaml .deployment.ports | nindent 12 }} + livenessProbe: + {{- toYaml .deployment.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .deployment.readinessProbe | nindent 12 }} + resources: + {{- toYaml .deployment.resources | nindent 12 }} + env: + {{- toYaml .deployment.env | nindent 12 }} + envFrom: + {{- toYaml .deployment.envFrom | nindent 12 }} + volumeMounts: + - name: burrito-config + mountPath: /etc/burrito + readOnly: true + {{- with .deployment.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .deployment.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .deployment.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + - name: burrito-config + configMap: + name: burrito-config +{{- if .service.enabled }} +--- +apiVersion: v1 +kind: Service +metadata: + name: burrito-controllers + labels: + {{- toYaml .metadata.labels | nindent 4}} + annotations: + {{- toYaml .metadata.annotations | nindent 4}} +spec: + type: {{ .type }} + ports: + {{- toYaml .service.ports | nindent 4 }} + selector: + {{- toYaml .metadata.labels | nindent 4 }} +{{- end }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: burrito-controllers + labels: + {{- toYaml .metadata.labels | nindent 4 }} + annotations: + {{- toYaml .metadata.annotations | nindent 4 }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: burrito-controllers + labels: + {{- toYaml .metadata.labels | nindent 4 }} + annotations: + {{- toYaml .metadata.annotations | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: burrito-controllers +subjects: + - kind: ServiceAccount + name: burrito-controllers + namespace: {{ $.Release.Namespace }} +{{- end }} diff --git a/deploy/charts/burrito/templates/crds/crd-terraformlayers.yaml b/deploy/charts/burrito/templates/crds/crd-terraformlayers.yaml new file mode 120000 index 00000000..855f37fb --- /dev/null +++ b/deploy/charts/burrito/templates/crds/crd-terraformlayers.yaml @@ -0,0 +1 @@ +../../../../../manifests/crds/config.terraform.padok.cloud_terraformlayers.yaml \ No newline at end of file diff --git a/deploy/charts/burrito/templates/crds/crd-terraformpullrequests.yaml b/deploy/charts/burrito/templates/crds/crd-terraformpullrequests.yaml new file mode 120000 index 00000000..e977cbb6 --- /dev/null +++ b/deploy/charts/burrito/templates/crds/crd-terraformpullrequests.yaml @@ -0,0 +1 @@ +../../../../../manifests/crds/config.terraform.padok.cloud_terraformpullrequests.yaml \ No newline at end of file diff --git a/deploy/charts/burrito/templates/crds/crd-terraformrepositories.yaml b/deploy/charts/burrito/templates/crds/crd-terraformrepositories.yaml new file mode 120000 index 00000000..7d0e7f72 --- /dev/null +++ b/deploy/charts/burrito/templates/crds/crd-terraformrepositories.yaml @@ -0,0 +1 @@ +../../../../../manifests/crds/config.terraform.padok.cloud_terraformrepositories.yaml \ No newline at end of file diff --git a/deploy/charts/burrito/templates/rbac.yaml b/deploy/charts/burrito/templates/rbac.yaml new file mode 100644 index 00000000..32626b03 --- /dev/null +++ b/deploy/charts/burrito/templates/rbac.yaml @@ -0,0 +1,209 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/component: runner + app.kubernetes.io/name: burrito-runner + app.kubernetes.io/part-of: burrito + name: burrito-runner +rules: +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - delete +- apiGroups: + - config.terraform.padok.cloud + resources: + - terraformlayers + verbs: + - get + - patch +- apiGroups: + - config.terraform.padok.cloud + resources: + - terraformrepositories + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/component: server + app.kubernetes.io/name: burrito-server + app.kubernetes.io/part-of: burrito + name: burrito-server +rules: +- apiGroups: + - config.terraform.padok.cloud + resources: + - terraformlayers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - config.terraform.padok.cloud + resources: + - terraformlayers/finalizers + verbs: + - update +- apiGroups: + - config.terraform.padok.cloud + resources: + - terraformpullrequests + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - config.terraform.padok.cloud + resources: + - terraformpullrequests/finalizers + verbs: + - update +- apiGroups: + - config.terraform.padok.cloud + resources: + - terraformpullrequests/status + verbs: + - get + - patch + - update +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/component: controllers + app.kubernetes.io/name: burrito-controllers + app.kubernetes.io/part-of: burrito + name: burrito-controllers +rules: +- apiGroups: + - events.k8s.io + resources: + - events + verbs: + - create + - update +- apiGroups: + - "" + resources: + - events + verbs: + - create + - update +- apiGroups: + - "" + resources: + - pods + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - config.terraform.padok.cloud + resources: + - terraformlayers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - config.terraform.padok.cloud + resources: + - terraformlayers/finalizers + verbs: + - update +- apiGroups: + - config.terraform.padok.cloud + resources: + - terraformlayers/status + verbs: + - get + - patch + - update +- apiGroups: + - config.terraform.padok.cloud + resources: + - terraformrepositories + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - config.terraform.padok.cloud + resources: + - terraformrepositories/finalizers + verbs: + - update +- apiGroups: + - config.terraform.padok.cloud + resources: + - terraformrepositories/status + verbs: + - get + - patch + - update +- apiGroups: + - config.terraform.padok.cloud + resources: + - terraformpullrequests + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - config.terraform.padok.cloud + resources: + - terraformpullrequests/finalizers + verbs: + - update +- apiGroups: + - config.terraform.padok.cloud + resources: + - terraformpullrequests/status + verbs: + - get + - patch + - update +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete diff --git a/deploy/charts/burrito/templates/redis.yaml b/deploy/charts/burrito/templates/redis.yaml new file mode 100644 index 00000000..897bcfa5 --- /dev/null +++ b/deploy/charts/burrito/templates/redis.yaml @@ -0,0 +1,110 @@ +{{- if .Values.redis.enabled }} +{{- with mergeOverwrite (deepCopy .Values.global) .Values.redis }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: burrito-redis + annotations: + {{- toYaml .metadata.annotations | nindent 4 }} + labels: + {{- toYaml .metadata.labels | nindent 4 }} +spec: + {{- if not .deployment.autoscaling.enabled }} + replicas: {{ .deployment.replicas }} + {{- end }} + selector: + matchLabels: + {{- toYaml .metadata.labels | nindent 6 }} + template: + metadata: + annotations: + {{- toYaml .deployment.podAnnotations | nindent 8 }} + labels: + {{- toYaml .metadata.labels | nindent 8 }} + spec: + {{- with .deployment.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: burrito-redis + securityContext: + {{- toYaml .deployment.podSecurityContext | nindent 8 }} + containers: + - name: redis + command: + {{- toYaml .deployment.command | nindent 12 }} + args: + {{- toYaml .deployment.args | nindent 12 }} + securityContext: + {{- toYaml .deployment.securityContext | nindent 12 }} + image: "{{ .deployment.image.repository }}:{{ .deployment.image.tag }}" + imagePullPolicy: {{ .deployment.image.pullPolicy }} + ports: + {{- toYaml .deployment.ports | nindent 12 }} + livenessProbe: + {{- toYaml .deployment.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .deployment.readinessProbe | nindent 12 }} + resources: + {{- toYaml .deployment.resources | nindent 12 }} + env: + {{- toYaml .deployment.env | nindent 12 }} + envFrom: + {{- toYaml .deployment.envFrom | nindent 12 }} + {{- with .deployment.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .deployment.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .deployment.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- if .service.enabled }} +--- +apiVersion: v1 +kind: Service +metadata: + name: burrito-redis + labels: + {{- toYaml .metadata.labels | nindent 4}} + annotations: + {{- toYaml .metadata.annotations | nindent 4}} +spec: + type: {{ .type }} + ports: + {{- toYaml .service.ports | nindent 4 }} + selector: + {{- toYaml .metadata.labels | nindent 4 }} +{{- end }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: burrito-redis + labels: + {{- toYaml .metadata.labels | nindent 4 }} + annotations: + {{- toYaml .metadata.annotations | nindent 4 }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: burrito-redis + labels: + {{- toYaml .metadata.labels | nindent 4 }} + annotations: + {{- toYaml .metadata.annotations | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: burrito-redis +subjects: + - kind: ServiceAccount + name: burrito-redis + namespace: {{ $.Release.Namespace }} +{{- end }} +{{- end }} diff --git a/deploy/charts/burrito/templates/server.yaml b/deploy/charts/burrito/templates/server.yaml new file mode 100644 index 00000000..65daf13d --- /dev/null +++ b/deploy/charts/burrito/templates/server.yaml @@ -0,0 +1,144 @@ +{{ $configChecksum := (include (print $.Template.BasePath "/config.yaml") . | sha256sum) }} +{{ $sshKnownHostsChecksum := (include (print $.Template.BasePath "/ssh-known-hosts.yaml") . | sha256sum) }} + +{{- with mergeOverwrite (deepCopy .Values.global) .Values.server }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: burrito-server + annotations: + {{- toYaml .metadata.annotations | nindent 4 }} + labels: + {{- toYaml .metadata.labels | nindent 4 }} +spec: + {{- if not .deployment.autoscaling.enabled }} + replicas: {{ .deployment.replicas }} + {{- end }} + selector: + matchLabels: + {{- toYaml .metadata.labels | nindent 6 }} + template: + metadata: + annotations: + checksum/burrito-config: {{ $configChecksum }} + checksum/burrito-ssh-known-hosts: {{ $sshKnownHostsChecksum }} + {{- toYaml .deployment.podAnnotations | nindent 8 }} + labels: + {{- toYaml .metadata.labels | nindent 8 }} + spec: + {{- with .deployment.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: burrito-server + securityContext: + {{- toYaml .deployment.podSecurityContext | nindent 8 }} + containers: + - name: burrito + command: + {{- toYaml .deployment.command | nindent 12 }} + args: + {{- toYaml .deployment.args | nindent 12 }} + securityContext: + {{- toYaml .deployment.securityContext | nindent 12 }} + image: "{{ .deployment.image.repository }}:{{ .deployment.image.tag | default $.Chart.AppVersion }}" + imagePullPolicy: {{ .deployment.image.pullPolicy }} + ports: + {{- toYaml .deployment.ports | nindent 12 }} + livenessProbe: + {{- toYaml .deployment.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .deployment.readinessProbe | nindent 12 }} + resources: + {{- toYaml .deployment.resources | nindent 12 }} + env: + {{- toYaml .deployment.env | nindent 12 }} + envFrom: + {{- toYaml .deployment.envFrom | nindent 12 }} + volumeMounts: + - name: burrito-config + mountPath: /etc/burrito + readOnly: true + {{- with .deployment.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .deployment.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .deployment.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + - name: burrito-config + configMap: + name: burrito-config +{{- if .service.enabled }} +--- +apiVersion: v1 +kind: Service +metadata: + name: burrito-server + labels: + {{- toYaml .metadata.labels | nindent 4 }} + annotations: + {{- toYaml .metadata.annotations | nindent 4 }} +spec: + type: {{ .type }} + ports: + {{- toYaml .service.ports | nindent 4 }} + selector: + {{- toYaml .metadata.labels | nindent 4 }} +{{- end }} +{{- if .ingress.enabled }} +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: burrito-server + annotations: + {{- toYaml .ingress.annotations | nindent 4 }} +spec: + ingressClassName: {{ .ingress.ingressClassName }} + rules: + - host: {{ .ingress.host }} + http: + paths: + - pathType: ImplementationSpecific + backend: + service: + name: burrito-server + port: + name: http + tls: + {{- toYaml .ingress.tls | nindent 4 }} +{{- end }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: burrito-server + labels: + {{- toYaml .metadata.labels | nindent 4 }} + annotations: + {{- toYaml .metadata.annotations | nindent 4 }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: burrito-server + labels: + {{- toYaml .metadata.labels | nindent 4 }} + annotations: + {{- toYaml .metadata.annotations | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: burrito-server +subjects: + - kind: ServiceAccount + name: burrito-server + namespace: {{ $.Release.Namespace }} +{{- end }} diff --git a/deploy/charts/burrito/templates/ssh-known-hosts.yaml b/deploy/charts/burrito/templates/ssh-known-hosts.yaml new file mode 100644 index 00000000..4d110dea --- /dev/null +++ b/deploy/charts/burrito/templates/ssh-known-hosts.yaml @@ -0,0 +1,31 @@ +{{/* +Create ConfigMap in all tenant namespaces + release namespace +*/}} +{{- $namespaces := list }} +{{- range $tenant := .Values.tenants }} +{{- $namespaces = append $namespaces $tenant.namespace.name }} +{{- end }} +{{- $namespaces = append $namespaces .Release.Namespace }} + +{{- range $namespace := $namespaces }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + app.kubernetes.io/part-of: burrito + app.kubernetes.io/name: burrito-ssh-known-hosts + name: burrito-ssh-known-hosts + namespace: {{ $namespace }} +data: + known_hosts: |- + bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw== + github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= + gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY= + gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf + gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9 + ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H + vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H + github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= + github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl +{{- end }} diff --git a/deploy/charts/burrito/templates/tenant.yaml b/deploy/charts/burrito/templates/tenant.yaml new file mode 100644 index 00000000..fa2dd8ea --- /dev/null +++ b/deploy/charts/burrito/templates/tenant.yaml @@ -0,0 +1,62 @@ +{{- range $tenant := .Values.tenants }} +{{- if $tenant.namespace.create }} +apiVersion: v1 +kind: Namespace +metadata: + labels: + {{- toYaml $tenant.namespace.labels | nindent 4 }} + annotations: + {{- toYaml $tenant.namespace.annotations | nindent 4 }} + name: {{ $tenant.namespace.name }} +spec: + finalizers: + - kubernetes +--- +{{- end }} +{{- range $serviceAccount := .serviceAccounts }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ $serviceAccount.name }} + labels: + {{- toYaml $serviceAccount.labels | nindent 4 }} + annotations: + {{- toYaml $serviceAccount.annotations | nindent 4 }} + namespace: {{ $tenant.namespace.name }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ $serviceAccount.name }}-burrito-runner + labels: + {{- toYaml $serviceAccount.labels | nindent 4 }} + namespace: {{ $tenant.namespace.name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: burrito-runner +subjects: +- kind: ServiceAccount + name: {{ $serviceAccount.name }} + namespace: {{ $tenant.namespace.name }} +--- +{{- range $additionalRoleBinding := $serviceAccount.additionalRoleBindings }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ $additionalRoleBinding.name }} + labels: + {{- toYaml $serviceAccount.labels | nindent 4 }} + namespace: {{ $tenant.namespace.name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: {{ $additionalRoleBinding.role.kind }} + name: {{ $additionalRoleBinding.role.name }} +subjects: +- kind: ServiceAccount + name: {{ $serviceAccount.name }} + namespace: {{ $tenant.namespace.name }} +--- +{{- end }} +{{- end }} +{{- end }} diff --git a/deploy/charts/burrito/values-example.yaml b/deploy/charts/burrito/values-example.yaml new file mode 100644 index 00000000..c6366294 --- /dev/null +++ b/deploy/charts/burrito/values-example.yaml @@ -0,0 +1,50 @@ +redis: + enabled: true + +global: + deployment: + image: + tag: "custom-version" + +config: + burrito: + controller: + timers: + driftDetection: 5m + +controller: + deployment: + envFrom: + - secretRef: + name: burrito-gh-token + +server: + deployment: + envFrom: + - secretRef: + name: burrito-webhook-secret + ingress: + enabled: true + annotations: + ingress.kubernetes.io/ssl-redirect: "true" + ingressClassName: nginx + host: burrito.padok.cloud + tls: + - secretName: wildcard-padok-cloud-tls + +tenants: + - namespace: + create: true + name: "burrito-project-1" + labels: {} + annotations: {} + serviceAccounts: + - name: runner-project-1 + additionalRoleBindings: + - name: custom + role: + kind: ClusterRole + name: my-custom-role + annotations: + iam.cloud.provider/role: cloud-provider-role + labels: {} diff --git a/deploy/charts/burrito/values.yaml b/deploy/charts/burrito/values.yaml new file mode 100644 index 00000000..112954ff --- /dev/null +++ b/deploy/charts/burrito/values.yaml @@ -0,0 +1,182 @@ +# TODO: Make CRD install optional? or use --skip-crds Helm flag +# Custom Resource Definitions +# crds: +# install: true + +# Burrito configuration +## Ref: https://padok-team.github.io/burrito/operator-manual/advanced-configuration/ +config: + # -- Create ConfigMap with Burrito configuration + create: true + # -- Annotations to be added to the ConfigMap + annotations: {} + + # -- Burrito configuration in YAML format + burrito: + # -- Redis connection configuration + redis: + hostname: "burrito-redis" + port: 6379 + database: 0 + # -- Prefer override with the BURRITO_REDIS_PASSWORD environment variable + password: "" + + # Burrito controller configuration + controller: + # -- By default, the controller will watch all namespaces + namespaces: [] + timers: + driftDetection: 20m + onError: 1m + waitAction: 1m + failureGracePeriod: 15s + types: ["layer", "repository", "pullrequest"] + leaderElection: + enabled: true + id: 6d185457.terraform.padok.cloud + metricsBindAddress: ":8080" + healthProbeBindAddress: ":8081" + kubernetesWebhookPort: 9443 + githubConfig: + # -- Prefer override with the BURRITO_CONTROLLER_GITHUBCONFIG_APITOKEN environment variable + apiToken: "" + gitlabConfig: + # -- Prefer override with the BURRITO_CONTROLLER_GITLABCONFIG_APITOKEN environment variable + apiToken: "" + url: "" + + # Burrito server configuration + server: + addr: ":8080" + webhook: + github: + # -- Prefer override with the BURRITO_SERVER_WEBHOOK_GITHUB_SECRET environment variable + secret: "" + gitlab: + # -- Prefer override with the BURRITO_SERVER_WEBHOOK_GITLAB_SECRET environment variable + secret: "" + + # Burrito runners configuration + runner: + sshKnownHostsConfigMapName: burrito-ssh-known-hosts + +redis: + enabled: true + metadata: + labels: + app.kubernetes.io/component: redis + app.kubernetes.io/name: burrito-redis + deployment: + image: + repository: redis + tag: "7.0.7-alpine" + pullPolicy: Always + args: [] + podSecurityContext: + runAsNonRoot: true + runAsUser: 999 + seccompProfile: + type: RuntimeDefault + service: + ports: + - name: tcp-redis + port: 6379 + targetPort: 6379 + +global: + metadata: + labels: + app.kubernetes.io/part-of: burrito + annotations: {} + deployment: + autoscaling: + enabled: false + replicas: 1 + image: + repository: ghcr.io/padok-team/burrito + tag: "" # By default use Chart's appVersion + pullPolicy: Always + podAnnotations: {} + podSecurityContext: + runAsNonRoot: true + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - "ALL" + resources: {} + ports: [] + envFrom: [] + service: + enabled: true + +controllers: + metadata: + labels: + app.kubernetes.io/component: controllers + app.kubernetes.io/name: burrito-controllers + deployment: + podAnnotations: + kubectl.kubernetes.io/default-container: burrito + command: ["burrito"] + args: ["controllers", "start"] + livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + envFrom: [] + service: + enabled: false + +server: + metadata: + labels: + app.kubernetes.io/component: server + app.kubernetes.io/name: burrito-server + deployment: + podAnnotations: + kubectl.kubernetes.io/default-container: burrito + command: ["burrito"] + args: ["server", "start"] + ports: + - name: http + containerPort: 8080 + livenessProbe: + httpGet: + path: /healthz + port: 8080 + initialDelaySeconds: 15 + periodSeconds: 20 + readinessProbe: + httpGet: + path: /healthz + port: 8080 + initialDelaySeconds: 15 + periodSeconds: 20 + envFrom: + # -- Reference the webhook secret here + ## It should define a BURRITO_SERVER_WEBHOOK_GITHUB_SECRET and/or BURRITO_SERVER_WEBHOOK_GITLAB_SECRET key + - secretRef: + name: burrito-webhook-secret + optional: true + service: + ports: + - name: http + port: 80 + targetPort: http + ingress: + enabled: false + annotations: {} + ingressClassName: nginx + host: burrito.example.com + tls: [] + +tenants: [] diff --git a/docs/assets/design/multi-tenant-architecture.excalidraw.png b/docs/assets/design/multi-tenant-architecture.excalidraw.png new file mode 100644 index 00000000..383c8d85 Binary files /dev/null and b/docs/assets/design/multi-tenant-architecture.excalidraw.png differ diff --git a/docs/getting-started.md b/docs/getting-started.md index 5433752d..cd1176e9 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -17,6 +17,9 @@ This will create a new namespace, `burrito`, where burrito services will live. !!! warning The installation manifests include `ClusterRoleBinding` resources that reference `burrito` namespace. If you are installing burrito into a different namespace then make sure to update the namespace reference. +!!! info + You might be interested by our [Helm chart](./operator-manual/install/with-helm.md), that provides more control over burrito's configuration as well as a [multi-tenant architecture](./operator-manual/multi-tenant-architecture.md). + ## 2. Create a connection to a private repository Create a Kubernetes `Secret` which looks like: @@ -64,12 +67,11 @@ metadata: name: random-pets namespace: burrito spec: - terraform: + terraform: version: "1.3.1" path: "internal/e2e/testdata/random-pets" branch: "main" repository: - kind: TerraformRepository name: burrito namespace: burrito ``` diff --git a/docs/index.md b/docs/index.md index 6b2ed79c..8d6a60f3 100644 --- a/docs/index.md +++ b/docs/index.md @@ -11,14 +11,14 @@ [`terraform`](https://www.terraform.io/) is a tremendous tool to manage your infrastructure in IaC. But, it does not come up with an out-of the box solution for managing [state drift](https://developer.hashicorp.com/terraform/tutorials/state/resource-drift). -Also, writing a CI/CD pipeline for terraform can be painful and depends on the tool you are using. +Also, writing a CI/CD pipeline for Terraform can be painful and depends on the tool you are using. -Finally, currently, there is no easy way to navigate your terraform state to truly understand the modifications it undergoes when running `terraform apply`. +Finally, currently, there is no easy way to navigate your Terraform state to truly understand the modifications it undergoes when running `terraform apply`. `burrito` aims to tackle those issues by: -- Planning continuously your terraform code and run applies if needed -- Offering an out of the box PR/MR integration so you do not have to write CI/CD pipelines for terraform ever again (not implemented yet) +- Planning continuously your Terraform code and run applies if needed +- Offering an out of the box PR/MR integration so you do not have to write CI/CD pipelines for Terraform ever again - Showing your state's modifications in a simple Web UI (not implemented yet) ## Getting started @@ -30,4 +30,4 @@ kubectl create namespace burrito kubectl apply -n burrito -f https://raw.githubusercontent.com/padok-team/burrito/main/manifests/install.yaml ``` -Follow our [getting started guide](getting_started.md). Further user oriented [documentation](user-guide/) is provided for additional features. +Follow our [getting started guide](./getting-started.md). Further user oriented [documentation](./user-guide/) is provided for additional features. diff --git a/docs/operator-manual/advanced-configuration.md b/docs/operator-manual/advanced-configuration.md index 302025e7..3325abeb 100644 --- a/docs/operator-manual/advanced-configuration.md +++ b/docs/operator-manual/advanced-configuration.md @@ -2,30 +2,34 @@ You can configure `burrito` with environment variables. -| Environment variable | Description | Default | -| :------------------: | :-------------------------: | :----------: | -| `BURRITO_REDIS_URL` | the redis URL to connect to | `redis:6379` | +| Environment variable | Description | Default | +| :------------------------: | :---------------------------------: | :----------------------------: | +| `BURRITO_REDIS_HOSTNAME` | the redis host to connect to | `burrito-redis.burrito-system` | +| `BURRITO_REDIS_SERVERPORT` | the port of the redis to connect to | `6379` | +| `BURRITO_REDIS_DATABASE` | the redis database to connect to | `0` | +| `BURRITO_REDIS_PASSWORD` | the redis password | (empty) | ## Controllers' configuration -| Environment variable | Description | Default | -| :--------------------------------------------------: | :------------------------------------------------------------------------------------------: | :------------------------------: | -| `BURRITO_CONTROLLER_TYPES` | list of controllers to start | `layer,repository` | -| `BURRITO_CONTROLLER_TIMERS_DRIFTDETECTION` | period between two plans for drift detection | `20m` | -| `BURRITO_CONTROLLER_TIMERS_ONERROR` | period between two runners launch when an error occurred in the controllers | `1m` | -| `BURRITO_CONTROLLER_TIMERS_WAITACTION` | period between two runners launch when a layer is locked | `1m` | -| `BURRITO_CONTROLLER_TIMERS_FAILUREGRACEPERIOD` | initial time before retry, goes exponential function of number failure | `15s` | -| `BURRITO_CONTROLLER_LEADERELECTION_ENABLED` | whether leader election is enabled or not | `true` | -| `BURRITO_CONTROLLER_LEADERELECTION_ID` | lease id used for leader election | `6d185457.terraform.padok.cloud` | -| `BURRITO_CONTROLLER_HEALTHPROBEBINDADDRESS` | address to bind the health probe server embedded in the controllers | `:8081` | -| `BURRITO_CONTROLLER_METRICSBINDADDRESS` | address to bind the metrics server embedded in the controllers | `:8080` | -| `BURRITO_CONTROLLER_KUBERNETESWEBHOOKPORT` | port used by the validating webhook server embedded in the controllers | `9443` | +| Environment variable | Description | Default | +| :--------------------------------------------: | :-------------------------------------------------------------------------: | :------------------------------: | +| `BURRITO_CONTROLLER_NAMESPACES` | list of namespaces to watch (comma-separated) | `burrito-system` | +| `BURRITO_CONTROLLER_TYPES` | list of controllers to start | `layer,repository,pullrequest` | +| `BURRITO_CONTROLLER_TIMERS_DRIFTDETECTION` | period between two plans for drift detection | `20m` | +| `BURRITO_CONTROLLER_TIMERS_ONERROR` | period between two runners launch when an error occurred in the controllers | `1m` | +| `BURRITO_CONTROLLER_TIMERS_WAITACTION` | period between two runners launch when a layer is locked | `1m` | +| `BURRITO_CONTROLLER_TIMERS_FAILUREGRACEPERIOD` | initial time before retry, goes exponential function of number failure | `15s` | +| `BURRITO_CONTROLLER_LEADERELECTION_ENABLED` | whether leader election is enabled or not | `true` | +| `BURRITO_CONTROLLER_LEADERELECTION_ID` | lease id used for leader election | `6d185457.terraform.padok.cloud` | +| `BURRITO_CONTROLLER_HEALTHPROBEBINDADDRESS` | address to bind the health probe server embedded in the controllers | `:8081` | +| `BURRITO_CONTROLLER_METRICSBINDADDRESS` | address to bind the metrics server embedded in the controllers | `:8080` | +| `BURRITO_CONTROLLER_KUBERNETESWEBHOOKPORT` | port used by the validating webhook server embedded in the controllers | `9443` | ## Server's configuration -| Environment variable | Description | Default | -| :-------------------: | :------------------------: | :-----: | -| `BURRITO_SERVER_ADDR` | addr the server listens on | `:8080` | +| Environment variable | Description | Default | +| :-------------------: | :---------------------------: | :-----: | +| `BURRITO_SERVER_ADDR` | address the server listens on | `:8080` | !!! info For webhook configuration see [Setup a git webhook](./git-webhook.md). diff --git a/docs/operator-manual/architecture.md b/docs/operator-manual/architecture.md index 65e6366f..aba4dc47 100644 --- a/docs/operator-manual/architecture.md +++ b/docs/operator-manual/architecture.md @@ -22,13 +22,13 @@ The layer controller is a Kubernetes Controller which continuously monitors decl It regularly starts runner pods which runs a `terraform plan` for each of your layer to check if a drift has been introduced. If so, it has the possibility to run a `terraform apply`. -It is also responsible for running your terraform `plan` and `apply` if there is a new commit on your layer. +It is also responsible for running your Terraform `plan` and `apply` if there is a new commit on your layer. It also generates [`Leases`](https://kubernetes.io/docs/concepts/architecture/leases/) to make sure no concurrent terraform commands will be launched on the same layer at the same time. -### The redis instance +### The Redis instance -The redis instance is used to store the binary generated by `terraform plan` before running the `apply`. We also store information about the `plan`/`apply` output to print it in the resources' statuses +The Redis instance is used to store the binary generated by `terraform plan` before running the `apply`. We also store information about the `plan`/`apply` output to print it in the resources' statuses ## Implementation @@ -45,10 +45,10 @@ The status of a `TerraformLayer` is defined using the [conditions standards defi - `IsPlanArtifactUpToDate`. This condition is used for drift detection. The evaluation is made by compraing the timestamp of the last `terraform plan` which ran and the current date. The timestamp of the last plan is "stored" using an annotation. - `IsApplyUpToDate`. This condition is used to check if an `apply` needs to run after the last `plan`. Comparison is made by comparing a checksum of the last planned binary and a checksum last applied binary stored in the annotations. - `IsLastRelevantCommitPlanned`. This condition is used to check if a new commit has been made to the layer and need to be applied. It is evaluated by comparing the commit used for the last `plan`, the last commit which intoduced changes to the layer and the last commit made to the same branch of the repository. Those commits are "stored" as annotations. -- `IsInfailureGracePeriod`. This condition is used to check if a terraform workflow has already failed. If so, we use an exponential backoff strategy before restarting a runner on the given layer. +- `IsInfailureGracePeriod`. This condition is used to check if a Terraform workflow has already failed. If so, we use an exponential backoff strategy before restarting a runner on the given layer. -!!! info - We use annotations to store information because we do not want to rely too heavily on the uptime of the redis instance. +!!! info + We use annotations to store information because we do not want to rely too heavily on the uptime of the Redis instance. With those 4 conditions, we defined 4 states: @@ -57,17 +57,17 @@ With those 4 conditions, we defined 4 states: - `ApplyNeeded`. This is the state of a layer if burrito needs to start an `apply` runner - `FailureGracePeriod`. This is the state of a layer if a `plan` or `apply` runner has failed -!!! info +!!! info If you use [`dry` remediation strategy](../user-guide/remediation-strategy.md) and an apply is needed, the layer will stay in the `ApplyNeeded` as long as it does not need to enter the `PlanNeeded`. -The layer controller also generates the Kubernetes leases to avoid concurrent use of terraform on the same layer. +The layer controller also generates the Kubernetes leases to avoid concurrent use of Terraform on the same layer. !!! info - N.B. We use lease objects in order to not have to rely on the redis instance for layer locking. + N.B. We use lease objects in order to not have to rely on the Redis instance for layer locking. The layer controller is also responsible for registering runner pods to the Kubernetes API. We decided to use dynamic runners in order to be able to associate specific service accounts for each layers (each layer does not need the same access right to be planned and applied). ### The runners -The runner image implementation heavily relies on golang libraries provided by hashicorp such as `tfexec`, `releases` and `product` which allows us to dynamically download and use any version of therraform binary. -Thus, we support any existing version of terraform. +The runner image implementation heavily relies on golang libraries provided by hashicorp such as `tfexec`, `releases` and `product` which allows us to dynamically download and use any version of the Terraform binary. +Thus, we support any existing version of Terraform. diff --git a/docs/operator-manual/index.md b/docs/operator-manual/index.md index e041e2f2..cd15a738 100644 --- a/docs/operator-manual/index.md +++ b/docs/operator-manual/index.md @@ -3,4 +3,4 @@ This guide is for administrator and operator wanting to install and configure burrito for other developers. !!! note - Please make sure you've completed the [getting started guide](../getting_started.md). + Please make sure you've completed the [getting started guide](../getting-started.md). diff --git a/docs/operator-manual/install/with-helm.md b/docs/operator-manual/install/with-helm.md new file mode 100644 index 00000000..16f3da15 --- /dev/null +++ b/docs/operator-manual/install/with-helm.md @@ -0,0 +1,76 @@ +# Install burrito with Helm + +## Requirements + +- Installed [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) command-line tool +- Installed [helm](https://helm.sh/docs/intro/install/) command-line tool **(version v3.8.0 and further)** +- Have a [kubeconfig](https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/) file (default location is `~/.kube/config`) + +## 1. Install burrito + +!!! info + Our Helm chart is published in an [OCI-based registry](https://helm.sh/docs/topics/registries/) (ghcr.io). You must use Helm v3.8.0 or above. + +```bash +helm install burrito oci://ghcr.io/padok-team/charts/burrito -n burrito-system --create-namespace +``` + +This will create a new namespace, `burrito-system`, where the burrito operator will live. + +You can change the chart's version with any version available on [our Chart registry](https://github.com/padok-team/burrito/pkgs/container/charts%2Fburrito). + +## 2. Override values + +You can inspect the chart's values with Helm. + +```bash +helm show values oci://ghcr.io/padok-team/charts/burrito +``` + +The chart's source code is available on [burrito GitHub repository](https://github.com/padok-team/burrito). + +Here is an example of values file overriding some default values of burrito: + +```yaml +# Example of external Redis instance +redis: + enabled: false +config: + burrito: + redis: + hostname: "custom-redis.svc.cluster.local" + +tenants: + # Example tenant with 1 service account having additional role bindings + - namespace: + create: true + name: "burrito-project-1" + labels: {} + annotations: {} + serviceAccounts: + - name: runner-project-1 + additionalRoleBindings: + - name: custom + role: + kind: ClusterRole + name: custom-role + annotations: {} + labels: {} + # Example tenant with multiple service accounts using GKE Workload Identity + - namespace: + create: true + name: "burrito-project-1" + serviceAccounts: + - name: runner-frontend + annotations: + iam.gke.io/gcp-service-account: burrito-frontend@company-project.iam.gserviceaccount.com + - name: runner-backend + annotations: + iam.gke.io/gcp-service-account: burrito-backend@company-project.iam.gserviceaccount.com + - name: runner-network + annotations: + iam.gke.io/gcp-service-account: burrito-network@company-project.iam.gserviceaccount.com +``` + +!!! info + Learn more about these values in [Advanced Configuration](../advanced-configuration.md) and [Multi-tenant architecture](../multi-tenant-architecture.md). diff --git a/docs/operator-manual/install/with-static-manifests.md b/docs/operator-manual/install/with-static-manifests.md new file mode 100644 index 00000000..eb581f00 --- /dev/null +++ b/docs/operator-manual/install/with-static-manifests.md @@ -0,0 +1,21 @@ +# Install burrito with static manifests + +## Requirements + +- Installed [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) command-line tool. +- Have a [kubeconfig](https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/) file (default location is `~/.kube/config`). + +## Install burrito + +!!! info + This will install a mono-tenant version of burrito. See the [Helm installation method](./with-helm.md) for a [multi-tenant-architecture](../multi-tenant-architecture.md). + +```bash +kubectl create namespace burrito +kubectl apply -n burrito -f https://raw.githubusercontent.com/padok-team/burrito/main/manifests/install.yaml +``` + +This will create a new namespace, `burrito`, where burrito services will live. + +!!! warning + The installation manifests include `ClusterRoleBinding` resources that reference `burrito` namespace. If you are installing burrito into a different namespace then make sure to update the namespace reference. diff --git a/docs/operator-manual/multi-tenant-architecture.md b/docs/operator-manual/multi-tenant-architecture.md new file mode 100644 index 00000000..02287798 --- /dev/null +++ b/docs/operator-manual/multi-tenant-architecture.md @@ -0,0 +1,104 @@ +# Multi-tenant architecture + +
+ +With our [Helm chart](./install/with-helm.md) we provide a way to setup multi-tenancy with burrito. This is useful when working at scale, when you controls multiple Terraform projects with burrito across several teams. + +The setup is split across multiple Kubernetes namespaces: + +- `burrito-system` is where burrito's components live and operate (controllers, server, Redis) +- the other namespaces (`tenant-namespace-[1-3]` on the schema) where `TerraformRepository`, `TerraformLayer` and `TerraformPullRequest` resources live and where burrito spawns runner pods for Terraform `plan` and `apply` actions. + +Thanks to Kubernetes native RBAC system you can restrict access for your users only to the namespaces their burrito resources live. + +## Configuring multi-tenancy with the Helm chart + +### 1. Configure basic tenants + +In the `values.yaml` of the [Helm chart](./install/with-helm.md), add the following: + +```yaml +tenants: + - namespace: + create: true + name: tenant-namespace-1 + serviceAccounts: + - name: runner-project + - namespace: + create: true + name: tenant-namespace-2 + serviceAccounts: + - name: runner-project + - namespace: + create: true + name: tenant-namespace-3 + serviceAccounts: + - name: runner-project +``` + +This setup creates 3 tenants with 3 namespaces with one service account in each namespace. + +The chart adds every tenant referenced in its values in the namespaces that the burrito controllers must watch. + +You can also customize namespaces' labels and annotations: + +```yaml +tenants: + - namespace: + create: true + name: tenant-namespace-1 + labels: + app.kubernetes.io/part-of: project-1 + annotations: + helm.sh/resource-policy: keep +``` + +### 2. Configure service accounts + +Each service account created in a tenant is binded to the `burrito-runner` ClusterRole, it is a basic role with the required permissions for a burrito runner pod to work properly. + +You can add additional role bindings to the service accounts if you need special permissions in the cluster (e.g. a Terraform layer deploying to Kubernetes) as well as annotations and labels (e.g. assume a role on a cloud provider). + +```yaml + - namespace: + create: true + name: tenant-namespace-1 + serviceAccounts: + - name: runner-kubernetes + additionalRoleBindings: + - name: custom + role: + kind: ClusterRole + name: custom-role + - name: runner-google + labels: + app.kubernetes.io/part-of: project-1 + annotations: + iam.gke.io/gcp-service-account: burrito-project-1@company-project.iam.gserviceaccount.com + - name: runner-aws + annotations: + eks.amazonaws.com/role-arn: arn:aws:iam::111122223333:role/my-role +``` + +### 3. Use service accounts in the tenant + +For the `TerraformRepository` or `TerraformLayer` you deploy in a tenant, you can use the `overrideRunnerSpec` parameter to select which service account to use for runners affected to a layer/repository. + +```yaml +apiVersion: config.terraform.padok.cloud/v1alpha1 +kind: TerraformLayer +metadata: + name: infra-aws + namespace: tenant-namespace-1 +spec: + terraform: + version: "1.5.3" + remediationStrategy: dry + path: "infra/layers/aws/production" + branch: "main" + repository: + name: project-1 + namespace: tenant-namespace-1 + overrideRunnerSpec: + serviceAccountName: runner-aws # <-- Specify service account here +``` diff --git a/docs/operator-manual/pr-mr-workflow.md b/docs/operator-manual/pr-mr-workflow.md index d2985c9b..b38e7927 100644 --- a/docs/operator-manual/pr-mr-workflow.md +++ b/docs/operator-manual/pr-mr-workflow.md @@ -4,22 +4,23 @@ !!! info In this documentation all references to pull requests can be change to merge requests for GitLab. However, the resulting Kubernetes object will still be named `TerraformPullRequest`. + ## Components ### The server !!! info - For mor information about the server, see the [architectural overview](./architecture.md) documentation. + For more information about the server, see the [architectural overview](./architecture.md) documentation. Upon receiving a Pull Request creation event, the server creates a `TerraformPullRequest` resource. -Upon receiving a Pull Requestion deletion event, the server deletes the related `TerraformPullRequest` resource. +Upon receiving a Pull Request deletion event, the server deletes the related `TerraformPullRequest` resource. ### The pull request controller The pull request controller is a Kubernetes controller which continuously monitors declared `TerraformPullRequest` resources. -It is responsible for creating temporary `TerraformLayer` resources linked to the Pull Request it was generated from. Once all the `TerraformLayer` have planned, it will send a comment contianing the plan results to the pull request. +It is responsible for creating temporary `TerraformLayer` resources linked to the Pull Request it was generated from. Once all the `TerraformLayer` have planned, it will send a comment containing the plan results to the pull request. @@ -31,9 +32,9 @@ The status of a `TerraformPulLRequest` is defined using the [conditions standard - `IsLastCommitDiscovered`. This condition is used to check if we received a new commit on the pull request by comparing the latest commit on the branch and the last discovered commit. - `AreLayersStillPlanning`. This condition is used to check if all the temporary layers have finished planning. This is done by checking all the resulting `TerraformLayer` statuses. -- `IsCommentUpToDate`. This condition is used to check if the controller needs to sen a comment to a pull request. This is checked by comparing the last discovered commit and the last commit for which a comment was already sent. +- `IsCommentUpToDate`. This condition is used to check if the controller needs to send a comment to a pull request. This is checked by comparing the last discovered commit and the last commit for which a comment was already sent. -!!! info +!!! info We use annotations to store information. With those 3 conditions, we defined 3 states: @@ -48,3 +49,4 @@ With those 3 conditions, we defined 3 states: | :----------------------------------------: | :-------------------------------------------: | | `BURRITO_CONTROLLER_GITHUBCONFIG_APITOKEN` | the API token to send comment to GitHub's API | | `BURRITO_CONTROLLER_GITLABCONFIG_APITOKEN` | the API token to send comment to GitLab's API | +| `BURRITO_CONTROLLER_GITLABCONFIG_URL` | the URL of the GitLab instance | diff --git a/docs/user-guide/index.md b/docs/user-guide/index.md index 93981ea2..40fd0dc5 100644 --- a/docs/user-guide/index.md +++ b/docs/user-guide/index.md @@ -3,4 +3,4 @@ This guide is for developers who have burrito installed for them and are managing layers. !!! note - Please make sure you've completed the [getting started guide](../getting_started.md). + Please make sure you've completed the [getting started guide](../getting-started.md). diff --git a/docs/user-guide/override-runner.md b/docs/user-guide/override-runner.md index 73777c17..4dfba3f7 100644 --- a/docs/user-guide/override-runner.md +++ b/docs/user-guide/override-runner.md @@ -23,7 +23,6 @@ Available overrides are: | `Metadata.Annotations` | | `Metadata.Labels` | - For instance with the following configuration, all the runner pods will have the specifications described inside the `TerraformRepository`: ```yaml @@ -57,7 +56,6 @@ spec: path: "internal/e2e/testdata/random-pets" branch: "main" repository: - kind: TerraformRepository name: burrito namespace: burrito ``` @@ -95,7 +93,6 @@ spec: path: "internal/e2e/testdata/random-pets" branch: "main" repository: - kind: TerraformRepository name: burrito namespace: burrito overrideRunnerSpec: diff --git a/docs/user-guide/private-modules.md b/docs/user-guide/private-modules.md index 5fb1f75a..8abc2077 100644 --- a/docs/user-guide/private-modules.md +++ b/docs/user-guide/private-modules.md @@ -1,6 +1,6 @@ # Configure the TerraformLayer to use private modules' repositories -If your stack use Terraform modules that are hosted on private repositories, you can configure the `TerraformLayer` to be able to use thos private modules by [configuring the `overrideRunnerSpec` in your resource definition](./override-runner.md). +If your stack use Terraform modules that are hosted on private repositories, you can configure the `TerraformLayer` to be able to use those private modules by [configuring the `overrideRunnerSpec` in your resource definition](./override-runner.md). ## The layer uses a private module with HTTPS @@ -136,5 +136,6 @@ spec: As you can see, we added a new `overrideRunnerSpec` field to the `TerraformLayer` spec. This field allows you to override the default runner pod spec. In this case, we added a new volume and a new environment variable to the runner pod spec: + - The volume is a secret volume that contains the SSH key we created earlier - The environment variable is used to tell git to use the SSH key we added to the runner pod diff --git a/docs/user-guide/terraform-version.md b/docs/user-guide/terraform-version.md index f913dbfe..ad920f3c 100644 --- a/docs/user-guide/terraform-version.md +++ b/docs/user-guide/terraform-version.md @@ -27,7 +27,6 @@ spec: path: "internal/e2e/testdata/terragrunt/random-pets/prod" branch: "feat/handle-terragrunt" repository: - kind: TerraformRepository name: burrito namespace: burrito ``` diff --git a/internal/burrito/config/config.go b/internal/burrito/config/config.go index ca4aee16..9d68a7f8 100644 --- a/internal/burrito/config/config.go +++ b/internal/burrito/config/config.go @@ -12,85 +12,86 @@ import ( ) type Config struct { - Runner RunnerConfig `yaml:"runner"` - Controller ControllerConfig `yaml:"controller"` - Redis Redis `yaml:"redis"` - Server ServerConfig `yaml:"server"` + Runner RunnerConfig `mapstructure:"runner"` + Controller ControllerConfig `mapstructure:"controller"` + Redis Redis `mapstructure:"redis"` + Server ServerConfig `mapstructure:"server"` } type WebhookConfig struct { - Github WebhookGithubConfig `yaml:"github"` - Gitlab WebhookGitlabConfig `yaml:"gitlab"` + Github WebhookGithubConfig `mapstructure:"github"` + Gitlab WebhookGitlabConfig `mapstructure:"gitlab"` } type WebhookGithubConfig struct { - Secret string `yaml:"secret"` + Secret string `mapstructure:"secret"` } type WebhookGitlabConfig struct { - Secret string `yaml:"secret"` + Secret string `mapstructure:"secret"` } type ControllerConfig struct { - Namespaces []string `yaml:"namespaces"` - Timers ControllerTimers `yaml:"timers"` - Types []string `yaml:"types"` - LeaderElection LeaderElectionConfig `yaml:"leaderElection"` - MetricsBindAddress string `yaml:"metricsBindAddress"` - HealthProbeBindAddress string `yaml:"healthProbeBindAddress"` - KubernetesWebhookPort int `yaml:"kubernetesWebhookPort"` - GithubConfig GithubConfig `yaml:"githubConfig"` - GitlabConfig GitlabConfig `yaml:"gitlabConfig"` + Namespaces []string `mapstructure:"namespaces"` + Timers ControllerTimers `mapstructure:"timers"` + Types []string `mapstructure:"types"` + LeaderElection LeaderElectionConfig `mapstructure:"leaderElection"` + MetricsBindAddress string `mapstructure:"metricsBindAddress"` + HealthProbeBindAddress string `mapstructure:"healthProbeBindAddress"` + KubernetesWebhookPort int `mapstructure:"kubernetesWebhookPort"` + GithubConfig GithubConfig `mapstructure:"githubConfig"` + GitlabConfig GitlabConfig `mapstructure:"gitlabConfig"` } type GithubConfig struct { - APIToken string `yaml:"apiToken"` + APIToken string `mapstructure:"apiToken"` } type GitlabConfig struct { - APIToken string `yaml:"apiToken"` - URL string `yaml:"url"` + APIToken string `mapstructure:"apiToken"` + URL string `mapstructure:"url"` } type LeaderElectionConfig struct { - Enabled bool `yaml:"enabled"` - ID string `yaml:"id"` + Enabled bool `mapstructure:"enabled"` + ID string `mapstructure:"id"` } type ControllerTimers struct { - DriftDetection time.Duration `yaml:"driftDetection"` - OnError time.Duration `yaml:"onError"` - WaitAction time.Duration `yaml:"waitAction"` - FailureGracePeriod time.Duration `yaml:"failureGracePeriod"` + DriftDetection time.Duration `mapstructure:"driftDetection"` + OnError time.Duration `mapstructure:"onError"` + WaitAction time.Duration `mapstructure:"waitAction"` + FailureGracePeriod time.Duration `mapstructure:"failureGracePeriod"` } type RepositoryConfig struct { - SSHPrivateKey string `yaml:"sshPrivateKey"` - Username string `yaml:"username"` - Password string `yaml:"password"` + SSHPrivateKey string `mapstructure:"sshPrivateKey"` + Username string `mapstructure:"username"` + Password string `mapstructure:"password"` } type RunnerConfig struct { - Action string `yaml:"action"` - Layer Layer `yaml:"layer"` - Repository RepositoryConfig `yaml:"repository"` - SSHKnownHostsConfigMapName string `yaml:"sshKnownHostsConfigMapName"` + Action string `mapstructure:"action"` + Layer Layer `mapstructure:"layer"` + Repository RepositoryConfig `mapstructure:"repository"` + SSHKnownHostsConfigMapName string `mapstructure:"sshKnownHostsConfigMapName"` } type Layer struct { - Name string `yaml:"name"` - Namespace string `yaml:"namespace"` + Name string `mapstructure:"name"` + Namespace string `mapstructure:"namespace"` } type Redis struct { - URL string `yaml:"url"` - Password string `yaml:"password"` - Database int `yaml:"database"` + Hostname string `mapstructure:"hostname"` + ServerPort int `mapstructure:"serverPort"` + Password string `mapstructure:"password"` + Database int `mapstructure:"database"` } type ServerConfig struct { - Addr string `yaml:"port"` - Webhook WebhookConfig `yaml:"webhook"` + Addr string `mapstructure:"addr"` + Webhook WebhookConfig `mapstructure:"webhook"` } func (c *Config) Load(flags *pflag.FlagSet) error { @@ -142,7 +143,7 @@ func bindEnvironmentVariables(v *viper.Viper, iface interface{}, parts ...string for i := 0; i < ift.NumField(); i++ { val := ifv.Field(i) typ := ift.Field(i) - tv, ok := typ.Tag.Lookup("yaml") + tv, ok := typ.Tag.Lookup("mapstructure") if !ok { continue } @@ -158,9 +159,10 @@ func bindEnvironmentVariables(v *viper.Viper, iface interface{}, parts ...string func TestConfig() *Config { return &Config{ Redis: Redis{ - URL: "redis://localhost:6379", - Password: "", - Database: 0, + Hostname: "localhost", + ServerPort: 6379, + Password: "", + Database: 0, }, Controller: ControllerConfig{ Timers: ControllerTimers{ diff --git a/internal/burrito/config/config_test.go b/internal/burrito/config/config_test.go index 0ffec7f0..32c5d297 100644 --- a/internal/burrito/config/config_test.go +++ b/internal/burrito/config/config_test.go @@ -76,12 +76,13 @@ func TestConfig_FromYamlFile(t *testing.T) { }, }, Redis: config.Redis{ - URL: "burrito-redis:6379", - Database: 0, - Password: "testPassword", + Hostname: "burrito-redis.namespace", + ServerPort: 5000, + Database: 0, + Password: "testPassword", }, Server: config.ServerConfig{ - Addr: ":8080", + Addr: ":9090", Webhook: config.WebhookConfig{ Github: config.WebhookGithubConfig{ Secret: "github-secret", @@ -131,7 +132,8 @@ func TestConfig_EnvVarOverrides(t *testing.T) { setEnvVar(t, "BURRITO_RUNNER_REPOSITORY_PASSWORD", "other-password", &envVarList) setEnvVar(t, "BURRITO_RUNNER_REPOSITORY_SSHPRIVATEKEY", "other-private-key", &envVarList) // Redis - setEnvVar(t, "BURRITO_REDIS_URL", "other-redis:6379", &envVarList) + setEnvVar(t, "BURRITO_REDIS_HOSTNAME", "other-redis", &envVarList) + setEnvVar(t, "BURRITO_REDIS_SERVERPORT", "8000", &envVarList) setEnvVar(t, "BURRITO_REDIS_DATABASE", "1", &envVarList) setEnvVar(t, "BURRITO_REDIS_PASSWORD", "otherPassword", &envVarList) // Controller @@ -207,9 +209,10 @@ func TestConfig_EnvVarOverrides(t *testing.T) { }, }, Redis: config.Redis{ - URL: "other-redis:6379", - Database: 1, - Password: "otherPassword", + Hostname: "other-redis", + ServerPort: 8000, + Database: 1, + Password: "otherPassword", }, Server: config.ServerConfig{ Addr: ":8090", diff --git a/internal/burrito/config/testdata/test-config-1.yaml b/internal/burrito/config/testdata/test-config-1.yaml index c7c8570d..ddb1cae2 100644 --- a/internal/burrito/config/testdata/test-config-1.yaml +++ b/internal/burrito/config/testdata/test-config-1.yaml @@ -32,12 +32,13 @@ controller: url: "https://gitlab.example.com" redis: - url: "burrito-redis:6379" + hostname: "burrito-redis.namespace" + serverPort: 5000 database: 0 password: "testPassword" server: - addr: ":8080" + addr: ":9090" webhook: github: secret: "github-secret" diff --git a/internal/controllers/manager.go b/internal/controllers/manager.go index 748337c7..6fb99efe 100644 --- a/internal/controllers/manager.go +++ b/internal/controllers/manager.go @@ -91,7 +91,7 @@ func (c *Controllers) Exec() { Client: mgr.GetClient(), Scheme: mgr.GetScheme(), Config: c.config, - Storage: redis.New(c.config.Redis.URL, c.config.Redis.Password, c.config.Redis.Database), + Storage: redis.New(c.config.Redis), }).SetupWithManager(mgr); err != nil { log.Fatalf("unable to create layer controller: %s", err) } diff --git a/internal/controllers/terraformlayer/pod.go b/internal/controllers/terraformlayer/pod.go index 18f9910c..35c06fda 100644 --- a/internal/controllers/terraformlayer/pod.go +++ b/internal/controllers/terraformlayer/pod.go @@ -159,8 +159,12 @@ func defaultPodSpec(config *config.Config, layer *configv1alpha1.TerraformLayer, }, Env: []corev1.EnvVar{ { - Name: "BURRITO_REDIS_URL", - Value: config.Redis.URL, + Name: "BURRITO_REDIS_HOSTNAME", + Value: config.Redis.Hostname, + }, + { + Name: "BURRITO_REDIS_SERVERPORT", + Value: fmt.Sprintf("%d", config.Redis.ServerPort), }, { Name: "BURRITO_REDIS_PASSWORD", diff --git a/internal/controllers/terraformpullrequest/controller.go b/internal/controllers/terraformpullrequest/controller.go index 148d40cd..44adbf3f 100644 --- a/internal/controllers/terraformpullrequest/controller.go +++ b/internal/controllers/terraformpullrequest/controller.go @@ -107,7 +107,7 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { providers = append(providers, p) } r.Providers = providers - r.Storage = redis.New(r.Config.Redis.URL, r.Config.Redis.Password, r.Config.Redis.Database) + r.Storage = redis.New(r.Config.Redis) return ctrl.NewControllerManagedBy(mgr). For(&configv1alpha1.TerraformPullRequest{}). WithEventFilter(ignorePredicate()). diff --git a/internal/runner/runner.go b/internal/runner/runner.go index 0b5b9a48..f46e26c0 100644 --- a/internal/runner/runner.go +++ b/internal/runner/runner.go @@ -117,6 +117,7 @@ func (r *Runner) Exec() { func (r *Runner) getLayerAndRepository() error { layer := &configv1alpha1.TerraformLayer{} + log.Infof("getting layer %s/%s", r.config.Runner.Layer.Namespace, r.config.Runner.Layer.Name) err := r.client.Get(context.TODO(), types.NamespacedName{ Namespace: r.config.Runner.Layer.Namespace, Name: r.config.Runner.Layer.Name, @@ -124,8 +125,10 @@ func (r *Runner) getLayerAndRepository() error { if err != nil { return err } + log.Infof("successfully retrieved layer") r.layer = layer repository := &configv1alpha1.TerraformRepository{} + log.Infof("getting repo %s/%s", layer.Spec.Repository.Namespace, layer.Spec.Repository.Name) err = r.client.Get(context.TODO(), types.NamespacedName{ Namespace: layer.Spec.Repository.Namespace, Name: layer.Spec.Repository.Name, @@ -133,6 +136,7 @@ func (r *Runner) getLayerAndRepository() error { if err != nil { return err } + log.Infof("successfully retrieved repo") r.repository = repository return nil } @@ -173,7 +177,7 @@ func (r *Runner) install() error { } func (r *Runner) init() error { - r.storage = redis.New(r.config.Redis.URL, r.config.Redis.Password, r.config.Redis.Database) + r.storage = redis.New(r.config.Redis) log.Infof("retrieving linked TerraformLayer and TerraformRepository") cl, err := newK8SClient() if err != nil { diff --git a/internal/storage/redis/redis.go b/internal/storage/redis/redis.go index 00b84113..686c1041 100644 --- a/internal/storage/redis/redis.go +++ b/internal/storage/redis/redis.go @@ -2,9 +2,11 @@ package redis import ( "context" + "fmt" "time" "github.com/go-redis/redis/v8" + "github.com/padok-team/burrito/internal/burrito/config" "github.com/padok-team/burrito/internal/storage" ) @@ -12,12 +14,12 @@ type Storage struct { Client *redis.Client } -func New(addr string, password string, db int) *Storage { +func New(config config.Redis) *Storage { return &Storage{ Client: redis.NewClient(&redis.Options{ - Addr: addr, - Password: password, // no password set - DB: db, // use default DB + Addr: fmt.Sprintf("%s:%d", config.Hostname, config.ServerPort), + Password: config.Password, // no password set + DB: config.Database, // use default DB }), } } diff --git a/manifests/base/config/burrito-config-cm.yaml b/manifests/base/config/burrito-config-cm.yaml index 58df26c5..a388e51a 100644 --- a/manifests/base/config/burrito-config-cm.yaml +++ b/manifests/base/config/burrito-config-cm.yaml @@ -5,4 +5,3 @@ metadata: app.kubernetes.io/name: burrito-config app.kubernetes.io/part-of: burrito name: burrito-config - namespace: burrito diff --git a/manifests/base/config/burrito-config-secret.yaml b/manifests/base/config/burrito-config-secret.yaml index 53a5f4ea..4cb6e37d 100644 --- a/manifests/base/config/burrito-config-secret.yaml +++ b/manifests/base/config/burrito-config-secret.yaml @@ -5,5 +5,4 @@ metadata: app.kubernetes.io/name: burrito-config app.kubernetes.io/part-of: burrito name: burrito-config - namespace: burrito type: Opaque diff --git a/manifests/base/config/burrito-ssh-known-hosts.yaml b/manifests/base/config/burrito-ssh-known-hosts.yaml index 5c75d69e..f669426d 100644 --- a/manifests/base/config/burrito-ssh-known-hosts.yaml +++ b/manifests/base/config/burrito-ssh-known-hosts.yaml @@ -5,7 +5,6 @@ metadata: app.kubernetes.io/part-of: burrito app.kubernetes.io/name: burrito-ssh-known-hosts name: burrito-ssh-known-hosts - namespace: burrito data: known_hosts: |- bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw== diff --git a/manifests/base/controllers/deployment.yaml b/manifests/base/controllers/deployment.yaml index b63b42b7..3f1e1a3a 100644 --- a/manifests/base/controllers/deployment.yaml +++ b/manifests/base/controllers/deployment.yaml @@ -6,7 +6,6 @@ metadata: app.kubernetes.io/component: controllers app.kubernetes.io/name: burrito-controllers app.kubernetes.io/part-of: burrito - namespace: burrito spec: selector: matchLabels: @@ -22,13 +21,12 @@ spec: securityContext: runAsNonRoot: true containers: - - command: - - /burrito + - name: burrito args: - controllers - start + - --namespaces=burrito image: ghcr.io/padok-team/burrito:main - name: burrito imagePullPolicy: Always envFrom: - configMapRef: diff --git a/manifests/base/controllers/serviceaccount.yaml b/manifests/base/controllers/serviceaccount.yaml index d282b99b..2ae56f47 100644 --- a/manifests/base/controllers/serviceaccount.yaml +++ b/manifests/base/controllers/serviceaccount.yaml @@ -2,7 +2,6 @@ apiVersion: v1 kind: ServiceAccount metadata: name: burrito-controllers - namespace: burrito labels: app.kubernetes.io/component: controllers app.kubernetes.io/name: burrito-controllers diff --git a/manifests/base/redis/deployment.yaml b/manifests/base/redis/deployment.yaml index b848f4e2..07412d02 100644 --- a/manifests/base/redis/deployment.yaml +++ b/manifests/base/redis/deployment.yaml @@ -6,7 +6,6 @@ metadata: app.kubernetes.io/name: burrito-redis app.kubernetes.io/part-of: burrito name: burrito-redis - namespace: burrito spec: selector: matchLabels: diff --git a/manifests/base/redis/service.yaml b/manifests/base/redis/service.yaml index 029a609c..8d3a8223 100644 --- a/manifests/base/redis/service.yaml +++ b/manifests/base/redis/service.yaml @@ -6,7 +6,6 @@ metadata: app.kubernetes.io/name: burrito-redis app.kubernetes.io/part-of: burrito name: burrito-redis - namespace: burrito spec: ports: - name: tcp-redis diff --git a/manifests/base/redis/serviceaccount.yaml b/manifests/base/redis/serviceaccount.yaml index dbe9aa72..9fa099ff 100644 --- a/manifests/base/redis/serviceaccount.yaml +++ b/manifests/base/redis/serviceaccount.yaml @@ -6,4 +6,3 @@ metadata: app.kubernetes.io/name: burrito-redis app.kubernetes.io/part-of: burrito name: burrito-redis - namespace: burrito diff --git a/manifests/base/runner/serviceaccount.yaml b/manifests/base/runner/serviceaccount.yaml index e0eba861..c8e150bb 100644 --- a/manifests/base/runner/serviceaccount.yaml +++ b/manifests/base/runner/serviceaccount.yaml @@ -2,7 +2,6 @@ apiVersion: v1 kind: ServiceAccount metadata: name: burrito-runner - namespace: burrito labels: app.kubernetes.io/component: runner app.kubernetes.io/name: burrito-runner diff --git a/manifests/base/server/deployment.yaml b/manifests/base/server/deployment.yaml index fea916eb..e0be7dfa 100644 --- a/manifests/base/server/deployment.yaml +++ b/manifests/base/server/deployment.yaml @@ -6,7 +6,6 @@ metadata: app.kubernetes.io/component: server app.kubernetes.io/name: burrito-server app.kubernetes.io/part-of: burrito - namespace: burrito spec: selector: matchLabels: @@ -22,8 +21,7 @@ spec: securityContext: runAsNonRoot: true containers: - - command: - - /burrito + - name: burrito args: - server - start @@ -38,7 +36,6 @@ spec: name: burrito-config optional: true image: ghcr.io/padok-team/burrito:main - name: burrito imagePullPolicy: Always securityContext: allowPrivilegeEscalation: false diff --git a/manifests/base/server/service.yaml b/manifests/base/server/service.yaml index dd33ec48..ed846630 100644 --- a/manifests/base/server/service.yaml +++ b/manifests/base/server/service.yaml @@ -6,7 +6,6 @@ metadata: app.kubernetes.io/name: burrito-server app.kubernetes.io/part-of: burrito name: burrito-server - namespace: burrito spec: ports: - name: http diff --git a/manifests/base/server/serviceaccount.yaml b/manifests/base/server/serviceaccount.yaml index f3ce7942..3921ff5c 100644 --- a/manifests/base/server/serviceaccount.yaml +++ b/manifests/base/server/serviceaccount.yaml @@ -2,7 +2,6 @@ apiVersion: v1 kind: ServiceAccount metadata: name: burrito-server - namespace: burrito labels: app.kubernetes.io/component: server app.kubernetes.io/name: burrito-server diff --git a/manifests/install.yaml b/manifests/install.yaml index c3548def..4127d184 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -2754,7 +2754,6 @@ metadata: app.kubernetes.io/name: burrito-controllers app.kubernetes.io/part-of: burrito name: burrito-controllers - namespace: burrito --- apiVersion: v1 kind: ServiceAccount @@ -2764,7 +2763,6 @@ metadata: app.kubernetes.io/name: burrito-redis app.kubernetes.io/part-of: burrito name: burrito-redis - namespace: burrito --- apiVersion: v1 kind: ServiceAccount @@ -2774,7 +2772,6 @@ metadata: app.kubernetes.io/name: burrito-runner app.kubernetes.io/part-of: burrito name: burrito-runner - namespace: burrito --- apiVersion: v1 kind: ServiceAccount @@ -2784,7 +2781,6 @@ metadata: app.kubernetes.io/name: burrito-server app.kubernetes.io/part-of: burrito name: burrito-server - namespace: burrito --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -3062,7 +3058,6 @@ metadata: app.kubernetes.io/name: burrito-config app.kubernetes.io/part-of: burrito name: burrito-config - namespace: burrito --- apiVersion: v1 data: @@ -3082,7 +3077,6 @@ metadata: app.kubernetes.io/name: burrito-ssh-known-hosts app.kubernetes.io/part-of: burrito name: burrito-ssh-known-hosts - namespace: burrito --- apiVersion: v1 kind: Secret @@ -3091,7 +3085,6 @@ metadata: app.kubernetes.io/name: burrito-config app.kubernetes.io/part-of: burrito name: burrito-config - namespace: burrito type: Opaque --- apiVersion: v1 @@ -3102,7 +3095,6 @@ metadata: app.kubernetes.io/name: burrito-redis app.kubernetes.io/part-of: burrito name: burrito-redis - namespace: burrito spec: ports: - name: tcp-redis @@ -3119,7 +3111,6 @@ metadata: app.kubernetes.io/name: burrito-server app.kubernetes.io/part-of: burrito name: burrito-server - namespace: burrito spec: ports: - name: http @@ -3137,7 +3128,6 @@ metadata: app.kubernetes.io/name: burrito-controllers app.kubernetes.io/part-of: burrito name: burrito-controllers - namespace: burrito spec: replicas: 1 selector: @@ -3154,8 +3144,7 @@ spec: - args: - controllers - start - command: - - /burrito + - --namespaces=burrito envFrom: - configMapRef: name: burrito-config @@ -3196,7 +3185,6 @@ metadata: app.kubernetes.io/name: burrito-redis app.kubernetes.io/part-of: burrito name: burrito-redis - namespace: burrito spec: selector: matchLabels: @@ -3233,7 +3221,6 @@ metadata: app.kubernetes.io/name: burrito-server app.kubernetes.io/part-of: burrito name: burrito-server - namespace: burrito spec: replicas: 1 selector: @@ -3250,8 +3237,6 @@ spec: - args: - server - start - command: - - /burrito envFrom: - configMapRef: name: burrito-config diff --git a/mkdocs.yml b/mkdocs.yml index ded88736..c64c0372 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -13,10 +13,14 @@ nav: - Overview: index.md - Getting Started: getting-started.md - Operator Manual: + - Install: + - With static manifests: operator-manual/install/with-static-manifests.md + - With our Helm chart: operator-manual/install/with-helm.md - operator-manual/index.md - operator-manual/architecture.md - operator-manual/git-webhook.md - operator-manual/advanced-configuration.md + - operator-manual/multi-tenant-architecture.md - operator-manual/pr-mr-workflow.md - User Guide: - user-guide/index.md