diff --git a/.gitignore b/.gitignore index 5c5ef1f27..fbbb5b1c3 100644 --- a/.gitignore +++ b/.gitignore @@ -19,7 +19,7 @@ terraform/account.json **/.terraform/* /.mvn/wrapper/maven-wrapper.jar # Is created on "helm dep update ." but not needed in repo -/argocd/argocd/argocd/charts/ +/argocd/cluster-resources/apps/argocd/argocd/charts/ gitops-playground.jar jenkins-plugins diff --git a/README.md b/README.md index e032fc3fd..c94f4ceab 100644 --- a/README.md +++ b/README.md @@ -648,7 +648,7 @@ features: In this Example we override the default `controller.replicaCount` (GOP's default is 2). This config file is merged with precedence over the defaults set by -* [the GOP](applications/cluster-resources/ingress-nginx-helm-values.ftl.yaml) and +* [the GOP](argocd/cluster-resources/apps/ingress/templates/ingress-nginx-helm-values.ftl.yaml) and * [the charts itself](https://github.com/kubernetes/ingress-nginx/blob/main/charts/ingress-nginx/values.yaml). ##### Deploy Ingresses @@ -1067,7 +1067,7 @@ From there, everything is managed via GitOps. This diagram shows how it works. ingresses) via the `templates` folder. The actual ArgoCD chart is declared in the `Chart.yaml` 3. The `Chart.yaml` contains the Argo CD helm chart as `dependency`. It points to a deterministic version of the Chart (pinned via `Chart.lock`) that is pulled from the Chart repository on the internet. - This mechanism can be used to upgrade Argo CD via GitOps. See the [Readme of the argocd repository](argocd/argocd/README.md) + This mechanism can be used to upgrade Argo CD via GitOps. See the [Readme of the argocd repository](argocd/cluster-resources/apps/argocd/README.md) for details. 4. The `projects` application manages the `projects` folder, that contains the following `AppProjects`: * the `argocd` project, used for bootstrapping @@ -1098,7 +1098,7 @@ From there, everything is managed via GitOps. This diagram shows how it works. * Two applications in the same YAML (implemented in the playground, see e.g. [`petclinic-plain.yaml`](argocd/example-apps/argocd/petclinic-plain.ftl.yaml)) * Two application with the same name in different namespaces, when ArgoCD is enabled to search for applications within different namespaces (implemented in the playground, see - [Argo CD's values.yaml](argocd/argocd/argocd/values.ftl.yaml) - `application.namespaces` setting) + [Argo CD's values.yaml](argocd/cluster-resources/apps/argocd/argocd/values.ftl.yaml) - `application.namespaces` setting) * One `ApplicationSet`, using the [`git` generator for directories](https://github.com/argoproj/argo-cd/blob/v2.7.1/docs/operator-manual/applicationset/Generators-Git.md#git-generator-directories) (not used in GitOps playground, yet) @@ -1348,7 +1348,7 @@ The `.petlinic.` part can be overridden using #### PetClinic with plain k8s resources -[Jenkinsfile](applications/petclinic/argocd/plain-k8s/Jenkinsfile) for `plain` deployment +[Jenkinsfile](examples/example-apps-via-content-loader/argocd/petclinic-plain/Jenkinsfile) for `plain` deployment * Staging: http://staging.petclinic-plain.petclinic.localhost/ * Production: http://production.petclinic-plain.petclinic.localhost/ @@ -1356,7 +1356,7 @@ The `.petlinic.` part can be overridden using #### PetClinic with helm -[Jenkinsfile](applications/petclinic/argocd/helm/Jenkinsfile) for `helm` deployment +[Jenkinsfile](examples/example-apps-via-content-loader/argocd/petclinic-helm/Jenkinsfile) for `helm` deployment * Staging: http://staging.petclinic-helm.petclinic.localhost/ * Production: http://production.petclinic-helm.petclinic.localhost/ diff --git a/argocd/argocd/applications/projects.ftl.yaml b/argocd/argocd/applications/projects.ftl.yaml deleted file mode 100644 index 9c66cd88e..000000000 --- a/argocd/argocd/applications/projects.ftl.yaml +++ /dev/null @@ -1,23 +0,0 @@ -apiVersion: argoproj.io/v1alpha1 -kind: Application -metadata: - name: projects - namespace: ${config.application.namePrefix}argocd -# finalizer disabled, because otherwise everything under this Application would be deleted as well, if this Application is deleted by accident -# finalizers: -# - resources-finalizer.argocd.argoproj.io -spec: - destination: - server: https://kubernetes.default.svc - namespace: ${config.application.namePrefix}argocd - project: argocd - source: - path: projects/ - repoURL: ${scm.repoUrl}argocd/argocd.git - targetRevision: main - directory: - recurse: true - syncPolicy: - automated: - prune: false # is set to false to prevent projects to be deleted by accident - selfHeal: true \ No newline at end of file diff --git a/argocd/argocd/multiTenant/central/applications/projects.ftl.yaml b/argocd/argocd/multiTenant/central/applications/projects.ftl.yaml deleted file mode 100644 index 22daaf97b..000000000 --- a/argocd/argocd/multiTenant/central/applications/projects.ftl.yaml +++ /dev/null @@ -1,23 +0,0 @@ -apiVersion: argoproj.io/v1alpha1 -kind: Application -metadata: - name: ${config.application.namePrefix}projects - namespace: ${config.multiTenant.centralArgocdNamespace} -# finalizer disabled, because otherwise everything under this Application would be deleted as well, if this Application is deleted by accident -# finalizers: -# - resources-finalizer.argocd.argoproj.io -spec: - destination: - server: https://kubernetes.default.svc - namespace: ${config.application.namePrefix}argocd - project: ${tenantName} - source: - path: multiTenant/central/projects/ - repoURL: ${scm.centralScmUrl}argocd/argocd.git - targetRevision: main - directory: - recurse: true - syncPolicy: - automated: - prune: false # is set to false to prevent projects to be deleted by accident - selfHeal: true \ No newline at end of file diff --git a/argocd/cluster-resources/apps/.gitkeep b/argocd/cluster-resources/apps/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/argocd/argocd/README.md b/argocd/cluster-resources/apps/argocd/README.md similarity index 100% rename from argocd/argocd/README.md rename to argocd/cluster-resources/apps/argocd/README.md diff --git a/argocd/argocd/applications/argocd.ftl.yaml b/argocd/cluster-resources/apps/argocd/applications/argocd.ftl.yaml similarity index 89% rename from argocd/argocd/applications/argocd.ftl.yaml rename to argocd/cluster-resources/apps/argocd/applications/argocd.ftl.yaml index 99a0f6a4b..3fbe9e597 100644 --- a/argocd/argocd/applications/argocd.ftl.yaml +++ b/argocd/cluster-resources/apps/argocd/applications/argocd.ftl.yaml @@ -18,8 +18,8 @@ spec: namespace: ${config.application.namePrefix}argocd project: argocd source: - path: ${config.features.argocd.operator?string("operator/", "argocd/")} - repoURL: ${scm.repoUrl}argocd/argocd.git + path: apps/argocd/${config.features.argocd.operator?string("operator/", "argocd/")} + repoURL: ${scm.repoUrl}argocd/cluster-resources.git targetRevision: main # needed to sync the operator/rbac folder <#if config.features.argocd.operator> diff --git a/argocd/argocd/applications/bootstrap.ftl.yaml b/argocd/cluster-resources/apps/argocd/applications/bootstrap.ftl.yaml similarity index 89% rename from argocd/argocd/applications/bootstrap.ftl.yaml rename to argocd/cluster-resources/apps/argocd/applications/bootstrap.ftl.yaml index 6454ab3ad..044bdef7a 100644 --- a/argocd/argocd/applications/bootstrap.ftl.yaml +++ b/argocd/cluster-resources/apps/argocd/applications/bootstrap.ftl.yaml @@ -13,8 +13,8 @@ spec: namespace: ${config.application.namePrefix}argocd project: argocd source: - path: applications/ - repoURL: ${scm.repoUrl}argocd/argocd.git + path: apps/argocd/applications/ + repoURL: ${scm.repoUrl}argocd/cluster-resources.git targetRevision: main directory: recurse: true diff --git a/argocd/argocd/applications/cluster-resources.ftl.yaml b/argocd/cluster-resources/apps/argocd/applications/projects.ftl.yaml similarity index 93% rename from argocd/argocd/applications/cluster-resources.ftl.yaml rename to argocd/cluster-resources/apps/argocd/applications/projects.ftl.yaml index 9b4b11302..49237a4ed 100644 --- a/argocd/argocd/applications/cluster-resources.ftl.yaml +++ b/argocd/cluster-resources/apps/argocd/applications/projects.ftl.yaml @@ -1,18 +1,18 @@ apiVersion: argoproj.io/v1alpha1 kind: Application metadata: - name: cluster-resources + name: projects namespace: ${config.application.namePrefix}argocd # finalizer disabled, because otherwise everything under this Application would be deleted as well, if this Application is deleted by accident # finalizers: # - resources-finalizer.argocd.argoproj.io spec: destination: - namespace: ${config.application.namePrefix}argocd server: https://kubernetes.default.svc + namespace: ${config.application.namePrefix}argocd project: argocd source: - path: argocd/ + path: apps/argocd/projects/ repoURL: ${scm.repoUrl}argocd/cluster-resources.git targetRevision: main directory: diff --git a/argocd/argocd/argocd/Chart.lock b/argocd/cluster-resources/apps/argocd/argocd/Chart.lock similarity index 100% rename from argocd/argocd/argocd/Chart.lock rename to argocd/cluster-resources/apps/argocd/argocd/Chart.lock diff --git a/argocd/argocd/argocd/Chart.yaml b/argocd/cluster-resources/apps/argocd/argocd/Chart.yaml similarity index 100% rename from argocd/argocd/argocd/Chart.yaml rename to argocd/cluster-resources/apps/argocd/argocd/Chart.yaml diff --git a/argocd/argocd/argocd/templates/.gitkeep b/argocd/cluster-resources/apps/argocd/argocd/templates/.gitkeep similarity index 100% rename from argocd/argocd/argocd/templates/.gitkeep rename to argocd/cluster-resources/apps/argocd/argocd/templates/.gitkeep diff --git a/argocd/argocd/argocd/templates/allow-namespaces.ftl.yaml b/argocd/cluster-resources/apps/argocd/argocd/templates/allow-namespaces.ftl.yaml similarity index 100% rename from argocd/argocd/argocd/templates/allow-namespaces.ftl.yaml rename to argocd/cluster-resources/apps/argocd/argocd/templates/allow-namespaces.ftl.yaml diff --git a/argocd/argocd/argocd/values.ftl.yaml b/argocd/cluster-resources/apps/argocd/argocd/values.ftl.yaml similarity index 100% rename from argocd/argocd/argocd/values.ftl.yaml rename to argocd/cluster-resources/apps/argocd/argocd/values.ftl.yaml diff --git a/argocd/argocd/multiTenant/central/applications/argocd.ftl.yaml b/argocd/cluster-resources/apps/argocd/multiTenant/central/applications/argocd.ftl.yaml similarity index 89% rename from argocd/argocd/multiTenant/central/applications/argocd.ftl.yaml rename to argocd/cluster-resources/apps/argocd/multiTenant/central/applications/argocd.ftl.yaml index 994685220..924056ebc 100644 --- a/argocd/argocd/multiTenant/central/applications/argocd.ftl.yaml +++ b/argocd/cluster-resources/apps/argocd/multiTenant/central/applications/argocd.ftl.yaml @@ -18,8 +18,8 @@ spec: namespace: ${config.application.namePrefix}argocd project: ${tenantName} source: - path: ${config.features.argocd.operator?string("operator/", "argocd/")} - repoURL: ${scm.centralScmUrl}argocd/argocd.git + path: apps/argocd/${config.features.argocd.operator?string("operator/", "argocd/")} + repoURL: ${scm.centralScmUrl}argocd/cluster-resources.git targetRevision: main # needed to sync the operator/rbac folder <#if config.features.argocd.operator??> diff --git a/argocd/argocd/multiTenant/central/applications/bootstrap.ftl.yaml b/argocd/cluster-resources/apps/argocd/multiTenant/central/applications/bootstrap.ftl.yaml similarity index 87% rename from argocd/argocd/multiTenant/central/applications/bootstrap.ftl.yaml rename to argocd/cluster-resources/apps/argocd/multiTenant/central/applications/bootstrap.ftl.yaml index 71a56c1af..f06b238a4 100644 --- a/argocd/argocd/multiTenant/central/applications/bootstrap.ftl.yaml +++ b/argocd/cluster-resources/apps/argocd/multiTenant/central/applications/bootstrap.ftl.yaml @@ -13,8 +13,8 @@ spec: namespace: ${config.application.namePrefix}argocd project: ${tenantName} source: - path: multiTenant/central/applications/ - repoURL: ${scm.centralScmUrl}argocd/argocd.git + path: apps/argocd/multiTenant/central/applications/ + repoURL: ${scm.centralScmUrl}argocd/cluster-resources.git targetRevision: main directory: recurse: true diff --git a/argocd/argocd/multiTenant/central/applications/cluster-resources.ftl.yaml b/argocd/cluster-resources/apps/argocd/multiTenant/central/applications/projects.ftl.yaml similarity index 87% rename from argocd/argocd/multiTenant/central/applications/cluster-resources.ftl.yaml rename to argocd/cluster-resources/apps/argocd/multiTenant/central/applications/projects.ftl.yaml index b27f1a8c0..6e69e0692 100644 --- a/argocd/argocd/multiTenant/central/applications/cluster-resources.ftl.yaml +++ b/argocd/cluster-resources/apps/argocd/multiTenant/central/applications/projects.ftl.yaml @@ -1,18 +1,18 @@ apiVersion: argoproj.io/v1alpha1 kind: Application metadata: - name: ${config.application.namePrefix}cluster-resources + name: ${config.application.namePrefix}projects namespace: ${config.multiTenant.centralArgocdNamespace} # finalizer disabled, because otherwise everything under this Application would be deleted as well, if this Application is deleted by accident # finalizers: # - resources-finalizer.argocd.argoproj.io spec: destination: - namespace: ${config.application.namePrefix}argocd server: https://kubernetes.default.svc + namespace: ${config.application.namePrefix}argocd project: ${tenantName} source: - path: argocd/ + path: apps/argocd/multiTenant/central/projects/ repoURL: ${scm.centralScmUrl}argocd/cluster-resources.git targetRevision: main directory: diff --git a/argocd/argocd/multiTenant/central/projects/tenant.ftl.yaml b/argocd/cluster-resources/apps/argocd/multiTenant/central/projects/tenant.ftl.yaml similarity index 96% rename from argocd/argocd/multiTenant/central/projects/tenant.ftl.yaml rename to argocd/cluster-resources/apps/argocd/multiTenant/central/projects/tenant.ftl.yaml index 12f54540f..1d91511c1 100644 --- a/argocd/argocd/multiTenant/central/projects/tenant.ftl.yaml +++ b/argocd/cluster-resources/apps/argocd/multiTenant/central/projects/tenant.ftl.yaml @@ -9,7 +9,6 @@ spec: - namespace: '*' server: https://kubernetes.default.svc sourceRepos: - - ${scm.centralScmUrl}argocd/argocd.git - ${scm.centralScmUrl}argocd/cluster-resources.git <#if config.application.mirrorRepos> - ${scm.repoUrl}3rd-party-dependencies/kube-prometheus-stack.git diff --git a/argocd/argocd/multiTenant/tenant/applications/bootstrap.ftl.yaml b/argocd/cluster-resources/apps/argocd/multiTenant/tenant/apps/argocd/applications/bootstrap.ftl.yaml similarity index 94% rename from argocd/argocd/multiTenant/tenant/applications/bootstrap.ftl.yaml rename to argocd/cluster-resources/apps/argocd/multiTenant/tenant/apps/argocd/applications/bootstrap.ftl.yaml index 993671016..49e2b47b4 100644 --- a/argocd/argocd/multiTenant/tenant/applications/bootstrap.ftl.yaml +++ b/argocd/cluster-resources/apps/argocd/multiTenant/tenant/apps/argocd/applications/bootstrap.ftl.yaml @@ -13,8 +13,8 @@ spec: namespace: ${config.application.namePrefix}argocd project: argocd source: - path: applications/ - repoURL: ${scm.repoUrl}argocd/argocd.git + path: apps/argocd/applications/ + repoURL: ${scm.repoUrl}argocd/cluster-resources.git targetRevision: main directory: recurse: true @@ -38,8 +38,8 @@ spec: namespace: ${config.application.namePrefix}argocd project: argocd source: - path: projects/ - repoURL: ${scm.repoUrl}argocd/argocd.git + path: apps/argocd/projects/ + repoURL: ${scm.repoUrl}argocd/cluster-resources.git targetRevision: main directory: recurse: true diff --git a/argocd/argocd/multiTenant/tenant/projects/argocd.ftl.yaml b/argocd/cluster-resources/apps/argocd/multiTenant/tenant/apps/argocd/projects/argocd.ftl.yaml similarity index 100% rename from argocd/argocd/multiTenant/tenant/projects/argocd.ftl.yaml rename to argocd/cluster-resources/apps/argocd/multiTenant/tenant/apps/argocd/projects/argocd.ftl.yaml diff --git a/argocd/argocd/multiTenant/tenant/projects/default.ftl.yaml b/argocd/cluster-resources/apps/argocd/multiTenant/tenant/apps/argocd/projects/default.ftl.yaml similarity index 100% rename from argocd/argocd/multiTenant/tenant/projects/default.ftl.yaml rename to argocd/cluster-resources/apps/argocd/multiTenant/tenant/apps/argocd/projects/default.ftl.yaml diff --git a/argocd/argocd/operator/argocd.ftl.yaml b/argocd/cluster-resources/apps/argocd/operator/argocd.ftl.yaml similarity index 99% rename from argocd/argocd/operator/argocd.ftl.yaml rename to argocd/cluster-resources/apps/argocd/operator/argocd.ftl.yaml index 1f52009bc..81fee222d 100644 --- a/argocd/argocd/operator/argocd.ftl.yaml +++ b/argocd/cluster-resources/apps/argocd/operator/argocd.ftl.yaml @@ -129,7 +129,7 @@ spec: initialRepositories: | <#if !(scm.centralScmUrl?has_content)> - name: argocd - url: ${scm.repoUrl}argocd/argocd.git + url: ${scm.repoUrl}argocd/cluster-resources.git - name: cluster-resources url: ${scm.repoUrl}argocd/cluster-resources.git - name: prometheus-community diff --git a/argocd/argocd/operator/ingress.ftl.yaml b/argocd/cluster-resources/apps/argocd/operator/ingress.ftl.yaml similarity index 100% rename from argocd/argocd/operator/ingress.ftl.yaml rename to argocd/cluster-resources/apps/argocd/operator/ingress.ftl.yaml diff --git a/argocd/argocd/projects/argocd.ftl.yaml b/argocd/cluster-resources/apps/argocd/projects/argocd.ftl.yaml similarity index 100% rename from argocd/argocd/projects/argocd.ftl.yaml rename to argocd/cluster-resources/apps/argocd/projects/argocd.ftl.yaml diff --git a/argocd/argocd/projects/cluster-resources.ftl.yaml b/argocd/cluster-resources/apps/argocd/projects/cluster-resources.ftl.yaml similarity index 100% rename from argocd/argocd/projects/cluster-resources.ftl.yaml rename to argocd/cluster-resources/apps/argocd/projects/cluster-resources.ftl.yaml diff --git a/argocd/argocd/projects/default.ftl.yaml b/argocd/cluster-resources/apps/argocd/projects/default.ftl.yaml similarity index 100% rename from argocd/argocd/projects/default.ftl.yaml rename to argocd/cluster-resources/apps/argocd/projects/default.ftl.yaml diff --git a/applications/cluster-resources/certManager-helm-values.ftl.yaml b/argocd/cluster-resources/apps/cert-manager/templates/certManager-helm-values.ftl.yaml similarity index 100% rename from applications/cluster-resources/certManager-helm-values.ftl.yaml rename to argocd/cluster-resources/apps/cert-manager/templates/certManager-helm-values.ftl.yaml diff --git a/applications/cluster-resources/secrets/external-secrets/values.ftl.yaml b/argocd/cluster-resources/apps/external-secrets/templates/values.ftl.yaml similarity index 100% rename from applications/cluster-resources/secrets/external-secrets/values.ftl.yaml rename to argocd/cluster-resources/apps/external-secrets/templates/values.ftl.yaml diff --git a/applications/cluster-resources/ingress-nginx-helm-values.ftl.yaml b/argocd/cluster-resources/apps/ingress/templates/ingress-nginx-helm-values.ftl.yaml similarity index 100% rename from applications/cluster-resources/ingress-nginx-helm-values.ftl.yaml rename to argocd/cluster-resources/apps/ingress/templates/ingress-nginx-helm-values.ftl.yaml diff --git a/jenkins/namespaceJobTemplate.xml.ftl b/argocd/cluster-resources/apps/jenkins/templates/namespaceJobTemplate.xml.ftl similarity index 100% rename from jenkins/namespaceJobTemplate.xml.ftl rename to argocd/cluster-resources/apps/jenkins/templates/namespaceJobTemplate.xml.ftl diff --git a/jenkins/values.ftl.yaml b/argocd/cluster-resources/apps/jenkins/values.ftl.yaml similarity index 100% rename from jenkins/values.ftl.yaml rename to argocd/cluster-resources/apps/jenkins/values.ftl.yaml diff --git a/applications/cluster-resources/mailhog-helm-values.ftl.yaml b/argocd/cluster-resources/apps/mailhog/templates/mailhog-helm-values.ftl.yaml similarity index 100% rename from applications/cluster-resources/mailhog-helm-values.ftl.yaml rename to argocd/cluster-resources/apps/mailhog/templates/mailhog-helm-values.ftl.yaml diff --git a/argocd/cluster-resources/misc/monitoring/argocd-dashboard.ftl.yaml b/argocd/cluster-resources/apps/prometheusstack/misc/dashboard/argocd-dashboard.ftl.yaml similarity index 100% rename from argocd/cluster-resources/misc/monitoring/argocd-dashboard.ftl.yaml rename to argocd/cluster-resources/apps/prometheusstack/misc/dashboard/argocd-dashboard.ftl.yaml diff --git a/argocd/cluster-resources/misc/monitoring/ingress-nginx-dashboard-requests-handling.ftl.yaml b/argocd/cluster-resources/apps/prometheusstack/misc/dashboard/ingress-nginx-dashboard-requests-handling.ftl.yaml similarity index 100% rename from argocd/cluster-resources/misc/monitoring/ingress-nginx-dashboard-requests-handling.ftl.yaml rename to argocd/cluster-resources/apps/prometheusstack/misc/dashboard/ingress-nginx-dashboard-requests-handling.ftl.yaml diff --git a/argocd/cluster-resources/misc/monitoring/ingress-nginx-dashboard.ftl.yaml b/argocd/cluster-resources/apps/prometheusstack/misc/dashboard/ingress-nginx-dashboard.ftl.yaml similarity index 100% rename from argocd/cluster-resources/misc/monitoring/ingress-nginx-dashboard.ftl.yaml rename to argocd/cluster-resources/apps/prometheusstack/misc/dashboard/ingress-nginx-dashboard.ftl.yaml diff --git a/argocd/cluster-resources/misc/monitoring/jenkins-dashboard.ftl.yaml b/argocd/cluster-resources/apps/prometheusstack/misc/dashboard/jenkins-dashboard.ftl.yaml similarity index 100% rename from argocd/cluster-resources/misc/monitoring/jenkins-dashboard.ftl.yaml rename to argocd/cluster-resources/apps/prometheusstack/misc/dashboard/jenkins-dashboard.ftl.yaml diff --git a/argocd/cluster-resources/misc/monitoring/prometheus-dashboard.ftl.yaml b/argocd/cluster-resources/apps/prometheusstack/misc/dashboard/prometheus-dashboard.ftl.yaml similarity index 100% rename from argocd/cluster-resources/misc/monitoring/prometheus-dashboard.ftl.yaml rename to argocd/cluster-resources/apps/prometheusstack/misc/dashboard/prometheus-dashboard.ftl.yaml diff --git a/argocd/cluster-resources/misc/monitoring/scmm-dashboard.ftl.yaml b/argocd/cluster-resources/apps/prometheusstack/misc/dashboard/scmm-dashboard.ftl.yaml similarity index 100% rename from argocd/cluster-resources/misc/monitoring/scmm-dashboard.ftl.yaml rename to argocd/cluster-resources/apps/prometheusstack/misc/dashboard/scmm-dashboard.ftl.yaml diff --git a/applications/cluster-resources/monitoring/netpols/prometheus-allow-scraping.ftl.yaml b/argocd/cluster-resources/apps/prometheusstack/templates/netpols/prometheus-allow-scraping.ftl.yaml similarity index 100% rename from applications/cluster-resources/monitoring/netpols/prometheus-allow-scraping.ftl.yaml rename to argocd/cluster-resources/apps/prometheusstack/templates/netpols/prometheus-allow-scraping.ftl.yaml diff --git a/applications/cluster-resources/monitoring/prometheus-stack-helm-values.ftl.yaml b/argocd/cluster-resources/apps/prometheusstack/templates/prometheus-stack-helm-values.ftl.yaml similarity index 96% rename from applications/cluster-resources/monitoring/prometheus-stack-helm-values.ftl.yaml rename to argocd/cluster-resources/apps/prometheusstack/templates/prometheus-stack-helm-values.ftl.yaml index f106bd476..54a6f4915 100644 --- a/applications/cluster-resources/monitoring/prometheus-stack-helm-values.ftl.yaml +++ b/argocd/cluster-resources/apps/prometheusstack/templates/prometheus-stack-helm-values.ftl.yaml @@ -160,8 +160,8 @@ grafana: adminPassword: ${config.application["password"]} service: type: <#if config.application.remote>LoadBalancer<#else>ClusterIP -<#if monitoring.grafana.host?has_content> - ingress: +<#if monitoring?? && monitoring?is_hash && monitoring.grafana?? && monitoring.grafana.host?has_content> + ingress: enabled: true hosts: [${monitoring.grafana.host}] @@ -321,7 +321,7 @@ prometheus: { } probeSelectorNilUsesHelmValues: false - <#if config.application.podResources == true> +<#if config.application.podResources == true> resources: limits: cpu: 500m @@ -341,7 +341,10 @@ prometheus: - prometheus-metrics-creds-scmm - prometheus-metrics-creds-jenkins additionalScrapeConfigs: -<#if config.scm.scmProviderType?lower_case == "scm_manager"> +<#if config.scm.scmProviderType?lower_case == "scm_manager" + && scm.host?has_content + && scm.protocol?has_content + && scm.path?has_content> - job_name: 'scm-manager' static_configs: - targets: [ '${scm.host}' ] @@ -351,6 +354,7 @@ prometheus: username: '${config.application.namePrefix}metrics' password_file: '/etc/prometheus/secrets/prometheus-metrics-creds-scmm/password' +<#if config.jenkins.active == true> - job_name: 'jenkins' static_configs: - targets: [ '${jenkins.host}' ] @@ -358,4 +362,5 @@ prometheus: metrics_path: '${jenkins.path}' basic_auth: username: '${jenkins.metricsUsername}' - password_file: '/etc/prometheus/secrets/prometheus-metrics-creds-jenkins/password' \ No newline at end of file + password_file: '/etc/prometheus/secrets/prometheus-metrics-creds-jenkins/password' + \ No newline at end of file diff --git a/applications/cluster-resources/monitoring/rbac/namespace-isolation-rbac.ftl.yaml b/argocd/cluster-resources/apps/prometheusstack/templates/rbac/namespace-isolation-rbac.ftl.yaml similarity index 95% rename from applications/cluster-resources/monitoring/rbac/namespace-isolation-rbac.ftl.yaml rename to argocd/cluster-resources/apps/prometheusstack/templates/rbac/namespace-isolation-rbac.ftl.yaml index 77183ac85..766c4c516 100644 --- a/applications/cluster-resources/monitoring/rbac/namespace-isolation-rbac.ftl.yaml +++ b/argocd/cluster-resources/apps/prometheusstack/templates/rbac/namespace-isolation-rbac.ftl.yaml @@ -136,7 +136,7 @@ metadata: subjects: - kind: ServiceAccount name: kube-prometheus-stack-operator - namespace: ${namePrefix}monitoring + namespace: ${config.application.namePrefix}monitoring roleRef: apiGroup: rbac.authorization.k8s.io kind: Role @@ -150,7 +150,7 @@ metadata: subjects: - kind: ServiceAccount name: kube-prometheus-stack-prometheus - namespace: ${namePrefix}monitoring + namespace: ${config.application.namePrefix}monitoring roleRef: apiGroup: rbac.authorization.k8s.io kind: Role @@ -184,4 +184,4 @@ roleRef: subjects: - kind: ServiceAccount name: kube-prometheus-stack-grafana - namespace: ${namePrefix}monitoring + namespace: ${config.application.namePrefix}monitoring diff --git a/scm-manager/values.ftl.yaml b/argocd/cluster-resources/apps/scm-manager/templates/values.ftl.yaml similarity index 68% rename from scm-manager/values.ftl.yaml rename to argocd/cluster-resources/apps/scm-manager/templates/values.ftl.yaml index 835bdba7a..ed43b0aa7 100644 --- a/scm-manager/values.ftl.yaml +++ b/argocd/cluster-resources/apps/scm-manager/templates/values.ftl.yaml @@ -8,16 +8,16 @@ livenessProbe: fullnameOverride : ${releaseName} extraEnv: | - - name: SCM_WEBAPP_INITIALUSER - value: "${username}" - - name: SCM_WEBAPP_INITIALPASSWORD - value: "${password}" + - name: SCM_WEBAPP_INITIALUSER + value: "${username}" + - name: SCM_WEBAPP_INITIALPASSWORD + value: "${password}" <#if remote?? && !remote> service: type: NodePort - - + + <#if host?has_content> ingress: enabled: true diff --git a/argocd/cluster-resources/misc/namespaces.ftl.yaml b/argocd/cluster-resources/apps/vault/misc/namespaces.ftl.yaml similarity index 100% rename from argocd/cluster-resources/misc/namespaces.ftl.yaml rename to argocd/cluster-resources/apps/vault/misc/namespaces.ftl.yaml diff --git a/argocd/cluster-resources/misc/secrets/secret-store-production.ftl.yaml b/argocd/cluster-resources/apps/vault/misc/secret-store-production.ftl.yaml similarity index 100% rename from argocd/cluster-resources/misc/secrets/secret-store-production.ftl.yaml rename to argocd/cluster-resources/apps/vault/misc/secret-store-production.ftl.yaml diff --git a/argocd/cluster-resources/misc/secrets/secret-store-staging.ftl.yaml b/argocd/cluster-resources/apps/vault/misc/secret-store-staging.ftl.yaml similarity index 100% rename from argocd/cluster-resources/misc/secrets/secret-store-staging.ftl.yaml rename to argocd/cluster-resources/apps/vault/misc/secret-store-staging.ftl.yaml diff --git a/applications/cluster-resources/secrets/vault/dev-post-start.ftl.sh b/argocd/cluster-resources/apps/vault/templates/dev-post-start.ftl.sh similarity index 100% rename from applications/cluster-resources/secrets/vault/dev-post-start.ftl.sh rename to argocd/cluster-resources/apps/vault/templates/dev-post-start.ftl.sh diff --git a/applications/cluster-resources/secrets/vault/values.ftl.yaml b/argocd/cluster-resources/apps/vault/templates/values.ftl.yaml similarity index 100% rename from applications/cluster-resources/secrets/vault/values.ftl.yaml rename to argocd/cluster-resources/apps/vault/templates/values.ftl.yaml diff --git a/argocd/cluster-resources/argocd/misc.ftl.yaml b/argocd/cluster-resources/argocd/misc.ftl.yaml deleted file mode 100644 index 4bba8b06a..000000000 --- a/argocd/cluster-resources/argocd/misc.ftl.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# this misc-Application manages all resources in the misc folder in the gitops repository -# use the misc folder to deploy resources, which are needed for multiple other apps such as ServiceAccounts or shared ConfigMaps -apiVersion: argoproj.io/v1alpha1 -kind: Application -metadata: - name: <#if config.multiTenant.useDedicatedInstance>${config.application.namePrefix}misc<#else>misc - namespace: <#if config.multiTenant.useDedicatedInstance>${config.multiTenant.centralArgocdNamespace}<#else>${config.application.namePrefix}argocd -spec: - project: <#if config.multiTenant.useDedicatedInstance>${tenantName}<#else>cluster-resources - destination: - server: https://kubernetes.default.svc - namespace: <#if config.multiTenant.useDedicatedInstance>${config.multiTenant.centralArgocdNamespace}<#else>${config.application.namePrefix}argocd - source: - path: misc/ -<#if config.multiTenant.useDedicatedInstance> - repoURL: ${scm.centralScmUrl}argocd/cluster-resources.git -<#else> - repoURL: ${scm.repoUrl}argocd/cluster-resources.git - - targetRevision: main - directory: - recurse: true - syncPolicy: - automated: - prune: true - selfHeal: true \ No newline at end of file diff --git a/argocd/cluster-resources/misc/.gitkeep b/argocd/cluster-resources/misc/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/examples/example-apps-via-content-loader/argocd/argocd/applications/example-apps.ftl.yaml b/examples/example-apps-via-content-loader/argocd/cluster-resources/apps/argocd/applications/example-apps.ftl.yaml similarity index 100% rename from examples/example-apps-via-content-loader/argocd/argocd/applications/example-apps.ftl.yaml rename to examples/example-apps-via-content-loader/argocd/cluster-resources/apps/argocd/applications/example-apps.ftl.yaml diff --git a/examples/example-apps-via-content-loader/argocd/argocd/projects/example-apps.ftl.yaml b/examples/example-apps-via-content-loader/argocd/cluster-resources/apps/argocd/projects/example-apps.ftl.yaml similarity index 100% rename from examples/example-apps-via-content-loader/argocd/argocd/projects/example-apps.ftl.yaml rename to examples/example-apps-via-content-loader/argocd/cluster-resources/apps/argocd/projects/example-apps.ftl.yaml diff --git a/examples/example-apps-via-content-loader/config.yaml b/examples/example-apps-via-content-loader/config.yaml index 44689aa01..39e056f53 100644 --- a/examples/example-apps-via-content-loader/config.yaml +++ b/examples/example-apps-via-content-loader/config.yaml @@ -23,7 +23,7 @@ content: createJenkinsJob: true - url: https://github.com/cloudogu/gitops-playground path: examples/example-apps-via-content-loader/ - ref: main + ref: feature/optimize-repo-structure templating: true type: FOLDER_BASED overwriteMode: UPGRADE diff --git a/src/main/groovy/com/cloudogu/gitops/destroy/ArgoCDDestructionHandler.groovy b/src/main/groovy/com/cloudogu/gitops/destroy/ArgoCDDestructionHandler.groovy index 5d2f3f8b1..ab745ecd7 100644 --- a/src/main/groovy/com/cloudogu/gitops/destroy/ArgoCDDestructionHandler.groovy +++ b/src/main/groovy/com/cloudogu/gitops/destroy/ArgoCDDestructionHandler.groovy @@ -40,7 +40,7 @@ class ArgoCDDestructionHandler implements DestructionHandler { @Override void destroy() { - def repo = repoProvider.getRepo("argocd/argocd", gitHandler.resourcesScm) + def repo = repoProvider.getRepo("argocd/cloud-resources", gitHandler.resourcesScm) repo.cloneRepo() for (def app in k8sClient.getCustomResource("app")) { diff --git a/src/main/groovy/com/cloudogu/gitops/features/CertManager.groovy b/src/main/groovy/com/cloudogu/gitops/features/CertManager.groovy index 66b7759c0..9967e973b 100644 --- a/src/main/groovy/com/cloudogu/gitops/features/CertManager.groovy +++ b/src/main/groovy/com/cloudogu/gitops/features/CertManager.groovy @@ -22,7 +22,7 @@ import java.nio.file.Path @Order(160) class CertManager extends Feature implements FeatureWithImage { - static final String HELM_VALUES_PATH = "applications/cluster-resources/certManager-helm-values.ftl.yaml" + static final String HELM_VALUES_PATH = "argocd/cluster-resources/apps/cert-manager/templates/certManager-helm-values.ftl.yaml" private FileSystemUtils fileSystemUtils private DeploymentStrategy deployer diff --git a/src/main/groovy/com/cloudogu/gitops/features/ExternalSecretsOperator.groovy b/src/main/groovy/com/cloudogu/gitops/features/ExternalSecretsOperator.groovy index 57fe90849..61cc6b410 100644 --- a/src/main/groovy/com/cloudogu/gitops/features/ExternalSecretsOperator.groovy +++ b/src/main/groovy/com/cloudogu/gitops/features/ExternalSecretsOperator.groovy @@ -22,7 +22,7 @@ import java.nio.file.Path @Order(400) class ExternalSecretsOperator extends Feature implements FeatureWithImage { - static final String HELM_VALUES_PATH = 'applications/cluster-resources/secrets/external-secrets/values.ftl.yaml' + static final String HELM_VALUES_PATH = "argocd/cluster-resources/apps/external-secrets/templates/values.ftl.yaml" String namespace = "${config.application.namePrefix}secrets" Config config diff --git a/src/main/groovy/com/cloudogu/gitops/features/IngressNginx.groovy b/src/main/groovy/com/cloudogu/gitops/features/IngressNginx.groovy index a01473971..15cb98584 100644 --- a/src/main/groovy/com/cloudogu/gitops/features/IngressNginx.groovy +++ b/src/main/groovy/com/cloudogu/gitops/features/IngressNginx.groovy @@ -22,7 +22,7 @@ import java.nio.file.Path @Order(150) class IngressNginx extends Feature implements FeatureWithImage { - static final String HELM_VALUES_PATH = "applications/cluster-resources/ingress-nginx-helm-values.ftl.yaml" + static final String HELM_VALUES_PATH = "argocd/cluster-resources/apps/ingress/templates/ingress-nginx-helm-values.ftl.yaml" String namespace = "${config.application.namePrefix}ingress-nginx" Config config diff --git a/src/main/groovy/com/cloudogu/gitops/features/Jenkins.groovy b/src/main/groovy/com/cloudogu/gitops/features/Jenkins.groovy index 4b2b8f97a..78db14bb9 100644 --- a/src/main/groovy/com/cloudogu/gitops/features/Jenkins.groovy +++ b/src/main/groovy/com/cloudogu/gitops/features/Jenkins.groovy @@ -22,7 +22,7 @@ import jakarta.inject.Singleton @Order(70) class Jenkins extends Feature { - static final String HELM_VALUES_PATH = "jenkins/values.ftl.yaml" + static final String HELM_VALUES_PATH = "argocd/cluster-resources/apps/jenkins/values.ftl.yaml" String namespace private Config config diff --git a/src/main/groovy/com/cloudogu/gitops/features/Mailhog.groovy b/src/main/groovy/com/cloudogu/gitops/features/Mailhog.groovy index 80ec1c0b3..440dce84e 100644 --- a/src/main/groovy/com/cloudogu/gitops/features/Mailhog.groovy +++ b/src/main/groovy/com/cloudogu/gitops/features/Mailhog.groovy @@ -23,7 +23,7 @@ import java.nio.file.Path @Order(200) class Mailhog extends Feature implements FeatureWithImage { - static final String HELM_VALUES_PATH = "applications/cluster-resources/mailhog-helm-values.ftl.yaml" + static final String HELM_VALUES_PATH = "argocd/cluster-resources/apps/mailhog/templates/mailhog-helm-values.ftl.yaml" String namespace = "${config.application.namePrefix}monitoring" Config config diff --git a/src/main/groovy/com/cloudogu/gitops/features/PrometheusStack.groovy b/src/main/groovy/com/cloudogu/gitops/features/PrometheusStack.groovy index bccf68b6c..0ac39bfcf 100644 --- a/src/main/groovy/com/cloudogu/gitops/features/PrometheusStack.groovy +++ b/src/main/groovy/com/cloudogu/gitops/features/PrometheusStack.groovy @@ -23,15 +23,15 @@ import static com.cloudogu.gitops.features.deployment.DeploymentStrategy.RepoTyp @Order(300) class PrometheusStack extends Feature implements FeatureWithImage { - static final String HELM_VALUES_PATH = "applications/cluster-resources/monitoring/prometheus-stack-helm-values.ftl.yaml" - static final String RBAC_NAMESPACE_ISOLATION_TEMPLATE = 'applications/cluster-resources/monitoring/rbac/namespace-isolation-rbac.ftl.yaml' - static final String NETWORK_POLICIES_PROMETHEUS_ALLOW_TEMPLATE = 'applications/cluster-resources/monitoring/netpols/prometheus-allow-scraping.ftl.yaml' + static final String HELM_VALUES_PATH = "argocd/cluster-resources/apps/prometheusstack/templates/prometheus-stack-helm-values.ftl.yaml" + static final String RBAC_NAMESPACE_ISOLATION_TEMPLATE = "argocd/cluster-resources/apps/prometheusstack/templates/rbac/namespace-isolation-rbac.ftl.yaml" + static final String NETWORK_POLICIES_PROMETHEUS_ALLOW_TEMPLATE = "argocd/cluster-resources/apps/prometheusstack/templates/netpols/prometheus-allow-scraping.ftl.yaml" String namespace = "${config.application.namePrefix}monitoring" Config config K8sClient k8sClient - GitRepoFactory scmRepoProvider + private GitRepoFactory scmRepoProvider private FileSystemUtils fileSystemUtils private DeploymentStrategy deployer private AirGappedUtils airGappedUtils @@ -72,7 +72,6 @@ class PrometheusStack extends Feature implements FeatureWithImage { Map templateModel = buildTemplateValues(config, uid) def values = templateToMap(HELM_VALUES_PATH, templateModel) - def helmConfig = config.features.monitoring.helm def mergedMap = MapUtils.deepMerge(helmConfig.values, values) @@ -111,7 +110,10 @@ class PrometheusStack extends Feature implements FeatureWithImage { [namespace : currentNamespace, namePrefix: namePrefix, config : config]) - clusterResourcesRepo.writeFile("misc/monitoring/rbac/${currentNamespace}.yaml", rbacYaml) + clusterResourcesRepo.writeFile( + "apps/prometheusstack/misc/rbac/${currentNamespace}.yaml", + rbacYaml + ) } if (config.application.netpols) { @@ -119,7 +121,10 @@ class PrometheusStack extends Feature implements FeatureWithImage { [namespace : currentNamespace, namePrefix: namePrefix]) - clusterResourcesRepo.writeFile("misc/monitoring/netpols/${currentNamespace}.yaml", netpolsYaml) + clusterResourcesRepo.writeFile( + "apps/prometheusstack/misc/netpols/${currentNamespace}.yaml", + netpolsYaml + ) } } clusterResourcesRepo.commitAndPush('Adding namespace-isolated RBAC and network policies if enabled.') diff --git a/src/main/groovy/com/cloudogu/gitops/features/Vault.groovy b/src/main/groovy/com/cloudogu/gitops/features/Vault.groovy index a55b782cc..b423c2755 100644 --- a/src/main/groovy/com/cloudogu/gitops/features/Vault.groovy +++ b/src/main/groovy/com/cloudogu/gitops/features/Vault.groovy @@ -18,8 +18,8 @@ import java.nio.file.Path @Singleton @Order(500) class Vault extends Feature implements FeatureWithImage { - static final String VAULT_START_SCRIPT_PATH = '/applications/cluster-resources/secrets/vault/dev-post-start.ftl.sh' - static final String HELM_VALUES_PATH = 'applications/cluster-resources/secrets/vault/values.ftl.yaml' + static final String VAULT_START_SCRIPT_PATH = "argocd/cluster-resources/apps/vault/templates/dev-post-start.ftl.sh" + static final String HELM_VALUES_PATH = "argocd/cluster-resources/apps/vault/templates/values.ftl.yaml" String namespace = "${config.application.namePrefix}secrets" Config config @@ -73,7 +73,7 @@ class Vault extends Feature implements FeatureWithImage { def vaultPostStartConfigMap = 'vault-dev-post-start' def vaultPostStartVolume = 'dev-post-start' - def templatedFile = fileSystemUtils.copyToTempDir(fileSystemUtils.getRootDir() + VAULT_START_SCRIPT_PATH) + def templatedFile = fileSystemUtils.copyToTempDir(fileSystemUtils.getRootDir() + "/"+VAULT_START_SCRIPT_PATH) def postStartScript = new TemplatingEngine().replaceTemplate(templatedFile.toFile(), [namePrefix: config.application.namePrefix]) log.debug('Creating namespace for vault, so it can add its secrets there') diff --git a/src/main/groovy/com/cloudogu/gitops/features/argocd/ArgoCD.groovy b/src/main/groovy/com/cloudogu/gitops/features/argocd/ArgoCD.groovy index 751252000..a640cc76a 100644 --- a/src/main/groovy/com/cloudogu/gitops/features/argocd/ArgoCD.groovy +++ b/src/main/groovy/com/cloudogu/gitops/features/argocd/ArgoCD.groovy @@ -23,33 +23,21 @@ import java.nio.file.Path @Singleton @Order(100) class ArgoCD extends Feature { - static final String HELM_VALUES_PATH = 'argocd/values.yaml' - static final String OPERATOR_CONFIG_PATH = 'operator/argocd.yaml' - static final String OPERATOR_RBAC_PATH = 'operator/rbac' - static final String CHART_YAML_PATH = 'argocd/Chart.yaml' - static final String DEDICATED_INSTANCE_PATH = 'multiTenant/central/' - static final String MONITORING_RESOURCES_PATH = '/misc/monitoring/' - private String namespace = "${config.application.namePrefix}${config.features.argocd.namespace}" - private Config config - private List gitRepos = [] + private final String namespace + private final Config config + private final K8sClient k8sClient + private final HelmClient helmClient + private final FileSystemUtils fileSystemUtils + private final GitRepoFactory repoProvider + private final GitHandler gitHandler + private final List gitRepos = [] - private String password + private final String password - protected final String scmmUrlInternal = "http://scmm.${config.application.namePrefix}scm-manager.svc.cluster.local/scm" - - protected RepoInitializationAction argocdRepoInitializationAction protected RepoInitializationAction clusterResourcesInitializationAction protected RepoInitializationAction tenantBootstrapInitializationAction - protected File remotePetClinicRepoTmpDir - - protected K8sClient k8sClient - protected HelmClient helmClient - protected FileSystemUtils fileSystemUtils - private GitRepoFactory repoProvider - - GitHandler gitHandler ArgoCD( Config config, @@ -65,7 +53,8 @@ class ArgoCD extends Feature { this.helmClient = helmClient this.fileSystemUtils = fileSystemUtils this.gitHandler = gitHandler - this.password = this.config.application.password + this.password = config.application.password + this.namespace = "${config.application.namePrefix}${config.features.argocd.namespace}" } @Override @@ -96,19 +85,13 @@ class ArgoCD extends Feature { @Override void enable() { + initGitOpsRepos() - initTenantRepos() - initCentralRepos() - - log.debug('Cloning Repositories') - - gitRepos.forEach(repoInitializationAction -> { - repoInitializationAction.initLocalRepo() - }) - + // init all repos (clusterResources, tenantBootstrap, etc.) + gitRepos.each { RepoInitializationAction repoInitializationAction -> repoInitializationAction.initLocalRepo() } prepareGitOpsRepos() - gitRepos.forEach(repoInitializationAction -> { + this.gitRepos.forEach(repoInitializationAction -> { repoInitializationAction.repo.commitAndPush('Initial Commit') }) @@ -116,9 +99,8 @@ class ArgoCD extends Feature { installArgoCd() } - private void installArgoCd() { - prepareArgoCdRepo() + private void installArgoCd() { log.debug("Creating namespaces") k8sClient.createNamespaces(config.application.namespaces.activeNamespaces.toList()) @@ -143,17 +125,21 @@ class ArgoCD extends Feature { deployWithHelm() } + ArgoCDRepoLayout repoLayout = repoLayout() + if (config.multiTenant.useDedicatedInstance) { //Bootstrapping dedicated instance - k8sClient.applyYaml(Path.of(argocdRepoInitializationAction.repo.getAbsoluteLocalRepoTmpDir(), "${DEDICATED_INSTANCE_PATH}projects/tenant.yaml").toString()) - k8sClient.applyYaml(Path.of(argocdRepoInitializationAction.repo.getAbsoluteLocalRepoTmpDir(), "${DEDICATED_INSTANCE_PATH}applications/bootstrap.yaml").toString()) + k8sClient.applyYaml(repoLayout.dedicatedTenantProject()) + k8sClient.applyYaml(repoLayout.dedicatedBootstrapApp()) + //Bootstrapping tenant Argocd projects - k8sClient.applyYaml(Path.of(tenantBootstrapInitializationAction.repo.getAbsoluteLocalRepoTmpDir(), 'projects/argocd.yaml').toString()) - k8sClient.applyYaml(Path.of(tenantBootstrapInitializationAction.repo.getAbsoluteLocalRepoTmpDir(), 'applications/bootstrap.yaml').toString()) + ArgoCDRepoLayout tenantRepoLayout = tenantRepoLayout() + k8sClient.applyYaml(Path.of(tenantRepoLayout.projectsDir(), "argocd.yaml").toString()) + k8sClient.applyYaml(Path.of(tenantRepoLayout.applicationsDir(), "bootstrap.yaml").toString()) } else { // Bootstrap root application - k8sClient.applyYaml(Path.of(argocdRepoInitializationAction.repo.getAbsoluteLocalRepoTmpDir(), 'projects/argocd.yaml').toString()) - k8sClient.applyYaml(Path.of(argocdRepoInitializationAction.repo.getAbsoluteLocalRepoTmpDir(), 'applications/bootstrap.yaml').toString()) + k8sClient.applyYaml(Path.of(repoLayout.projectsDir(), "argocd.yaml").toString()) + k8sClient.applyYaml(Path.of(repoLayout.applicationsDir(), "bootstrap.yaml").toString()) } // Delete helm-argo secrets to decouple from helm. @@ -163,84 +149,119 @@ class ArgoCD extends Feature { new Tuple2('owner', 'helm'), new Tuple2('name', 'argocd')) } - protected initTenantRepos() { - if (!config.multiTenant.useDedicatedInstance) { - argocdRepoInitializationAction = createRepoInitializationAction('argocd/argocd', 'argocd/argocd', this.gitHandler.tenant) + private void initGitOpsRepos() { + initTenantRepos() + initCentralRepos() + + Set clusterResourceSubDirs = new LinkedHashSet<>() + + clusterResourceSubDirs.add(ArgoCDRepoLayout.argocdSubdirRel()) + + if (config.features.certManager.active) { + clusterResourceSubDirs.add(ArgoCDRepoLayout.certManagerSubdirRel()) // "apps/cert-manager" + } + if (config.features.ingressNginx.active) { + clusterResourceSubDirs.add(ArgoCDRepoLayout.ingressSubdirRel()) + } + + if (config.jenkins.active) { + clusterResourceSubDirs.add(ArgoCDRepoLayout.jenkinsSubdirRel()) + } + if (config.features.mail.active) { + clusterResourceSubDirs.add(ArgoCDRepoLayout.mailhogSubdirRel()) + } + + if (config.features.monitoring.active) { + clusterResourceSubDirs.add(ArgoCDRepoLayout.monitoringSubdirRel()) + } + if (config.scm.scmManager?.url) { + clusterResourceSubDirs.add(ArgoCDRepoLayout.scmManagerSubdirRel()) + } + + if (config.features.secrets.active) { + clusterResourceSubDirs.add(ArgoCDRepoLayout.secretsSubdirRel()) + clusterResourceSubDirs.add(ArgoCDRepoLayout.vaultSubdirRel()) + } + + clusterResourcesInitializationAction.subDirsToCopy = clusterResourceSubDirs + } + + private void initTenantRepos() { + if (!config.multiTenant.useDedicatedInstance) { clusterResourcesInitializationAction = createRepoInitializationAction('argocd/cluster-resources', 'argocd/cluster-resources', this.gitHandler.tenant) - gitRepos += clusterResourcesInitializationAction + this.gitRepos.add(clusterResourcesInitializationAction) + } else { - tenantBootstrapInitializationAction = createRepoInitializationAction('argocd/argocd/multiTenant/tenant', 'argocd/argocd', this.gitHandler.tenant) - gitRepos += tenantBootstrapInitializationAction + tenantBootstrapInitializationAction = createRepoInitializationAction('argocd/cluster-resources/apps/argocd/multiTenant/tenant', 'argocd/cluster-resources', this.gitHandler.tenant) + this.gitRepos.add(tenantBootstrapInitializationAction) } } - protected initCentralRepos() { + private void initCentralRepos() { if (config.multiTenant.useDedicatedInstance) { - argocdRepoInitializationAction = createRepoInitializationAction('argocd/argocd', 'argocd/argocd', true) - clusterResourcesInitializationAction = createRepoInitializationAction('argocd/cluster-resources', 'argocd/cluster-resources', true) - gitRepos += clusterResourcesInitializationAction + this.gitRepos.add(clusterResourcesInitializationAction) } } private void prepareGitOpsRepos() { + ArgoCDRepoLayout repoLayout = repoLayout() - if (!config.features.secrets.active) { - log.debug("Deleting unnecessary secrets folder from cluster resources: ${clusterResourcesInitializationAction.repo.getAbsoluteLocalRepoTmpDir()}") - FileSystemUtils.deleteDir clusterResourcesInitializationAction.repo.getAbsoluteLocalRepoTmpDir() + '/misc/secrets' + if (config.features.argocd.operator) { + log.debug("Deleting unnecessary argocd (argocd helm variant) folder from argocd repo: ${repoLayout.helmDir()}") + FileSystemUtils.deleteDir repoLayout.helmDir() + generateRBAC() + } else { + log.debug("Deleting unnecessary operator (argocd operator variant) folder from argocd repo: ${repoLayout.operatorDir()}") + FileSystemUtils.deleteDir repoLayout.operatorDir() } - if (!config.features.monitoring.active) { - log.debug("Deleting unnecessary monitoring folder from cluster resources: ${clusterResourcesInitializationAction.repo.getAbsoluteLocalRepoTmpDir()}") - FileSystemUtils.deleteDir clusterResourcesInitializationAction.repo.getAbsoluteLocalRepoTmpDir() + MONITORING_RESOURCES_PATH - } else if (!config.features.ingressNginx.active) { - FileSystemUtils.deleteFile clusterResourcesInitializationAction.repo.getAbsoluteLocalRepoTmpDir() + MONITORING_RESOURCES_PATH + 'ingress-nginx-dashboard.yaml' - FileSystemUtils.deleteFile clusterResourcesInitializationAction.repo.getAbsoluteLocalRepoTmpDir() + MONITORING_RESOURCES_PATH + 'ingress-nginx-dashboard-requests-handling.yaml' + if (config.multiTenant.useDedicatedInstance) { + log.debug("Deleting unnecessary non dedicated instances folders from argocd repo: applications=${repoLayout.applicationsDir()}, projects=${repoLayout.projectsDir()}") + FileSystemUtils.deleteDir repoLayout.applicationsDir() + FileSystemUtils.deleteDir repoLayout.projectsDir() + } else { + log.debug("Deleting unnecessary multiTenant folder from argocd repo: ${repoLayout.multiTenantDir()}") + FileSystemUtils.deleteDir repoLayout.multiTenantDir() } - } - - private void deployWithHelm() { - // Install umbrella chart from folder - String umbrellaChartPath = Path.of(argocdRepoInitializationAction.repo.getAbsoluteLocalRepoTmpDir(), 'argocd/') - // Even if the Chart.lock already contains the repo, we need to add it before resolving it - // See https://github.com/helm/helm/issues/8036#issuecomment-872502901 - List helmDependencies = fileSystemUtils.readYaml( - Path.of(argocdRepoInitializationAction.repo.getAbsoluteLocalRepoTmpDir(), CHART_YAML_PATH))['dependencies'] - helmClient.addRepo('argo', helmDependencies[0]['repository'] as String) - helmClient.dependencyBuild(umbrellaChartPath) - helmClient.upgrade('argocd', umbrellaChartPath, [namespace: "${namespace}"]) - - // Delete helm-argo secrets to decouple from helm. - // This does not delete Argo from the cluster, but you can no longer modify argo directly with helm - // For development keeping it in helm makes it easier (e.g. for helm uninstall). - k8sClient.delete('secret', namespace, - new Tuple2('owner', 'helm'), new Tuple2('name', 'argocd')) + if (!config.application.netpols) { + log.debug("Deleting argocd netpols at ${repoLayout.netpolFile()}") + FileSystemUtils.deleteFile repoLayout.netpolFile() + } - log.debug("Setting new argocd admin password") - // Set admin password imperatively here instead of values.yaml, because we don't want it to show in git repo - String bcryptArgoCDPassword = BCrypt.hashpw(password, BCrypt.gensalt(4)) - k8sClient.patch('secret', 'argocd-secret', namespace, - [stringData: ['admin.password': bcryptArgoCDPassword]]) + if (config.features.monitoring.active) { + String monitoringRootDashboard = "${repoLayout.monitoringDir()}/misc/dashboard" + if (!config.features.ingressNginx.active) { + FileSystemUtils.deleteFile monitoringRootDashboard + '/ingress-nginx-dashboard.yaml' + FileSystemUtils.deleteFile monitoringRootDashboard + '/ingress-nginx-dashboard-requests-handling.yaml' + } + if (!config.jenkins.active) { + FileSystemUtils.deleteFile monitoringRootDashboard + '/jenkins-dashboard.yaml' + } + if (!config.scm.scmManager?.url) { + FileSystemUtils.deleteFile monitoringRootDashboard + '/scmm-dashboard.yaml' + } + } } private void deployWithOperator() { + ArgoCDRepoLayout repoLayout = repoLayout() + // Apply argocd yaml from operator folder - String argocdConfigPath = Path.of(argocdRepoInitializationAction.repo.getAbsoluteLocalRepoTmpDir(), OPERATOR_CONFIG_PATH) + String argocdConfigPath = repoLayout.operatorConfigFile() if (this.config.features.argocd?.values) { log.debug("extend Argocd.yaml with ${this.config.features.argocd.values}") def argocdYaml = fileSystemUtils.readYaml( - Path.of(argocdRepoInitializationAction.repo.getAbsoluteLocalRepoTmpDir(), OPERATOR_CONFIG_PATH)) + Path.of(repoLayout.operatorConfigFile())) def result = MapUtils.deepMerge(this.config.features.argocd.values, argocdYaml) fileSystemUtils.writeYaml(result, new File (argocdConfigPath)) log.debug("Argocd.yaml for operator contains ${result}") // reload file - argocdConfigPath = Path.of(argocdRepoInitializationAction.repo.getAbsoluteLocalRepoTmpDir(), OPERATOR_CONFIG_PATH) - + argocdConfigPath = repoLayout.operatorConfigFile() } - k8sClient.applyYaml(argocdConfigPath) // ArgoCD is not installed until the ArgoCD-Operator did his job. @@ -252,21 +273,43 @@ class ArgoCD extends Feature { // The Operator uses an extra secret to store the admin Password, which is not bcrypted k8sClient.patch('secret', 'argocd-cluster', namespace, [stringData: ['admin.password': password]]) + // In newer Versions ArgoCD Operator uses the password in argocd-cluster secret only as generated initial password // but we want to set our own admin password so we set the password in both Secrets for consistency String bcryptArgoCDPassword = BCrypt.hashpw(password, BCrypt.gensalt(4)) k8sClient.patch('secret', 'argocd-secret', namespace, [stringData: ['admin.password': bcryptArgoCDPassword]]) - updatingArgoCDManagedNamespaces() log.debug("Apply RBAC permissions for ArgoCD in all managed namespaces imperatively") // Apply rbac yamls from operator/rbac folder - String argocdRbacPath = Path.of(argocdRepoInitializationAction.repo.getAbsoluteLocalRepoTmpDir(), OPERATOR_RBAC_PATH) + String argocdRbacPath = repoLayout.operatorRbacDir() k8sClient.applyYaml("${argocdRbacPath} --recursive") } + + private void deployWithHelm() { + ArgoCDRepoLayout repoLayout = repoLayout() + + // Install umbrella chart from argocd/argocd + String umbrellaChartPath = repoLayout.helmDir() + // Even if the Chart.lock already contains the repo, we need to add it before resolving it + // See https://github.com/helm/helm/issues/8036#issuecomment-872502901 + List helmDependencies = fileSystemUtils.readYaml( + Path.of(repoLayout.chartYaml()))['dependencies'] + helmClient.addRepo('argo', helmDependencies[0]['repository'] as String) + helmClient.dependencyBuild(umbrellaChartPath) + helmClient.upgrade('argocd', umbrellaChartPath, [namespace: namespace]) + + log.debug("Setting new argocd admin password") + // Set admin password imperatively here instead of values.yaml, because we don't want it to show in git repo + String bcryptArgoCDPassword = BCrypt.hashpw(password, BCrypt.gensalt(4)) + k8sClient.patch('secret', 'argocd-secret', namespace, + [stringData: ['admin.password': bcryptArgoCDPassword]]) + + } + // The ArgoCD instance installed via an operator only manages its deployment namespace. // To manage additional namespaces, we need to update the 'argocd-default-cluster-config' secret with all managed namespaces. void updatingArgoCDManagedNamespaces() { @@ -298,6 +341,8 @@ class ArgoCD extends Feature { private void generateRBAC() { log.debug("Generate RBAC permissions for ArgoCD in all managed namespaces") + ArgoCDRepoLayout repoLayout = repoLayout() + if (config.multiTenant.useDedicatedInstance) { //Generating Tenant Namespace RBACs for Tenant Argocd for (String ns : config.application.namespaces.tenantNamespaces) { @@ -309,8 +354,8 @@ class ArgoCD extends Feature { ["argocd-argocd-server", "argocd-argocd-application-controller", "argocd-applicationset-controller"] ) .withConfig(config) - .withRepo(argocdRepoInitializationAction.repo) - .withSubfolder("${OPERATOR_RBAC_PATH}/tenant") + .withRepo(clusterResourcesInitializationAction.repo) + .withSubfolder(repoLayout.operatorRbacTenantSubfolder()) .generate() } @@ -325,8 +370,8 @@ class ArgoCD extends Feature { ["argocd-argocd-server", "argocd-argocd-application-controller", "argocd-applicationset-controller"] ) .withConfig(config) - .withRepo(argocdRepoInitializationAction.repo) - .withSubfolder(OPERATOR_RBAC_PATH) + .withRepo(clusterResourcesInitializationAction.repo) + .withSubfolder(repoLayout.operatorRbacSubfolder()) .generate() } } else { @@ -339,12 +384,12 @@ class ArgoCD extends Feature { ["argocd-argocd-server", "argocd-argocd-application-controller", "argocd-applicationset-controller"] ) .withConfig(config) - .withRepo(argocdRepoInitializationAction.repo) - .withSubfolder(OPERATOR_RBAC_PATH) + .withRepo(clusterResourcesInitializationAction.repo) + .withSubfolder(repoLayout.operatorRbacSubfolder()) .generate() } - if(config.application.clusterAdmin) { + if (config.application.clusterAdmin) { new RbacDefinition(Role.Variant.CLUSTER_ADMIN) .withName("argocd-cluster-admin") .withNamespace(namespace) @@ -353,8 +398,8 @@ class ArgoCD extends Feature { ["argocd-argocd-server", "argocd-argocd-application-controller", "argocd-applicationset-controller"] ) .withConfig(config) - .withRepo(argocdRepoInitializationAction.repo) - .withSubfolder(OPERATOR_RBAC_PATH) + .withRepo(clusterResourcesInitializationAction.repo) + .withSubfolder(repoLayout.operatorRbacSubfolder()) .generate() } } @@ -383,66 +428,29 @@ class ArgoCD extends Feature { } protected void createSCMCredentialsSecret() { - log.debug("Creating repo credential secret that is used by argocd to access repos in ${config.scm.scmProviderType.toString()}") - // Create secret imperatively here instead of values.yaml, because we don't want it to show in git repo - def repoTemplateSecretName = 'argocd-repo-creds-scm' - k8sClient.createSecret('generic', repoTemplateSecretName, namespace, - new Tuple2('url', this.gitHandler.tenant.url), - new Tuple2('username', this.gitHandler.tenant.credentials.username), - new Tuple2('password', this.gitHandler.tenant.credentials.password) + // Create secret imperatively here instead of values.yaml, because we don't want it to show in git repo + createRepoCredentialsSecret( + 'argocd-repo-creds-scm', + namespace, + gitHandler.tenant.url, + gitHandler.tenant.credentials.username, + gitHandler.tenant.credentials.password ) - k8sClient.label('secret', repoTemplateSecretName, namespace, - new Tuple2('argocd.argoproj.io/secret-type', 'repo-creds')) - if (config.multiTenant.useDedicatedInstance) { log.debug("Creating central repo credential secret that is used by argocd to access repos in ${config.scm.scmProviderType.toString()}") - // Create secret imperatively here instead of values.yaml, because we don't want it to show in git repo - def centralRepoTemplateSecretName = 'argocd-repo-creds-central-scm' - k8sClient.createSecret('generic', centralRepoTemplateSecretName, config.multiTenant.centralArgocdNamespace, - new Tuple2('url', this.gitHandler.central.url), - new Tuple2('username', this.gitHandler.central.credentials.username), - new Tuple2('password', this.gitHandler.central.credentials.password) + // Create secret imperatively here instead of values.yaml, because we don't want it to show in git repo + createRepoCredentialsSecret( + 'argocd-repo-creds-central-scm', + config.multiTenant.centralArgocdNamespace, + gitHandler.central.url, + gitHandler.central.credentials.username, + gitHandler.central.credentials.password ) - - k8sClient.label('secret', centralRepoTemplateSecretName, config.multiTenant.centralArgocdNamespace, - new Tuple2('argocd.argoproj.io/secret-type', 'repo-creds')) - } - } - - protected void prepareArgoCdRepo() { - - argocdRepoInitializationAction.initLocalRepo() - - if (config.features.argocd.operator) { - log.debug("Deleting unnecessary argocd (argocd helm variant) folder from argocd repo: ${argocdRepoInitializationAction.repo.getAbsoluteLocalRepoTmpDir()}") - FileSystemUtils.deleteDir argocdRepoInitializationAction.repo.getAbsoluteLocalRepoTmpDir() + '/argocd' - log.debug("Deleting unnecessary namespaces resources from clusterResources repo: ${clusterResourcesInitializationAction.repo.getAbsoluteLocalRepoTmpDir()}") - FileSystemUtils.deleteFile clusterResourcesInitializationAction.repo.getAbsoluteLocalRepoTmpDir() + '/misc/namespaces.yaml' - generateRBAC() - } else { - log.debug("Deleting unnecessary operator (argocd operator variant) folder from argocd repo: ${argocdRepoInitializationAction.repo.getAbsoluteLocalRepoTmpDir()}") - FileSystemUtils.deleteDir argocdRepoInitializationAction.repo.getAbsoluteLocalRepoTmpDir() + '/operator' - } - - if (config.multiTenant.useDedicatedInstance) { - log.debug("Deleting unnecessary non dedicated instances folders from argocd repo: ${argocdRepoInitializationAction.repo.getAbsoluteLocalRepoTmpDir()}") - FileSystemUtils.deleteDir argocdRepoInitializationAction.repo.getAbsoluteLocalRepoTmpDir() + '/applications' - FileSystemUtils.deleteDir argocdRepoInitializationAction.repo.getAbsoluteLocalRepoTmpDir() + '/projects' - } else { - log.debug("Deleting unnecessary multiTenant folder from argocd repo: ${argocdRepoInitializationAction.repo.getAbsoluteLocalRepoTmpDir()}") - FileSystemUtils.deleteDir argocdRepoInitializationAction.repo.getAbsoluteLocalRepoTmpDir() + '/multiTenant' - } - - if (!config.application.netpols) { - log.debug("Deleting argocd netpols.") - FileSystemUtils.deleteFile argocdRepoInitializationAction.repo.getAbsoluteLocalRepoTmpDir() + '/argocd/templates/allow-namespaces.yaml' } - - argocdRepoInitializationAction.repo.commitAndPush("Initial Commit") } protected RepoInitializationAction createRepoInitializationAction(String localSrcDir, String scmRepoTarget, Boolean isCentral) { @@ -454,9 +462,22 @@ class ArgoCD extends Feature { new RepoInitializationAction(config, repoProvider.getRepo(scmRepoTarget, gitProvider), this.gitHandler, localSrcDir) } - private void replaceFileContentInYamls(File folder, String from, String to) { - fileSystemUtils.getAllFilesFromDirectoryWithEnding(folder.absolutePath, ".yaml").forEach(file -> { - fileSystemUtils.replaceFileContent(file.absolutePath, from, to) - }) + private void createRepoCredentialsSecret(String secretName, String ns, String url, String username, String password) { + k8sClient.createSecret('generic', secretName, ns, + new Tuple2('url', url), + new Tuple2('username', username), + new Tuple2('password', password) + ) + k8sClient.label('secret', secretName, ns, + new Tuple2('argocd.argoproj.io/secret-type', 'repo-creds')) + } + + protected ArgoCDRepoLayout repoLayout() { + new ArgoCDRepoLayout(clusterResourcesInitializationAction.repo.getAbsoluteLocalRepoTmpDir()) } + + private ArgoCDRepoLayout tenantRepoLayout() { + new ArgoCDRepoLayout(tenantBootstrapInitializationAction.repo.getAbsoluteLocalRepoTmpDir()) + } + } \ No newline at end of file diff --git a/src/main/groovy/com/cloudogu/gitops/features/argocd/ArgoCDRepoLayout.groovy b/src/main/groovy/com/cloudogu/gitops/features/argocd/ArgoCDRepoLayout.groovy new file mode 100644 index 000000000..b1a1db049 --- /dev/null +++ b/src/main/groovy/com/cloudogu/gitops/features/argocd/ArgoCDRepoLayout.groovy @@ -0,0 +1,145 @@ +package com.cloudogu.gitops.features.argocd + +import java.nio.file.Path + +class ArgoCDRepoLayout { + private static final String APPS_MONITORING_REL = 'apps/prometheusstack' + private static final String APPS_SECRETS_REL = 'apps/external-secrets' + private static final String APPS_VAULT_REL = 'apps/vault' + private static final String APPS_CERTMANAGER_REL = 'apps/cert-manager' + private static final String APPS_JENKINS_REL = 'apps/jenkins' + private static final String APPS_INGRESS_REL = 'apps/ingress' + private static final String APPS_MAILHOG_REL = 'apps/mailhog' + private static final String APPS_SCMMANAGER_REL = 'apps/scm-manager' + private static final String APPS_ARGOCD_REL = 'apps/argocd' + + private static final String OPERATOR_DIR = 'operator' + private static final String MULTITENANT_DIR = 'multiTenant' + private static final String APPLICATIONS_DIR = 'applications' + private static final String PROJECTS_DIR = 'projects' + private static final String HELM_DIR = 'argocd' // argocd/argocd + private static final String NETPOL_REL = 'templates/allow-namespaces.yaml' + private static final String NAMESPACES_YAML = 'misc/namespaces.yaml' + + private final String repoRootDir + + ArgoCDRepoLayout(String repoRootDir) { + this.repoRootDir = repoRootDir + } + + String rootDir() { + repoRootDir + } + + String argocdRoot() { + Path.of(repoRootDir, APPS_ARGOCD_REL).toString() + } + + // --- folder --- + + String operatorDir() { + Path.of(argocdRoot(), OPERATOR_DIR).toString() + } + + String operatorConfigFile() { + // "cluster-resources/argocd/operator/argocd.yaml" + Path.of(operatorDir(), "argocd.yaml").toString() + } + + String operatorRbacDir() { + // "cluster-resources/argocd/operator/rbac" + Path.of(operatorDir(), "rbac").toString() + } + + String multiTenantDir() { + Path.of(argocdRoot(), MULTITENANT_DIR).toString() + } + + String applicationsDir() { + Path.of(argocdRoot(), APPLICATIONS_DIR).toString() + } + + String projectsDir() { + Path.of(argocdRoot(), PROJECTS_DIR).toString() + } + + String helmDir() { + Path.of(argocdRoot(), HELM_DIR).toString() + } + + String monitoringDir() { + Path.of(repoRootDir, APPS_MONITORING_REL).toString() + } + + String vaultDir() { + Path.of(repoRootDir, APPS_VAULT_REL).toString() + } + + static String monitoringSubdirRel() { + APPS_MONITORING_REL + } + + static String secretsSubdirRel() { + APPS_SECRETS_REL + } + static String vaultSubdirRel() { + APPS_VAULT_REL + } + + static String certManagerSubdirRel() { + APPS_CERTMANAGER_REL + } + + static String jenkinsSubdirRel() { + APPS_JENKINS_REL + } + + static String ingressSubdirRel() { + APPS_INGRESS_REL + } + static String mailhogSubdirRel() { + APPS_MAILHOG_REL + } + static String scmManagerSubdirRel() { + APPS_SCMMANAGER_REL + } + static String argocdSubdirRel() { + APPS_ARGOCD_REL + } + + // --- files --- + + String chartYaml() { + Path.of(helmDir(), "Chart.yaml").toString() + } + + String netpolFile() { + Path.of(helmDir(), NETPOL_REL).toString() + } + + String namespacesYaml() { + Path.of(repoRootDir, NAMESPACES_YAML).toString() + } + + // --- dedicated instance bootstrap --- + + String dedicatedTenantProject() { + Path.of(argocdRoot(), MULTITENANT_DIR, "central/projects/tenant.yaml").toString() + } + + String dedicatedBootstrapApp() { + Path.of(argocdRoot(), MULTITENANT_DIR, "central/applications/bootstrap.yaml").toString() + } + + + // --- relative subfolders for RBAC (passed to RbacDefinition.withSubfolder) --- + static String operatorRbacSubfolder() { + // "argocd/operator/rbac" + "${APPS_ARGOCD_REL}/${OPERATOR_DIR}/rbac" + } + + static String operatorRbacTenantSubfolder() { + // "argocd/operator/rbac/tenant" + "${operatorRbacSubfolder()}/tenant" + } +} diff --git a/src/main/groovy/com/cloudogu/gitops/features/argocd/RepoInitializationAction.groovy b/src/main/groovy/com/cloudogu/gitops/features/argocd/RepoInitializationAction.groovy index d37cd87a2..39c4cf4ef 100644 --- a/src/main/groovy/com/cloudogu/gitops/features/argocd/RepoInitializationAction.groovy +++ b/src/main/groovy/com/cloudogu/gitops/features/argocd/RepoInitializationAction.groovy @@ -4,10 +4,13 @@ import com.cloudogu.gitops.config.Config import com.cloudogu.gitops.features.git.GitHandler import com.cloudogu.gitops.git.GitRepo import freemarker.template.DefaultObjectWrapperBuilder +import groovy.util.logging.Slf4j +@Slf4j class RepoInitializationAction { private GitRepo repo private String copyFromDirectory + Set subDirsToCopy = [] as Set private Config config private GitHandler gitHandler @@ -19,11 +22,14 @@ class RepoInitializationAction { } /** - * Clone repo from SCM and initialize it with default basic files. Afterwards we can edit these files. + * Clone repo from SCM and initialize it by copying only the configured subdirectories. + * Afterwards we can edit these files. */ void initLocalRepo() { repo.cloneRepo() - repo.copyDirectoryContents(copyFromDirectory) + + log.debug("Initializing repo ${repo.repoTarget} from ${copyFromDirectory} with subdirs: ${subDirsToCopy}") + repo.copyDirectoryContents(copyFromDirectory, createSubdirFilter()) replaceTemplates() } @@ -55,4 +61,77 @@ class RepoInitializationAction { return model } + private FileFilter createSubdirFilter() { + if (!subDirsToCopy || subDirsToCopy.isEmpty()) { + return { File f -> true } as FileFilter + } + + File srcRoot = new File(copyFromDirectory).canonicalFile + + // Normalize entries like "argocd", "apps/monitoring" to "argocd/" or "apps/monitoring/" + Set prefixes = subDirsToCopy.collect { String s -> + def norm = s.replace('\\', '/') + norm = norm.replaceAll('^/+', '').replaceAll('/+$', '') + return norm + '/' + } as Set + + boolean hasPrefixes = !prefixes.isEmpty() + + // Templates that MUST be copied (chart templates), even though they match the global templates-exclude + Set templateIncludePrefixes = [ + 'apps/argocd/argocd/templates/' + ] as Set + + return { File f -> + File canon = f.canonicalFile + String rel = srcRoot.toURI().relativize(canon.toURI()).toString() + rel = rel.replace('\\', '/') + + // Always copy the root (copyFromDirectory itself), otherwise we can't build up the directory structure + if (rel == '' || rel == '.') { + return true + } + + boolean isDir = f.isDirectory() + // For directories, always compare using a trailing slash + String relDir = rel.endsWith('/') ? rel : rel + '/' + + // --- Exception: keep required chart templates (e.g., ArgoCD chart templates) --- + // If the current path is inside an explicitly allowed templates subtree, always allow it. + if (templateIncludePrefixes.any { String p -> + (isDir ? relDir : rel).startsWith(p) + }) { + return true + } + + // --- Global excludes for feature templates --- + // do NOT copy anything under apps/**/templates/** into the SCM repo + if (rel.startsWith('apps/') && relDir.contains('/templates/')) { + return false + } + + // If no prefixes are configured, copy everything (except templates) + if (!hasPrefixes) { + return true + } + + if (isDir) { + // Allow a directory if it is: + // - exactly one of the requested subdirs, or + // - inside one of them, or + // - a parent of one of them (needed to keep the tree structure). + return prefixes.any { String p -> + relDir == p || relDir.startsWith(p) || p.startsWith(relDir) + } + } else { + // Only copy files that are directly under one of the allowed subtrees + return prefixes.any { String p -> + rel.startsWith(p) + } + } + } as FileFilter + } + + + } \ No newline at end of file diff --git a/src/main/groovy/com/cloudogu/gitops/features/deployment/ArgoCdApplicationStrategy.groovy b/src/main/groovy/com/cloudogu/gitops/features/deployment/ArgoCdApplicationStrategy.groovy index cb3d3b2d5..eaddbabcd 100644 --- a/src/main/groovy/com/cloudogu/gitops/features/deployment/ArgoCdApplicationStrategy.groovy +++ b/src/main/groovy/com/cloudogu/gitops/features/deployment/ArgoCdApplicationStrategy.groovy @@ -45,19 +45,61 @@ class ArgoCdApplicationStrategy implements DeploymentStrategy { GitRepo clusterResourcesRepo = gitRepoProvider.getRepo('argocd/cluster-resources', this.gitHandler.resourcesScm) clusterResourcesRepo.cloneRepo() - // Inline values from tmpHelmValues file into ArgoCD Application YAML - def inlineValues = helmValuesPath.toFile().text - String project = "cluster-resources" String namespaceName = "${namePrefix}argocd" //DedicatedInstances if (config.multiTenant.useDedicatedInstance) { repoName = "${config.application.namePrefix}${repoName}" - namespaceName = "argocd" + namespaceName = "${config.multiTenant.centralArgocdNamespace}" project = config.application.namePrefix.replaceFirst(/-$/, "") } + // Feature-Name -> Ordner underapps//misc + // e.g. repoName = "prometheus" → apps/prometheus/misc + String featureName = repoName + String miscPath = "apps/${featureName}/misc" + + + String valuesRelPath = "${miscPath}/${featureName}-gop-helm.yaml" // relative to repo-root + // inline values from tmpHelmValues file into ArgoCD Application YAML + def inlineValues = helmValuesPath.toFile().text + clusterResourcesRepo.writeFile(valuesRelPath, inlineValues) + + //GOP should not overwrite this file + String userValuesRelPath = "${miscPath}/${featureName}-user-values.yaml" + clusterResourcesRepo.writeFile(userValuesRelPath, "") + + // 1) helm source (external chart source) + def helmSource = [ + repoURL : repoURL, + (chooseKeyChartOrPath(repoType)) : chartOrPath, + targetRevision : version, + helm : [ + releaseName: releaseName, + valueFiles : [ + "\$values/${valuesRelPath}".toString(), + "\$values/${userValuesRelPath}".toString() + ], + ignoreMissingValueFiles: true + ] + ] + + // 2) Git source for misc + values + // - repoURL: cluster-resources repo + // - ref: values → used in valueFiles as $values + // - path: apps//misc → additional manifests + def miscRepoUrl = "${clusterResourcesRepo.gitProvider.repoPrefix()}argocd/cluster-resources.git".toString() + def miscSource = [ + repoURL : miscRepoUrl, + targetRevision: "main", + ref : "values", + path : miscPath, + directory : [recurse: true] + ] + + def sources = [helmSource, miscSource] + // Prepare ArgoCD Application YAML def yamlMapper = YAMLMapper.builder() .enable(YAMLGenerator.Feature.LITERAL_BLOCK_STYLE) @@ -76,15 +118,7 @@ class ArgoCdApplicationStrategy implements DeploymentStrategy { namespace: namespace ], project : project, - sources : [[ - repoURL : repoURL, - "${chooseKeyChartOrPath(repoType)}": chartOrPath, - targetRevision : version, - helm : [ - releaseName: releaseName, - values : inlineValues - ] - ]], + sources : sources, syncPolicy : [ automated : [ prune : true, @@ -100,7 +134,8 @@ class ArgoCdApplicationStrategy implements DeploymentStrategy { ] ]) - clusterResourcesRepo.writeFile("argocd/${releaseName}.yaml", yamlResult) + String appManifestPath = "apps/argocd/applications/${releaseName}.yaml" + clusterResourcesRepo.writeFile(appManifestPath, yamlResult) log.debug("Deploying helm release ${releaseName} basing on chart ${chartOrPath} from ${repoURL}, version " + "${version}, into namespace ${namespace}. Using Argo CD application:\n${yamlResult}") diff --git a/src/main/groovy/com/cloudogu/gitops/features/git/GitHandler.groovy b/src/main/groovy/com/cloudogu/gitops/features/git/GitHandler.groovy index 472961bc7..c45eb7a20 100644 --- a/src/main/groovy/com/cloudogu/gitops/features/git/GitHandler.groovy +++ b/src/main/groovy/com/cloudogu/gitops/features/git/GitHandler.groovy @@ -92,7 +92,7 @@ class GitHandler extends Feature { case ScmProviderType.SCM_MANAGER: def prefixedNamespace = "${config.application.namePrefix}scm-manager".toString() config.scm.scmManager.namespace = prefixedNamespace - this.tenant = new ScmManager(this.config, config.scm.scmManager, helmStrategy,k8sClient, networkingUtils) + this.tenant = new ScmManager(this.config, config.scm.scmManager, helmStrategy,k8sClient, networkingUtils, true) // this.tenant.setup() setup will be here in future break default: @@ -116,25 +116,18 @@ class GitHandler extends Feature { final String namePrefix = (config?.application?.namePrefix ?: "").trim() if (this.central) { setupRepos(this.central, namePrefix) - setupRepos(this.tenant, namePrefix, false) + setupRepos(this.tenant, namePrefix) } else { - setupRepos(this.tenant, namePrefix, true) + setupRepos(this.tenant, namePrefix) } create3thPartyDependencies(this.tenant, namePrefix) } - // includeClusterResources = true => also create the argocd/cluster-resources repository - static void setupRepos(GitProvider gitProvider, String namePrefix = "", boolean includeClusterResources = true) { + static void setupRepos(GitProvider gitProvider, String namePrefix = "") { gitProvider.createRepository( - withOrgPrefix(namePrefix, "argocd/argocd"), - "GitOps repo for administration of ArgoCD" + withOrgPrefix(namePrefix, "argocd/cluster-resources"), + "GitOps repo for basic cluster-resources" ) - if (includeClusterResources) { - gitProvider.createRepository( - withOrgPrefix(namePrefix, "argocd/cluster-resources"), - "GitOps repo for basic cluster-resources" - ) - } } static create3thPartyDependencies(GitProvider gitProvider, String namePrefix = "") { diff --git a/src/main/groovy/com/cloudogu/gitops/features/git/config/ScmCentralSchema.groovy b/src/main/groovy/com/cloudogu/gitops/features/git/config/ScmCentralSchema.groovy index 84eaf379b..b8cb97f56 100644 --- a/src/main/groovy/com/cloudogu/gitops/features/git/config/ScmCentralSchema.groovy +++ b/src/main/groovy/com/cloudogu/gitops/features/git/config/ScmCentralSchema.groovy @@ -17,8 +17,6 @@ class ScmCentralSchema { public static final String CENTRAL_GITLAB_PARENTGROUP_ID_DESCRIPTION = "Main Group for Gitlab where the GOP creates it's groups/repos" // Only supports external Gitlab for now - Boolean internal = false - @Option(names = ['--central-gitlab-url'], description = CENTRAL_GITLAB_URL_DESCRIPTION) @JsonPropertyDescription(CENTRAL_GITLAB_URL_DESCRIPTION) String url = 'https://gitlab.com/' diff --git a/src/main/groovy/com/cloudogu/gitops/features/git/config/util/ScmManagerConfig.groovy b/src/main/groovy/com/cloudogu/gitops/features/git/config/util/ScmManagerConfig.groovy index ffdd63813..5e92bc6c7 100644 --- a/src/main/groovy/com/cloudogu/gitops/features/git/config/util/ScmManagerConfig.groovy +++ b/src/main/groovy/com/cloudogu/gitops/features/git/config/util/ScmManagerConfig.groovy @@ -6,7 +6,6 @@ import com.cloudogu.gitops.config.Credentials interface ScmManagerConfig { Boolean getInternal() - String getUrl() String getUsername() String getPassword() diff --git a/src/main/groovy/com/cloudogu/gitops/git/GitRepo.groovy b/src/main/groovy/com/cloudogu/gitops/git/GitRepo.groovy index be6b95d15..fd0001fc6 100644 --- a/src/main/groovy/com/cloudogu/gitops/git/GitRepo.groovy +++ b/src/main/groovy/com/cloudogu/gitops/git/GitRepo.groovy @@ -186,13 +186,10 @@ class GitRepo { file.text = content } - void replaceTemplates(Map parameters) { new TemplatingEngine().replaceTemplates(new File(absoluteLocalRepoTmpDir), parameters) } - - String getGitRepositoryUrl() { return this.gitProvider.repoUrl(repoTarget, RepoUrlScope.CLIENT) } diff --git a/src/main/groovy/com/cloudogu/gitops/git/providers/scmmanager/ScmManager.groovy b/src/main/groovy/com/cloudogu/gitops/git/providers/scmmanager/ScmManager.groovy index bf4765c60..9ee684f40 100644 --- a/src/main/groovy/com/cloudogu/gitops/git/providers/scmmanager/ScmManager.groovy +++ b/src/main/groovy/com/cloudogu/gitops/git/providers/scmmanager/ScmManager.groovy @@ -28,18 +28,18 @@ class ScmManager implements GitProvider { Config config ScmManagerSetup scmManagerSetup - ScmManager(Config config, ScmManagerConfig scmmConfig, HelmStrategy helmStrategy, K8sClient k8sClient, NetworkingUtils networkingUtils) { + ScmManager(Config config, ScmManagerConfig scmmConfig, HelmStrategy helmStrategy, K8sClient k8sClient, NetworkingUtils networkingUtils, Boolean installNeeded = false) { this.scmmConfig = scmmConfig this.config = config this.helmStrategy = helmStrategy this.k8sClient = k8sClient this.networkingUtils = networkingUtils - init() + init(installNeeded) } - void init() { + void init(installNeeded) { // --- Init Setup --- - if (this.scmmConfig.internal) { + if (this.scmmConfig.internal && installNeeded) { this.scmManagerSetup = new ScmManagerSetup(this) this.scmManagerSetup.setupHelm() this.urls = new ScmManagerUrlResolver(this.config, this.scmmConfig, this.k8sClient, this.networkingUtils) diff --git a/src/main/groovy/com/cloudogu/gitops/git/providers/scmmanager/ScmManagerSetup.groovy b/src/main/groovy/com/cloudogu/gitops/git/providers/scmmanager/ScmManagerSetup.groovy index c89a0a008..a67e32d02 100644 --- a/src/main/groovy/com/cloudogu/gitops/git/providers/scmmanager/ScmManagerSetup.groovy +++ b/src/main/groovy/com/cloudogu/gitops/git/providers/scmmanager/ScmManagerSetup.groovy @@ -12,7 +12,7 @@ class ScmManagerSetup { private ScmManager scmManager - static final String HELM_VALUES_PATH = "scm-manager/values.ftl.yaml" + static final String HELM_VALUES_PATH = "argocd/cluster-resources/apps/scm-manager/templates/values.ftl.yaml" ScmManagerSetup(ScmManager scmManager) { this.scmManager = scmManager @@ -31,7 +31,7 @@ class ScmManagerSetup { return } } catch (Exception e) { - println "Waiting for SCM-Manager... Error: ${e.message}" + log.debug("Waiting for SCM-Manager... Error: ${e.message}") } @@ -79,7 +79,7 @@ class ScmManagerSetup { def installScmmPlugins() { if (this.scmManager.config.scm.scmManager.skipPlugins) { - log.info("Skipping SCM plugin installation") + log.debug("Skipping SCM plugin installation") return } @@ -101,12 +101,12 @@ class ScmManagerSetup { } Boolean restartForThisPlugin = false pluginNames.each { String pluginName -> - log.info("Installing Plugin ${pluginName} ...") + log.debug("Installing Plugin ${pluginName} ...") restartForThisPlugin = !this.scmManager.config.scm.scmManager.skipRestart && pluginName == pluginNames.last() ScmManagerApiClient.handleApiResponse(scmManager.apiClient.pluginApi().install(pluginName, restartForThisPlugin)) } - log.info("SCM-Manager plugin installation finished successfully!") + log.debug("SCM-Manager plugin installation finished successfully!") if (restartForThisPlugin) { waitForScmmAvailable(60,2000,100) } diff --git a/src/main/groovy/com/cloudogu/gitops/git/providers/scmmanager/ScmManagerUrlResolver.groovy b/src/main/groovy/com/cloudogu/gitops/git/providers/scmmanager/ScmManagerUrlResolver.groovy index 3ad218f85..f79d2a4f9 100644 --- a/src/main/groovy/com/cloudogu/gitops/git/providers/scmmanager/ScmManagerUrlResolver.groovy +++ b/src/main/groovy/com/cloudogu/gitops/git/providers/scmmanager/ScmManagerUrlResolver.groovy @@ -14,9 +14,10 @@ class ScmManagerUrlResolver { private final K8sClient k8s private final NetworkingUtils net - private final String releaseName = 'scmm' private URI cachedClusterBind + private final String releaseName = 'scmm' + ScmManagerUrlResolver(Config config, ScmManagerConfig scmm, K8sClient k8s, NetworkingUtils net) { this.config = config this.scmm = scmm diff --git a/src/main/groovy/com/cloudogu/gitops/git/providers/scmmanager/api/ScmManagerApiClient.groovy b/src/main/groovy/com/cloudogu/gitops/git/providers/scmmanager/api/ScmManagerApiClient.groovy index 336a16ad3..a9a5f0ce7 100644 --- a/src/main/groovy/com/cloudogu/gitops/git/providers/scmmanager/api/ScmManagerApiClient.groovy +++ b/src/main/groovy/com/cloudogu/gitops/git/providers/scmmanager/api/ScmManagerApiClient.groovy @@ -55,7 +55,7 @@ class ScmManagerApiClient { log.error(errorMessage) throw new RuntimeException(errorMessage) } else { - log.info("Successfully completed ${apiCall}") + log.debug("Successfully completed ${apiCall}") } } catch (Exception e) { def errorMessage = "Error executing API: ${e.message}" diff --git a/src/main/groovy/com/cloudogu/gitops/jenkins/JobManager.groovy b/src/main/groovy/com/cloudogu/gitops/jenkins/JobManager.groovy index 06d4a85f8..c262211d8 100644 --- a/src/main/groovy/com/cloudogu/gitops/jenkins/JobManager.groovy +++ b/src/main/groovy/com/cloudogu/gitops/jenkins/JobManager.groovy @@ -49,7 +49,7 @@ class JobManager { return false } else { // Note for development: the XML representation of an existing job can be exporting by adding /config.xml to the URL - String payloadXml = new TemplatingEngine().template(new File('jenkins/namespaceJobTemplate.xml.ftl'), + String payloadXml = new TemplatingEngine().template(new File('argocd/cluster-resources/apps/jenkins/templates/namespaceJobTemplate.xml.ftl'), [ SCMM_NAMESPACE_JOB_SERVER_URL : serverUrl, SCMM_NAMESPACE_JOB_NAMESPACE : jobNamespace, diff --git a/src/test/groovy/com/cloudogu/gitops/features/PrometheusStackTest.groovy b/src/test/groovy/com/cloudogu/gitops/features/PrometheusStackTest.groovy index c4f0fcdb2..2383976af 100644 --- a/src/test/groovy/com/cloudogu/gitops/features/PrometheusStackTest.groovy +++ b/src/test/groovy/com/cloudogu/gitops/features/PrometheusStackTest.groovy @@ -34,8 +34,9 @@ class PrometheusStackTest { ], jenkins: [ internal : true, + active: true, metricsUsername: 'metrics', - metricsPassword: 'metrics' + metricsPassword: 'metrics', ], application: [ username : 'abc', @@ -294,12 +295,12 @@ policies: @Test void 'uses ingress if enabled'() { config.features.monitoring.grafanaUrl = 'http://grafana.local' - createStack(scmManagerMock).install() + createStack(scmManagerMock).install() - def ingressYaml = parseActualYaml()['grafana']['ingress'] - assertThat(ingressYaml['enabled']).isEqualTo(true) - assertThat((ingressYaml['hosts'] as List)[0]).isEqualTo('grafana.local') + def serviceYaml = parseActualYaml()['grafana']['service'] + assertThat(serviceYaml['enabled']).isEqualTo(true) + assertThat((serviceYaml['hosts'] as List)[0]).isEqualTo('grafana.local') } @Test @@ -511,7 +512,7 @@ policies: assertThat(yaml['global']['rbac']['create']).isEqualTo(false) for (String namespace : config.application.namespaces.getActiveNamespaces()) { - def rbacYaml = new File("$clusterResourcesRepoDir/misc/monitoring/rbac/${namespace}.yaml") + def rbacYaml = new File("$clusterResourcesRepoDir/apps/prometheusstack/misc/rbac/${namespace}.yaml") assertThat(rbacYaml.text).contains("namespace: ${namespace}") assertThat(rbacYaml.text).contains(" namespace: foo-monitoring") } @@ -534,7 +535,7 @@ policies: prometheusStack.install() for (String namespace : config.application.namespaces.getActiveNamespaces()) { - def netPolsYaml = new File("$clusterResourcesRepoDir/misc/monitoring/netpols/${namespace}.yaml") + def netPolsYaml = new File("$clusterResourcesRepoDir/apps/prometheusstack/misc/netpols/${namespace}.yaml") assertThat(netPolsYaml.text).contains("namespace: ${namespace}") } } diff --git a/src/test/groovy/com/cloudogu/gitops/features/ScmManagerSetupTest.groovy b/src/test/groovy/com/cloudogu/gitops/features/ScmManagerSetupTest.groovy deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/test/groovy/com/cloudogu/gitops/features/argocd/ArgoCDTest.groovy b/src/test/groovy/com/cloudogu/gitops/features/argocd/ArgoCDTest.groovy index 243b922b3..c36ba2f6e 100644 --- a/src/test/groovy/com/cloudogu/gitops/features/argocd/ArgoCDTest.groovy +++ b/src/test/groovy/com/cloudogu/gitops/features/argocd/ArgoCDTest.groovy @@ -2,11 +2,11 @@ package com.cloudogu.gitops.features.argocd import com.cloudogu.gitops.config.Config import com.cloudogu.gitops.git.GitRepo +import com.cloudogu.gitops.git.providers.GitProvider +import com.cloudogu.gitops.utils.* import com.cloudogu.gitops.utils.git.GitHandlerForTests import com.cloudogu.gitops.utils.git.TestGitProvider import com.cloudogu.gitops.utils.git.TestGitRepoFactory -import com.cloudogu.gitops.git.providers.GitProvider -import com.cloudogu.gitops.utils.* import groovy.io.FileType import groovy.json.JsonSlurper import groovy.yaml.YamlSlurper @@ -20,7 +20,6 @@ import java.util.stream.Collectors import static com.github.stefanbirkner.systemlambda.SystemLambda.withEnvironmentVariable import static org.assertj.core.api.Assertions.assertThat -import static org.assertj.core.api.Assertions.fail import static org.assertj.core.api.AssertionsForClassTypes.assertThatCode class ArgoCDTest { @@ -107,14 +106,13 @@ class ArgoCDTest { CommandExecutorForTest k8sCommands = new CommandExecutorForTest() CommandExecutorForTest helmCommands = new CommandExecutorForTest() - GitRepo argocdRepo +// GitRepo argocdRepo String actualHelmValuesFile GitRepo clusterResourcesRepo - GitRepo nginxHelmJenkinsRepo - GitRepo tenantBootstrap List petClinicRepos = [] String prefixPathCentral = '/multiTenant/central/' ArgoCD argocd + ArgoCDRepoLayout repoLayout @Test void 'Installs argoCD'() { @@ -123,18 +121,20 @@ class ArgoCDTest { def argocd = createArgoCD() argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo - this.actualHelmValuesFile = Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), - ArgoCD.HELM_VALUES_PATH - ) + this.clusterResourcesRepo = (argocd as ArgoCDForTest).clusterResourcesRepo + + repoLayout = argocd.repoLayout() + this.actualHelmValuesFile = "${repoLayout.helmDir()}/values.yaml" + k8sCommands.assertExecuted('kubectl create namespace argocd') // check values.yaml - List filesWithInternalSCMM = findFilesContaining(new File(argocdRepo.getAbsoluteLocalRepoTmpDir()), argocd.scmmUrlInternal) + List filesWithInternalSCMM = findFilesContaining( + new File(repoLayout.rootDir()), + clusterResourcesRepo.gitProvider.url + ) assertThat(filesWithInternalSCMM).isNotEmpty() - assertThat(parseActualYaml(actualHelmValuesFile)['argo-cd']['server']['service']['type']) - .isEqualTo('ClusterIP') assertThat(parseActualYaml(actualHelmValuesFile)['argo-cd']['server']['service']['type']) .isEqualTo('ClusterIP') assertThat(parseActualYaml(actualHelmValuesFile)['argo-cd']['notifications']['argocdUrl']).isNull() @@ -146,12 +146,13 @@ class ArgoCDTest { k8sCommands.assertExecuted('kubectl create secret generic argocd-repo-creds-scm -n argocd') k8sCommands.assertExecuted('kubectl label secret argocd-repo-creds-scm -n argocd') - // Check dependency build and helm install - assertThat(helmCommands.actualCommands[0].trim()).isEqualTo('helm repo add argo https://argoproj.github.io/argo-helm') - assertThat(helmCommands.actualCommands[1].trim()).isEqualTo( - "helm dependency build ${Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), 'argocd/')}".toString()) - assertThat(helmCommands.actualCommands[2].trim()).isEqualTo( - "helm upgrade -i argocd ${Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), 'argocd/')} --create-namespace --namespace argocd".toString()) + // Check dependency build and helm install (Chart liegt jetzt unter apps/argocd/argocd) + assertThat(helmCommands.actualCommands[0].trim()) + .isEqualTo('helm repo add argo https://argoproj.github.io/argo-helm') + assertThat(helmCommands.actualCommands[1].trim()) + .isEqualTo("helm dependency build ${repoLayout.helmDir()}".toString()) + assertThat(helmCommands.actualCommands[2].trim()) + .isEqualTo("helm upgrade -i argocd ${repoLayout.helmDir()} --create-namespace --namespace argocd".toString()) // Check patched PW def patchCommand = k8sCommands.assertExecuted('kubectl patch secret argocd-secret -n argocd') @@ -160,55 +161,61 @@ class ArgoCDTest { parseActualYaml(patchFile)['stringData']['admin.password'] as String)) .as("Password hash missmatch").isTrue() - // Check bootstrapping - k8sCommands.assertExecuted("kubectl apply -f " + - "${Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), 'projects/argocd.yaml')}") - k8sCommands.assertExecuted("kubectl apply -f " + - "${Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), 'applications/bootstrap.yaml')}") + // Check bootstrapping (liegt jetzt unter argocd/projects und argocd/applications) + k8sCommands.assertExecuted("kubectl apply -f ${Path.of(repoLayout.projectsDir(), 'argocd.yaml')}") + k8sCommands.assertExecuted("kubectl apply -f ${Path.of(repoLayout.applicationsDir(), 'bootstrap.yaml')}") def deleteCommand = k8sCommands.assertExecuted('kubectl delete secret -n argocd') assertThat(deleteCommand).contains('owner=helm', 'name=argocd') - // Operator disabled - def argocdConfigPath = Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), ArgoCD.OPERATOR_CONFIG_PATH) - def rbacConfigPath = Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), ArgoCD.OPERATOR_RBAC_PATH) - assertThat(argocdConfigPath.toFile()).doesNotExist() - assertThat(rbacConfigPath.toFile()).doesNotExist() + // Operator disabled -> operator Ordner sollte fehlen + assertThat(Path.of(repoLayout.operatorConfigFile()).toFile()).doesNotExist() + assertThat(Path.of(repoLayout.operatorRbacDir()).toFile()).doesNotExist() - // Projects - def clusterRessourcesYaml = new YamlSlurper().parse(Path.of argocdRepo.getAbsoluteLocalRepoTmpDir(), 'projects/cluster-resources.yaml') + // Projects (jetzt unter argocd/projects) + def clusterRessourcesYaml = new YamlSlurper().parse( + Path.of(repoLayout.projectsDir(), 'cluster-resources.yaml') + ) assertThat(clusterRessourcesYaml['spec']['sourceRepos'] as List).contains( - 'https://prometheus-community.github.io/helm-charts') + 'https://prometheus-community.github.io/helm-charts' + ) assertThat(clusterRessourcesYaml['spec']['sourceRepos'] as List).doesNotContain( - 'http://scmm-scm-manager.default.svc.cluster.local/scm/repo/3rd-party-dependencies/kube-prometheus-stack') - // The other project files should be validated here as well! + 'http://scmm-scm-manager.default.svc.cluster.local/scm/repo/3rd-party-dependencies/kube-prometheus-stack' + ) - // Applications - def argocdYaml = new YamlSlurper().parse(Path.of argocdRepo.getAbsoluteLocalRepoTmpDir(), 'applications/argocd.yaml') + // Applications (jetzt unter argocd/applications) + def argocdYaml = new YamlSlurper().parse( + Path.of(repoLayout.applicationsDir(), 'argocd.yaml') + ) assertThat(argocdYaml['spec']['source']['directory']).isNull() - assertThat(argocdYaml['spec']['source']['path']).isEqualTo('argocd/') + + // Neuer Pfad: Chart liegt unter argocd/argocd (nicht mehr nur argocd/) + assertThat(argocdYaml['spec']['source']['path'] as String) + .isIn('apps/argocd/argocd', 'apps/argocd/argocd/') } + @Test void 'Installs argoCD for remote and external Scmm'() { config.application.remote = true config.scm.scmManager.internal = false config.scm.scmManager.url = "https://abc" config.features.argocd.url = 'https://argo.cd' + String scmmUrlInternal = "http://scmm.${config.application.namePrefix}scm-manager.svc.cluster.local/scm" def argocd = createArgoCD() argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo - this.actualHelmValuesFile = Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), - ArgoCD.HELM_VALUES_PATH + repoLayout = argocd.repoLayout() + // check values.yaml + List filesWithInternalSCMM = findFilesContaining( + new File(repoLayout.rootDir()), + scmmUrlInternal ) - - - List filesWithInternalSCMM = findFilesContaining(new File(argocdRepo.getAbsoluteLocalRepoTmpDir()), argocd.scmmUrlInternal) assertThat(filesWithInternalSCMM).isEmpty() - List filesWithExternalSCMM = findFilesContaining(new File(argocdRepo.getAbsoluteLocalRepoTmpDir()), "https://abc") + List filesWithExternalSCMM = findFilesContaining(new File(repoLayout.rootDir()), "https://abc") assertThat(filesWithExternalSCMM).isNotEmpty() + this.actualHelmValuesFile = "${repoLayout.helmDir()}/values.yaml" def valuesYaml = parseActualYaml(actualHelmValuesFile) assertThat(valuesYaml['argo-cd']['server']['service']['type']).isEqualTo('LoadBalancer') assertThat(valuesYaml['argo-cd']['notifications']['argocdUrl']).isEqualTo('https://argo.cd') @@ -222,26 +229,25 @@ class ArgoCDTest { def argocd = createArgoCD() argocd.install() - this.clusterResourcesRepo = (argocd as ArgoCDForTest).clusterResourcesRepo + repoLayout = argocd.repoLayout() - assertThat(new File(clusterResourcesRepo.getAbsoluteLocalRepoTmpDir() + ArgoCD.MONITORING_RESOURCES_PATH)).doesNotExist() + assertThat(new File(repoLayout.monitoringDir())).doesNotExist() } @Test void 'When monitoring enabled: Does push path monitoring to cluster resources'() { config.features.monitoring.active = true - def argo = createArgoCD() - argo.install() - this.clusterResourcesRepo = (argo as ArgoCDForTest).clusterResourcesRepo - - assertThat(new File(clusterResourcesRepo.getAbsoluteLocalRepoTmpDir() + ArgoCD.MONITORING_RESOURCES_PATH)).exists() + def argocd = createArgoCD() + argocd.install() + repoLayout = argocd.repoLayout() - assertValidDashboards() + assertThat(new File(repoLayout.monitoringDir())).exists() + assertValidDashboards(repoLayout.monitoringDir()) } - void assertValidDashboards() { - Files.walk(Path.of(clusterResourcesRepo.getAbsoluteLocalRepoTmpDir(), "/misc/monitoring/")) + void assertValidDashboards(String monitoringPath) { + Files.walk(Path.of(monitoringPath)) .filter { it.toString() ==~ /.*-dashboard\.yaml/ }.each { Path path -> def dashboardConfigMap = null @@ -262,25 +268,25 @@ class ArgoCDTest { void 'When ingressNginx disabled: Does not push monitoring dashboard resources'() { config.features.monitoring.active = true config.features.ingressNginx.active = false + def argocd = createArgoCD() argocd.install() - this.clusterResourcesRepo = (argocd as ArgoCDForTest).clusterResourcesRepo + repoLayout = argocd.repoLayout() - assertThat(new File(clusterResourcesRepo.getAbsoluteLocalRepoTmpDir() + ArgoCD.MONITORING_RESOURCES_PATH)).exists() - assertThat(new File(clusterResourcesRepo.getAbsoluteLocalRepoTmpDir() + "/misc/ingress-nginx-dashboard.yaml")).doesNotExist() - assertThat(new File(clusterResourcesRepo.getAbsoluteLocalRepoTmpDir() + "/misc/ingress-nginx-dashboard-requests-handling.yaml")).doesNotExist() + assertThat(new File(repoLayout.monitoringDir())).exists() + assertThat(new File(repoLayout.monitoringDir() + "/misc/dashboard/ingress-nginx-dashboard.yaml")).doesNotExist() + assertThat(new File(repoLayout.monitoringDir() + "/misc/dashboard/ingress-nginx-dashboard-requests-handling.yaml")).doesNotExist() } @Test void 'When mailhog disabled: Does not include mail configurations into cluster resources'() { config.features.mail.active = false config.features.mail.mailhog = false + def argocd = createArgoCD() argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo - this.actualHelmValuesFile = Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), - ArgoCD.HELM_VALUES_PATH - ) + repoLayout = argocd.repoLayout() + this.actualHelmValuesFile = "${repoLayout.helmDir()}/values.yaml" def valuesYaml = parseActualYaml(actualHelmValuesFile) assertThat(valuesYaml['argo-cd']['notifications']['enabled']).isEqualTo(false) @@ -290,14 +296,13 @@ class ArgoCDTest { @Test void 'When mailhog enabled: Includes mail configurations into cluster resources'() { config.features.mail.active = true + def argocd = createArgoCD() argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo - this.actualHelmValuesFile = Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), - ArgoCD.HELM_VALUES_PATH - ) - + repoLayout = argocd.repoLayout() + this.actualHelmValuesFile = "${repoLayout.helmDir()}/values.yaml" def valuesYaml = parseActualYaml(actualHelmValuesFile) + assertThat(valuesYaml['argo-cd']['notifications']['enabled']).isEqualTo(true) assertThat(valuesYaml['argo-cd']['notifications']['notifiers']).isNotNull() } @@ -308,19 +313,16 @@ class ArgoCDTest { config.features.argocd.emailFrom = 'argocd@example.com' config.features.argocd.emailToUser = 'app-team@example.com' config.features.argocd.emailToAdmin = 'argocd@example.com' + def argocd = createArgoCD() argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo - - this.actualHelmValuesFile = Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), - ArgoCD.HELM_VALUES_PATH - ) - - + repoLayout = argocd.repoLayout() + this.actualHelmValuesFile = "${repoLayout.helmDir()}/values.yaml" def valuesYaml = parseActualYaml(actualHelmValuesFile) - def clusterRessourcesYaml = new YamlSlurper().parse(Path.of argocdRepo.getAbsoluteLocalRepoTmpDir(), 'projects/cluster-resources.yaml') - def argocdYaml = new YamlSlurper().parse(Path.of argocdRepo.getAbsoluteLocalRepoTmpDir(), 'applications/argocd.yaml') - def defaultYaml = new YamlSlurper().parse(Path.of argocdRepo.getAbsoluteLocalRepoTmpDir(), 'projects/default.yaml') + + def clusterRessourcesYaml = new YamlSlurper().parse(Path.of repoLayout.projectsDir(), "cluster-resources.yaml") + def argocdYaml = new YamlSlurper().parse(Path.of repoLayout.applicationsDir(), 'argocd.yaml') + def defaultYaml = new YamlSlurper().parse(Path.of repoLayout.projectsDir(), 'default.yaml') assertThat(new YamlSlurper().parseText(valuesYaml['argo-cd']['notifications']['notifiers']['service.email'] as String)['from']).isEqualTo("argocd@example.com") assertThat(clusterRessourcesYaml['metadata']['annotations']['notifications.argoproj.io/subscribe.email']).isEqualTo('argocd@example.com') @@ -334,16 +336,13 @@ class ArgoCDTest { def argocd = createArgoCD() argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo - - this.actualHelmValuesFile = Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), - ArgoCD.HELM_VALUES_PATH - ) - + repoLayout = argocd.repoLayout() + this.actualHelmValuesFile = "${repoLayout.helmDir()}/values.yaml" def valuesYaml = parseActualYaml(actualHelmValuesFile) - def clusterRessourcesYaml = new YamlSlurper().parse(Path.of argocdRepo.getAbsoluteLocalRepoTmpDir(), 'projects/cluster-resources.yaml') - def argocdYaml = new YamlSlurper().parse(Path.of argocdRepo.getAbsoluteLocalRepoTmpDir(), 'applications/argocd.yaml') - def defaultYaml = new YamlSlurper().parse(Path.of argocdRepo.getAbsoluteLocalRepoTmpDir(), 'projects/default.yaml') + + def clusterRessourcesYaml = new YamlSlurper().parse(Path.of repoLayout.projectsDir(), "cluster-resources.yaml") + def argocdYaml = new YamlSlurper().parse(Path.of repoLayout.applicationsDir(), 'argocd.yaml') + def defaultYaml = new YamlSlurper().parse(Path.of repoLayout.projectsDir(), 'default.yaml') assertThat(new YamlSlurper().parseText(valuesYaml['argo-cd']['notifications']['notifiers']['service.email'] as String)['from']).isEqualTo("argocd@example.org") assertThat(clusterRessourcesYaml['metadata']['annotations']['notifications.argoproj.io/subscribe.email']).isEqualTo('infra@example.org') @@ -361,10 +360,8 @@ class ArgoCDTest { def argocd = createArgoCD() argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo - this.actualHelmValuesFile = Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), - ArgoCD.HELM_VALUES_PATH - ) + repoLayout = argocd.repoLayout() + this.actualHelmValuesFile = "${repoLayout.helmDir()}/values.yaml" def serviceEmail = new YamlSlurper().parseText( parseActualYaml(actualHelmValuesFile)['argo-cd']['notifications']['notifiers']['service.email'] as String) @@ -412,10 +409,9 @@ class ArgoCDTest { def argocd = createArgoCD() argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo - this.actualHelmValuesFile = Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), - ArgoCD.HELM_VALUES_PATH - ) + + repoLayout = argocd.repoLayout() + this.actualHelmValuesFile = "${repoLayout.helmDir()}/values.yaml" def serviceEmail = new YamlSlurper().parseText( parseActualYaml(actualHelmValuesFile)['argo-cd']['notifications']['notifiers']['service.email'] as String) @@ -431,13 +427,11 @@ class ArgoCDTest { @Test void 'When external Mailserver is NOT set'() { config.features.mail.active = true + def argocd = createArgoCD() argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo - this.actualHelmValuesFile = Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), - ArgoCD.HELM_VALUES_PATH - ) - + repoLayout = argocd.repoLayout() + this.actualHelmValuesFile = "${repoLayout.helmDir()}/values.yaml" def valuesYaml = parseActualYaml(actualHelmValuesFile) assertThat(new YamlSlurper().parseText(valuesYaml['argo-cd']['notifications']['notifiers']['service.email'] as String)['host']) doesNotHaveToString('mailhog.*monitoring.svc.cluster.local') @@ -449,11 +443,12 @@ class ArgoCDTest { @Test void 'When vault disabled: Does not push path "secrets" to cluster resources'() { config.features.secrets.active = false + def argocd = createArgoCD() argocd.install() - this.clusterResourcesRepo = (argocd as ArgoCDForTest).clusterResourcesRepo + repoLayout = argocd.repoLayout() - assertThat(new File(clusterResourcesRepo.getAbsoluteLocalRepoTmpDir() + "/misc/secrets")).doesNotExist() + assertThat(new File(repoLayout.vaultDir())).doesNotExist() } @Test @@ -463,10 +458,11 @@ class ArgoCDTest { def argocd = createArgoCD() argocd.install() + repoLayout = argocd.repoLayout() + this.actualHelmValuesFile = "${repoLayout.helmDir()}/values.yaml" - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo + def clusterRessourcesYaml = new YamlSlurper().parse(Path.of repoLayout.projectsDir(), "cluster-resources.yaml") - def clusterRessourcesYaml = new YamlSlurper().parse(Path.of argocdRepo.getAbsoluteLocalRepoTmpDir(), 'projects/cluster-resources.yaml') assertThat(clusterRessourcesYaml['spec']['sourceRepos'] as List).contains( 'http://scmm.scm-manager.svc.cluster.local/scm/repo/3rd-party-dependencies/kube-prometheus-stack') assertThat(clusterRessourcesYaml['spec']['sourceRepos'] as List).doesNotContain( @@ -498,40 +494,15 @@ class ArgoCDTest { k8sCommands.assertExecuted("kubectl apply -f https://raw.githubusercontent.com/prometheus-community/helm-charts/kube-prometheus-stack-42.0.3/charts/kube-prometheus-stack/charts/crds/crds/crd-servicemonitors.yaml") } - @Test - void 'For internal SCMM: Use service address in gitops repos'() { - def argocd = createArgoCD() - argocd.install() - this.clusterResourcesRepo = (argocd as ArgoCDForTest).clusterResourcesRepo - - List filesWithInternalSCMM = findFilesContaining(new File(clusterResourcesRepo.getAbsoluteLocalRepoTmpDir()), argocd.scmmUrlInternal) - assertThat(filesWithInternalSCMM).isNotEmpty() - } - - @Test - void 'For external SCMM: Use external address in gitops repos'() { - config.scm.internal = false - config.scm.scmManager.url = "https://abc" - def argocd = createArgoCD() - argocd.install() - - this.clusterResourcesRepo = (argocd as ArgoCDForTest).clusterResourcesRepo - - List filesWithInternalSCMM = findFilesContaining(new File(clusterResourcesRepo.getAbsoluteLocalRepoTmpDir()), argocd.scmmUrlInternal) - assertThat(filesWithInternalSCMM).isEmpty() - - List filesWithExternalSCMM = findFilesContaining(new File(clusterResourcesRepo.getAbsoluteLocalRepoTmpDir()), "https://abc") - assertThat(filesWithExternalSCMM).isNotEmpty() - } - @Test void 'Pushes repos with empty name-prefix'() { def argocd = createArgoCD() argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo this.clusterResourcesRepo = (argocd as ArgoCDForTest).clusterResourcesRepo + repoLayout = argocd.repoLayout() + - assertArgoCdYamlPrefixes(argocd.scmmUrlInternal, '') + assertArgoCdYamlPrefixes(clusterResourcesRepo.gitProvider.url, '', repoLayout) } @Test @@ -548,12 +519,10 @@ class ArgoCDTest { def argocd = createArgoCD() argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo this.clusterResourcesRepo = (argocd as ArgoCDForTest).clusterResourcesRepo + repoLayout = argocd.repoLayout() - - assertArgoCdYamlPrefixes(argocd.scmmUrlInternal, 'abc-') - + assertArgoCdYamlPrefixes(clusterResourcesRepo.gitProvider.url, config.application.namePrefix, repoLayout) } @Test @@ -579,10 +548,8 @@ class ArgoCDTest { def argocd = createArgoCD() argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo - this.actualHelmValuesFile = Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), - ArgoCD.HELM_VALUES_PATH - ) + repoLayout = argocd.repoLayout() + this.actualHelmValuesFile = "${repoLayout.helmDir()}/values.yaml" assertThat(parseActualYaml(actualHelmValuesFile)['argo-cd']['crds']['install']).isEqualTo(false) } @@ -590,7 +557,6 @@ class ArgoCDTest { @Test void 'disables serviceMonitor, when monitoring not active'() { config.application.skipCrds = true - createArgoCD().createMonitoringCrd() k8sCommands.assertNotExecuted('kubectl apply -f https://raw.githubusercontent.com/prometheus-community/helm-charts/') @@ -614,54 +580,18 @@ class ArgoCDTest { def argocd = createArgoCD() argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo - this.actualHelmValuesFile = Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), - ArgoCD.HELM_VALUES_PATH - ) + repoLayout = argocd.repoLayout() + this.actualHelmValuesFile = "${repoLayout.helmDir()}/values.yaml" assertThat(parseActualYaml(actualHelmValuesFile)['argo-cd']['global']['networkPolicy']['create']).isEqualTo(true) - assertThat(new File(argocdRepo.getAbsoluteLocalRepoTmpDir(), '/argocd/values.yaml').text.contains("namespace: monitoring")) - assertThat(new File(argocdRepo.getAbsoluteLocalRepoTmpDir(), '/argocd/templates/allow-namespaces.yaml').text.contains("namespace: monitoring")) - assertThat(new File(argocdRepo.getAbsoluteLocalRepoTmpDir(), '/argocd/templates/allow-namespaces.yaml').text.contains("namespace: default")) - } - - private static Map parseBuildImagesMapFromString(String text) { - def startIndex = text.indexOf('buildImages') - if (startIndex != -1) { - def bracketCount = 0 - def inBrackets = false - def endIndex = startIndex - - for (i in startIndex..text.length() - 1) { - if (text[i] == '[') { - bracketCount++ - inBrackets = true - } else if (text[i] == ']') { - bracketCount-- - } - - if (inBrackets && bracketCount == 0) { - endIndex = i + 1 - break - } - } - - def matchedText = text.substring(startIndex + 'buildImages'.length(), endIndex).trim().replaceFirst(":", "") - - Binding binding = new Binding() - binding.setVariable('dockerRegistryProxyCredentials', 'dockerRegistryProxyCredentials') - def map = new GroovyShell(binding).evaluate(matchedText) - - return map as Map - - } else { - return [:] - } + assertThat(new File(repoLayout.argocdRoot(), '/argocd/values.yaml').text.contains("namespace: monitoring")) + assertThat(new File(repoLayout.argocdRoot(), '/argocd/templates/allow-namespaces.yaml').text.contains("namespace: monitoring")) + assertThat(new File(repoLayout.argocdRoot(), '/argocd/templates/allow-namespaces.yaml').text.contains("namespace: default")) } - private void assertArgoCdYamlPrefixes(String scmmUrl, String expectedPrefix) { + private void assertArgoCdYamlPrefixes(String scmmUrl, String expectedPrefix, ArgoCDRepoLayout repoLayout) { - assertAllYamlFiles(new File(argocdRepo.getAbsoluteLocalRepoTmpDir()), 'projects', 3) { Path file -> + assertAllYamlFiles(new File(repoLayout.argocdRoot()), 'projects', 3) { Path file -> def yaml = parseActualYaml(file.toString()) List sourceRepos = yaml['spec']['sourceRepos'] as List // Some projects might not have sourceRepos @@ -694,7 +624,7 @@ class ArgoCDTest { } } - assertAllYamlFiles(new File(argocdRepo.getAbsoluteLocalRepoTmpDir()), 'applications', 4) { Path file -> + assertAllYamlFiles(new File(repoLayout.argocdRoot()), 'applications', 3) { Path file -> def yaml = parseActualYaml(file.toString()) assertThat(yaml['spec']['source']['repoURL'] as String) .as("$file repoURL have name prefix") @@ -709,34 +639,12 @@ class ArgoCDTest { .isEqualTo("${expectedPrefix}argocd".toString()) } - assertAllYamlFiles(new File(clusterResourcesRepo.getAbsoluteLocalRepoTmpDir()), 'argocd', 1) { Path it -> - def yaml = parseActualYaml(it.toString()) + assertAllYamlFiles(new File(repoLayout.rootDir()), 'apps', 7, + [ '/apps/argocd/' ]) { Path it -> - assertThat(yaml['spec']['source']['repoURL'] as String) - .as("$it repoURL has name prefix") - .startsWith("${scmmUrl}/repo/${expectedPrefix}argocd") - - - def metadataNamespace = yaml['metadata']['namespace'] as String - if (metadataNamespace) { - assertThat(metadataNamespace) - .as("$it metadata.namespace has name prefix") - .startsWith("${expectedPrefix}") - } - - def destinationNamespace = yaml['spec']['destination']['namespace'] - if (destinationNamespace) { - assertThat(destinationNamespace as String) - .as("$it spec.destination.namespace has name prefix") - .startsWith("${expectedPrefix}") - } - } - - assertAllYamlFiles(new File(clusterResourcesRepo.getAbsoluteLocalRepoTmpDir()), 'misc', 9) { Path it -> def yaml = parseActualYaml(it.toString()) List yamlDocuments = yaml instanceof List ? yaml : [yaml] for (def document in yamlDocuments) { - // Check all YAMLs objects for proper namespace, but namespaces because they dont have namespace attributes if (document && document['kind'] != 'Namespace') { def metadataNamespace = document['metadata']['namespace'] as String assertThat(metadataNamespace) @@ -747,15 +655,32 @@ class ArgoCDTest { } } - private static void assertAllYamlFiles(File rootDir, String childDir, Integer numberOfFiles, Closure cl) { - def nFiles = Files.walk(Path.of(rootDir.absolutePath, childDir)) - .filter { it.toString() ==~ /.*\.yaml/ } + private static void assertAllYamlFiles( + File rootDir, + String childDir, + Integer numberOfFiles, + List excludeContains = [], + Closure cl + ) { + def rootPath = Path.of(rootDir.absolutePath, childDir) + + def yamlFiles = Files.walk(rootPath) + .filter { Files.isRegularFile(it) } + .filter { Path p -> + def s = p.toString().replace('\\', '/') + (s.endsWith('.yaml') || s.endsWith('.yml')) && + !excludeContains.any { ex -> s.contains(ex) } + } .collect(Collectors.toList()) - .each(cl) - .size() - assertThat(nFiles).isEqualTo(numberOfFiles) + + yamlFiles.each(cl) + + assertThat(yamlFiles.size()).isEqualTo(numberOfFiles) } + + + private static List findFilesContaining(File folder, String stringToSearch) { List result = [] folder.eachFileRecurse(FileType.FILES) { @@ -803,10 +728,10 @@ class ArgoCDTest { def argocd = setupOperatorTest() argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo + repoLayout = argocd.repoLayout() - def argocdConfigPath = Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), ArgoCD.OPERATOR_CONFIG_PATH) - def rbacConfigPath = Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), ArgoCD.OPERATOR_RBAC_PATH) + def argocdConfigPath = Path.of(repoLayout.operatorConfigFile()) + def rbacConfigPath = Path.of(repoLayout.operatorRbacDir()) assertThat(argocdConfigPath.toFile()).exists() assertThat(rbacConfigPath.toFile()).exists() @@ -819,11 +744,12 @@ class ArgoCDTest { @Test void 'No files for operator when operator is false'() { def argocd = createArgoCD() + argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo + repoLayout = argocd.repoLayout() - def argocdConfigPath = Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), ArgoCD.OPERATOR_CONFIG_PATH) - def rbacConfigPath = Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), ArgoCD.OPERATOR_RBAC_PATH) + def argocdConfigPath = Path.of(repoLayout.operatorConfigFile()) + def rbacConfigPath = Path.of(repoLayout.operatorRbacDir()) assertThat(argocdConfigPath.toFile()).doesNotExist() assertThat(rbacConfigPath.toFile()).doesNotExist() @@ -832,20 +758,20 @@ class ArgoCDTest { @Test void 'Deploys with operator without OpenShift configuration'() { def argocd = setupOperatorTest(openshift: false) - argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo + argocd.install() + repoLayout = argocd.repoLayout() + def argocdConfigPath = Path.of(repoLayout.operatorConfigFile()) - def argocdConfigPath = Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), ArgoCD.OPERATOR_CONFIG_PATH) k8sCommands.assertExecuted("kubectl apply -f ${argocdConfigPath}") def yaml = parseActualYaml(argocdConfigPath.toFile().toString()) assertThat(yaml['spec']['rbac']).isNull() assertThat(yaml['spec']['sso']).isNull() - def argocdYaml = new YamlSlurper().parse(Path.of argocdRepo.getAbsoluteLocalRepoTmpDir(), 'applications/argocd.yaml') + def argocdYaml = new YamlSlurper().parse(Path.of repoLayout.applicationsDir(), 'argocd.yaml') assertThat(argocdYaml['spec']['source']['directory']['recurse'] as Boolean).isTrue() - assertThat(argocdYaml['spec']['source']['path']).isEqualTo('operator/') + assertThat(argocdYaml['spec']['source']['path']).isEqualTo('apps/argocd/operator/') // Here we should assert all <#if argocd.isOperator> in YAML 😐️ } @@ -871,10 +797,9 @@ class ArgoCDTest { def argocd = setupOperatorTest(openshift: false) argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo - - File rbacPath = Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), ArgoCD.OPERATOR_RBAC_PATH).toFile() + repoLayout = argocd.repoLayout() + File rbacPath = Path.of(repoLayout.operatorRbacDir()).toFile() expectedNamespaces.each { String ns -> File roleFile = new File(rbacPath, "role-argocd-${ns}.yaml") @@ -917,9 +842,9 @@ class ArgoCDTest { def argocd = setupOperatorTest(openshift: true) argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo + repoLayout = argocd.repoLayout() - def argocdConfigPath = Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), ArgoCD.OPERATOR_CONFIG_PATH) + def argocdConfigPath = Path.of(repoLayout.operatorConfigFile()) k8sCommands.assertExecuted("kubectl apply -f ${argocdConfigPath}") def yaml = parseActualYaml(argocdConfigPath.toFile().toString()) @@ -940,9 +865,9 @@ class ArgoCDTest { config.features.argocd.resourceInclusionsCluster = 'https://192.168.0.1:6443' argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo + repoLayout = argocd.repoLayout() - def argocdConfigPath = Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), ArgoCD.OPERATOR_CONFIG_PATH) + def argocdConfigPath = Path.of(repoLayout.operatorConfigFile()) def yaml = parseActualYaml(argocdConfigPath.toFile().toString()) def expectedClusterUrl = 'https://192.168.0.1:6443' @@ -972,11 +897,10 @@ class ArgoCDTest { argocd.install() } - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo + repoLayout = argocd.repoLayout() - def argocdConfigPath = Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), ArgoCD.OPERATOR_CONFIG_PATH) + def argocdConfigPath = Path.of(repoLayout.operatorConfigFile()) def yaml = parseActualYaml(argocdConfigPath.toFile().toString()) - def expectedClusterUrlFromConfig = "https://192.168.0.1:6443" // Retrieve and parse the resourceInclusions string into structured YAML @@ -1003,9 +927,9 @@ class ArgoCDTest { ] as List argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo + repoLayout = argocd.repoLayout() - def argocdConfigPath = Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), ArgoCD.OPERATOR_CONFIG_PATH) + def argocdConfigPath = Path.of(repoLayout.operatorConfigFile()) def yaml = parseActualYaml(argocdConfigPath.toFile().toString()) def expectedEnv = [ @@ -1029,9 +953,9 @@ class ArgoCDTest { config.features.argocd.env = [] argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo + repoLayout = argocd.repoLayout() - def argocdConfigPath = Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), ArgoCD.OPERATOR_CONFIG_PATH) + def argocdConfigPath = Path.of(repoLayout.operatorConfigFile()) def yaml = parseActualYaml(argocdConfigPath.toFile().toString()) // Check that the env variables are not present @@ -1053,9 +977,9 @@ class ArgoCDTest { ] as List argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo + repoLayout = argocd.repoLayout() - def argocdConfigPath = Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), ArgoCD.OPERATOR_CONFIG_PATH) + def argocdConfigPath = Path.of(repoLayout.operatorConfigFile()) def yaml = parseActualYaml(argocdConfigPath.toFile().toString()) def expectedEnv = [ @@ -1073,7 +997,6 @@ class ArgoCDTest { void 'Creates all necessary namespaces'() { def argoCD = createArgoCD() simulateNamespaceCreation() - argoCD.install() config.application.namespaces.getActiveNamespaces().each { namespace -> @@ -1085,22 +1008,20 @@ class ArgoCDTest { void 'Operator config sets server insecure to true when insecure is set'() { config.application.insecure = true def argocd = setupOperatorTest() - argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo + repoLayout = argocd.repoLayout() - def yaml = parseActualYaml(Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), ArgoCD.OPERATOR_CONFIG_PATH).toString()) + def yaml = parseActualYaml(Path.of(repoLayout.operatorConfigFile()).toString()) assertThat(yaml['spec']['server']['insecure']).isEqualTo(true) } @Test void 'Operator config sets server_insecure to false when insecure is not set'() { def argocd = setupOperatorTest() - argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo + repoLayout = argocd.repoLayout() - def yaml = parseActualYaml(Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), ArgoCD.OPERATOR_CONFIG_PATH).toString()) + def yaml = parseActualYaml(Path.of(repoLayout.operatorConfigFile()).toString()) assertThat(yaml['spec']['server']['insecure']).isEqualTo(false) } @@ -1109,11 +1030,10 @@ class ArgoCDTest { config.application.insecure = true config.features.argocd.url = "http://argocd.localhost" def argocd = setupOperatorTest(openshift: false) - argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo + repoLayout = argocd.repoLayout() - def ingressFile = new File(argocdRepo.getAbsoluteLocalRepoTmpDir(), "operator/ingress.yaml") + def ingressFile = new File(repoLayout.operatorDir(), "ingress.yaml") assertThat(ingressFile) .as("Ingress file should be generated for insecure mode on non-OpenShift") .exists() @@ -1132,9 +1052,9 @@ class ArgoCDTest { config.application.insecure = false def argocd = setupOperatorTest(openshift: false) argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo + repoLayout = argocd.repoLayout() - def ingressFile = new File(argocdRepo.getAbsoluteLocalRepoTmpDir(), "operator/ingress.yaml") + def ingressFile = new File(repoLayout.operatorDir(), "ingress.yaml") assertThat(ingressFile) .as("Ingress file should not be generated when insecure is false") .doesNotExist() @@ -1144,11 +1064,10 @@ class ArgoCDTest { void 'Does not generate ingress yaml when running on OpenShift'() { config.application.insecure = true def argocd = setupOperatorTest(openshift: true) - argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo + repoLayout = argocd.repoLayout() - def ingressFile = new File(argocdRepo.getAbsoluteLocalRepoTmpDir(), "operator/ingress.yaml") + def ingressFile = new File(repoLayout.operatorDir(), "ingress.yaml") assertThat(ingressFile) .as("Ingress file should not be generated on OpenShift") .doesNotExist() @@ -1159,10 +1078,9 @@ class ArgoCDTest { config.application.insecure = false def argocd = setupOperatorTest(openshift: true) argocd.install() + repoLayout = argocd.repoLayout() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo - - def ingressFile = new File(argocdRepo.getAbsoluteLocalRepoTmpDir(), "operator/ingress.yaml") + def ingressFile = new File(repoLayout.operatorDir(), "ingress.yaml") assertThat(ingressFile) .as("Ingress file should not be generated when both flags are false") .doesNotExist() @@ -1171,8 +1089,8 @@ class ArgoCDTest { @Test void 'Central Bootstrapping for Tenant Applications'() { setupDedicatedInstanceMode() -// this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo - def ingressFile = new File(argocdRepo.getAbsoluteLocalRepoTmpDir(), "operator/ingress.yaml") + + def ingressFile = new File(repoLayout.operatorDir(), "ingress.yaml") assertThat(ingressFile) .as("Ingress file should not be generated when both flags are false") .doesNotExist() @@ -1182,54 +1100,38 @@ class ArgoCDTest { void 'GOP DedicatedInstances Central templating works correctly'() { setupDedicatedInstanceMode() //Central Applications - assertThat(new File(argocdRepo.getAbsoluteLocalRepoTmpDir() + "${prefixPathCentral}applications/argocd.yaml")).exists() - assertThat(new File(argocdRepo.getAbsoluteLocalRepoTmpDir() + "${prefixPathCentral}applications/bootstrap.yaml")).exists() - assertThat(new File(argocdRepo.getAbsoluteLocalRepoTmpDir() + "${prefixPathCentral}applications/projects.yaml")).exists() - assertThat(new File(argocdRepo.getAbsoluteLocalRepoTmpDir() + "${prefixPathCentral}applications/example-apps.yaml")).doesNotExist() + assertThat(new File(repoLayout.argocdRoot() + "${prefixPathCentral}applications/argocd.yaml")).exists() + assertThat(new File(repoLayout.argocdRoot() + "${prefixPathCentral}applications/bootstrap.yaml")).exists() + assertThat(new File(repoLayout.argocdRoot() + "${prefixPathCentral}applications/projects.yaml")).exists() + assertThat(new File(repoLayout.argocdRoot() + "${prefixPathCentral}applications/example-apps.yaml")).doesNotExist() - def argocdYaml = new YamlSlurper().parse(Path.of argocdRepo.getAbsoluteLocalRepoTmpDir(), "${prefixPathCentral}applications/argocd.yaml") - def bootstrapYaml = new YamlSlurper().parse(Path.of argocdRepo.getAbsoluteLocalRepoTmpDir(), "${prefixPathCentral}applications/bootstrap.yaml") - def clusterResourcesYaml = new YamlSlurper().parse(Path.of argocdRepo.getAbsoluteLocalRepoTmpDir(), "${prefixPathCentral}applications/cluster-resources.yaml") - def projectsYaml = new YamlSlurper().parse(Path.of argocdRepo.getAbsoluteLocalRepoTmpDir(), "${prefixPathCentral}applications/projects.yaml") + def argocdYaml = new YamlSlurper().parse(Path.of repoLayout.argocdRoot(), "${prefixPathCentral}applications/argocd.yaml") + def bootstrapYaml = new YamlSlurper().parse(Path.of repoLayout.argocdRoot(), "${prefixPathCentral}applications/bootstrap.yaml") + def projectsYaml = new YamlSlurper().parse(Path.of repoLayout.argocdRoot(), "${prefixPathCentral}applications/projects.yaml") assertThat(argocdYaml['metadata']['name']).isEqualTo('testPrefix-argocd') assertThat(argocdYaml['metadata']['namespace']).isEqualTo('argocd') assertThat(argocdYaml['spec']['project']).isEqualTo('testPrefix') - assertThat(argocdYaml['spec']['source']['path']).isEqualTo('operator/') + assertThat(argocdYaml['spec']['source']['path']).isEqualTo('apps/argocd/operator/') assertThat(bootstrapYaml['metadata']['name']).isEqualTo('testPrefix-bootstrap') assertThat(bootstrapYaml['metadata']['namespace']).isEqualTo('argocd') assertThat(bootstrapYaml['spec']['project']).isEqualTo('testPrefix') - assertThat(bootstrapYaml['spec']['source']['repoURL']).isEqualTo("scmm.testhost/scm/repo/testPrefix-argocd/argocd.git") - - assertThat(clusterResourcesYaml['metadata']['name']).isEqualTo('testPrefix-cluster-resources') - assertThat(clusterResourcesYaml['metadata']['namespace']).isEqualTo('argocd') - assertThat(clusterResourcesYaml['spec']['project']).isEqualTo('testPrefix') + assertThat(bootstrapYaml['spec']['source']['repoURL']).isEqualTo("scmm.testhost/scm/repo/testPrefix-argocd/cluster-resources.git") assertThat(projectsYaml['metadata']['name']).isEqualTo('testPrefix-projects') assertThat(projectsYaml['metadata']['namespace']).isEqualTo('argocd') assertThat(projectsYaml['spec']['project']).isEqualTo('testPrefix') //Central Project - assertThat(new File(argocdRepo.getAbsoluteLocalRepoTmpDir() + "${prefixPathCentral}projects/tenant.yaml")).exists() + assertThat(new File(repoLayout.argocdRoot() + "${prefixPathCentral}projects/tenant.yaml")).exists() - def tenantProject = new YamlSlurper().parse(Path.of argocdRepo.getAbsoluteLocalRepoTmpDir(), "${prefixPathCentral}projects/tenant.yaml") + def tenantProject = new YamlSlurper().parse(Path.of repoLayout.argocdRoot(), "${prefixPathCentral}projects/tenant.yaml") assertThat(tenantProject['metadata']['name']).isEqualTo('testPrefix') assertThat(tenantProject['metadata']['namespace']).isEqualTo('argocd') def sourceRepos = (List) tenantProject['spec']['sourceRepos'] - assertThat(sourceRepos[0]).isEqualTo('scmm.testhost/scm/repo/testPrefix-argocd/argocd.git') - assertThat(sourceRepos[1]).isEqualTo('scmm.testhost/scm/repo/testPrefix-argocd/cluster-resources.git') - } - - @Test - void 'Cluster Resource Misc templating'() { - setupDedicatedInstanceMode() - this.clusterResourcesRepo = (argocd as ArgoCDForTest).clusterResourcesRepo - assertThat(new File(clusterResourcesRepo.getAbsoluteLocalRepoTmpDir() + "/argocd/misc.yaml")).exists() - def miscYaml = new YamlSlurper().parse(Path.of clusterResourcesRepo.getAbsoluteLocalRepoTmpDir(), "/argocd/misc.yaml") - assertThat(miscYaml['metadata']['name']).isEqualTo('testPrefix-misc') - assertThat(miscYaml['metadata']['namespace']).isEqualTo('argocd') + assertThat(sourceRepos[0]).isEqualTo('scmm.testhost/scm/repo/testPrefix-argocd/cluster-resources.git') } @Test @@ -1247,10 +1149,11 @@ class ArgoCDTest { def argocd = createArgoCD() argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo - assertThat(Path.of(this.argocdRepo.getAbsoluteLocalRepoTmpDir(), 'multiTenant/')).doesNotExist() - assertThat(Path.of(this.argocdRepo.getAbsoluteLocalRepoTmpDir(), 'applications/')).exists() - assertThat(Path.of(this.argocdRepo.getAbsoluteLocalRepoTmpDir(), 'projects/')).exists() + repoLayout = argocd.repoLayout() + + assertThat(Path.of(repoLayout.argocdRoot(), 'multiTenant/')).doesNotExist() + assertThat(Path.of(repoLayout.argocdRoot(), 'applications/')).exists() + assertThat(Path.of(repoLayout.argocdRoot(), 'projects/')).exists() } @Test @@ -1259,10 +1162,11 @@ class ArgoCDTest { def argocd = createArgoCD() argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo - assertThat(Path.of(this.argocdRepo.getAbsoluteLocalRepoTmpDir(), 'multiTenant/')).exists() - assertThat(Path.of(this.argocdRepo.getAbsoluteLocalRepoTmpDir(), 'applications/')).doesNotExist() - assertThat(Path.of(this.argocdRepo.getAbsoluteLocalRepoTmpDir(), 'projects/')).doesNotExist() + repoLayout = argocd.repoLayout() + + assertThat(Path.of(repoLayout.argocdRoot(), 'multiTenant/')).exists() + assertThat(Path.of(repoLayout.argocdRoot(), 'applications/')).doesNotExist() + assertThat(Path.of(repoLayout.argocdRoot(), 'projects/')).doesNotExist() } @Test @@ -1270,8 +1174,8 @@ class ArgoCDTest { config.application.namespaces.tenantNamespaces = new LinkedHashSet(['testprefix-tenant-test1', 'testprefix-tenant-test2', 'testprefix-tenant-test3']) setupDedicatedInstanceMode() - File rbacFolder = new File(argocdRepo.getAbsoluteLocalRepoTmpDir() + "/operator/rbac") - File rbacTenantFolder = new File(argocdRepo.getAbsoluteLocalRepoTmpDir() + "/operator/rbac/tenant") + File rbacFolder = new File(repoLayout.operatorRbacDir()) + File rbacTenantFolder = new File(repoLayout.operatorRbacDir() + "/tenant") assertThat(rbacFolder).exists() assertThat(rbacTenantFolder).exists() @@ -1309,11 +1213,11 @@ class ArgoCDTest { def argocd = setupOperatorTest(openshift: false) argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo + repoLayout = argocd.repoLayout() print config.toMap() - File rbacDir = Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), ArgoCD.OPERATOR_RBAC_PATH).toFile() + File rbacDir = Path.of(repoLayout.operatorRbacDir()).toFile() File roleFile = new File(rbacDir, "role-argocd-testprefix-monitoring.yaml") Map yaml = new YamlSlurper().parse(roleFile) as Map @@ -1331,9 +1235,9 @@ class ArgoCDTest { def argocd = setupOperatorTest(openshift: true) argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo + repoLayout = argocd.repoLayout() - File rbacDir = Path.of(argocdRepo.getAbsoluteLocalRepoTmpDir(), ArgoCD.OPERATOR_RBAC_PATH).toFile() + File rbacDir = Path.of(repoLayout.operatorRbacDir()).toFile() File roleFile = new File(rbacDir, "role-argocd-testprefix-monitoring.yaml") println roleFile @@ -1352,12 +1256,9 @@ class ArgoCDTest { def argocd = createArgoCD() argocd.install() + repoLayout = argocd.repoLayout() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo - this.clusterResourcesRepo = (argocd as ArgoCDForTest).clusterResourcesRepo - - - def clusterRessourcesYaml = new YamlSlurper().parse(Path.of argocdRepo.getAbsoluteLocalRepoTmpDir(), 'projects/cluster-resources.yaml') + def clusterRessourcesYaml = new YamlSlurper().parse(Path.of repoLayout.projectsDir(), '/cluster-resources.yaml') clusterRessourcesYaml['spec']['sourceRepos'] assertThat(clusterRessourcesYaml['spec']['sourceRepos'] as List).contains( @@ -1394,10 +1295,9 @@ class ArgoCDTest { def argocd = createArgoCD() argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo - this.clusterResourcesRepo = (argocd as ArgoCDForTest).clusterResourcesRepo + repoLayout = argocd.repoLayout() - def clusterRessourcesYaml = new YamlSlurper().parse(Path.of argocdRepo.getAbsoluteLocalRepoTmpDir(), 'projects/cluster-resources.yaml') + def clusterRessourcesYaml = new YamlSlurper().parse(Path.of repoLayout.projectsDir(), '/cluster-resources.yaml') clusterRessourcesYaml['spec']['sourceRepos'] assertThat(clusterRessourcesYaml['spec']['sourceRepos'] as List).contains( @@ -1426,9 +1326,9 @@ class ArgoCDTest { config.scm.gitlab.url = 'https://testGitLab.com/testgroup' def argocd = createArgoCD() argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo + repoLayout = argocd.repoLayout() - def clusterRessourcesYaml = new YamlSlurper().parse(Path.of argocdRepo.getAbsoluteLocalRepoTmpDir(), 'projects/cluster-resources.yaml') + def clusterRessourcesYaml = new YamlSlurper().parse(Path.of repoLayout.projectsDir(), '/cluster-resources.yaml') clusterRessourcesYaml['spec']['sourceRepos'] assertThat(clusterRessourcesYaml['spec']['sourceRepos'] as List).contains( @@ -1450,9 +1350,9 @@ class ArgoCDTest { def argocd = createArgoCD() argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo + repoLayout = argocd.repoLayout() - def clusterRessourcesYaml = new YamlSlurper().parse(Path.of argocdRepo.getAbsoluteLocalRepoTmpDir(), 'projects/cluster-resources.yaml') + def clusterRessourcesYaml = new YamlSlurper().parse(Path.of repoLayout.projectsDir(), '/cluster-resources.yaml') clusterRessourcesYaml['spec']['sourceRepos'] assertThat(clusterRessourcesYaml['spec']['sourceRepos'] as List).contains( @@ -1481,9 +1381,9 @@ class ArgoCDTest { def argocd = createArgoCD() argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo + repoLayout = argocd.repoLayout() - def clusterRessourcesYaml = new YamlSlurper().parse(Path.of argocdRepo.getAbsoluteLocalRepoTmpDir(), 'projects/cluster-resources.yaml') + def clusterRessourcesYaml = new YamlSlurper().parse(Path.of repoLayout.projectsDir(), '/cluster-resources.yaml') clusterRessourcesYaml['spec']['sourceRepos'] @@ -1514,8 +1414,8 @@ class ArgoCDTest { config.multiTenant.useDedicatedInstance = true this.argocd = setupOperatorTest() argocd.install() - this.argocdRepo = (argocd as ArgoCDForTest).argocdRepo this.clusterResourcesRepo = (argocd as ArgoCDForTest).clusterResourcesRepo + repoLayout = argocd.repoLayout() } @@ -1613,23 +1513,22 @@ class ArgoCDTest { static class ArgoCDForTest extends ArgoCD { final Config cfg - GitProvider tenantMock + final GitProvider tenantProvider + final GitProvider centralProvider - // **Factory** static ArgoCDForTest newWithAutoProviders(Config cfg, CommandExecutorForTest k8sCommands, CommandExecutorForTest helmCommands) { - def prov = TestGitProvider.buildProviders(cfg) return new ArgoCDForTest( cfg, k8sCommands, helmCommands, prov.tenant as GitProvider, - prov.central as GitProvider) + prov.central as GitProvider + ) } - // ---- Only keep the real constructor ---- ArgoCDForTest(Config cfg, CommandExecutorForTest k8sCommands, CommandExecutorForTest helmCommands, @@ -1644,32 +1543,37 @@ class ArgoCDTest { new GitHandlerForTests(cfg, tenantProvider, centralProvider) ) this.cfg = cfg - this.tenantMock = tenantProvider + this.tenantProvider = tenantProvider + this.centralProvider = centralProvider mockPrefixActiveNamespaces(cfg) } - GitRepo getArgocdRepo() { - return this.argocdRepoInitializationAction?.repo - } - GitRepo getClusterResourcesRepo() { return this.clusterResourcesInitializationAction?.repo } - @Override - protected initCentralRepos() { - super.initCentralRepos() + GitRepo getTenantBootstrapRepo() { + return this.tenantBootstrapInitializationAction?.repo } + ArgoCDRepoLayout getClusterRepoLayout() { + def root = getClusterResourcesRepo()?.getAbsoluteLocalRepoTmpDir() + return root ? new ArgoCDRepoLayout(root.toString()) : null + } - @Override - protected initTenantRepos() { - super.initTenantRepos() + ArgoCDRepoLayout getTenantRepoLayout() { + def root = getTenantBootstrapRepo()?.getAbsoluteLocalRepoTmpDir() + return root ? new ArgoCDRepoLayout(root.toString()) : null } + // Convenience: argocd-Unterordner im cluster-resources Repo + String getArgocdDirInClusterResources() { + return getClusterRepoLayout()?.argocdRoot() + } } + private Map parseActualYaml(String pathToYamlFile) { File yamlFile = new File(pathToYamlFile) def ys = new YamlSlurper() diff --git a/src/test/groovy/com/cloudogu/gitops/features/deployment/ArgoCdApplicationStrategyTest.groovy b/src/test/groovy/com/cloudogu/gitops/features/deployment/ArgoCdApplicationStrategyTest.groovy index 95c680322..b55bcc430 100644 --- a/src/test/groovy/com/cloudogu/gitops/features/deployment/ArgoCdApplicationStrategyTest.groovy +++ b/src/test/groovy/com/cloudogu/gitops/features/deployment/ArgoCdApplicationStrategyTest.groovy @@ -23,14 +23,10 @@ class ArgoCdApplicationStrategyTest { void 'deploys feature using argo CD'() { def strategy = createStrategy() File valuesYaml = File.createTempFile('values', 'yaml') - valuesYaml.text = """ -param1: value1 -param2: value2 -""" strategy.deployFeature("repoURL", "repoName", "chartName", "version", "foo-namespace", "releaseName", valuesYaml.toPath()) - def argoCdApplicationYaml = new File("$localTempDir/argocd/releaseName.yaml") + def argoCdApplicationYaml = new File("$localTempDir/apps/argocd/applications/releaseName.yaml") assertThat(argoCdApplicationYaml.text).isEqualTo("""--- apiVersion: "argoproj.io/v1alpha1" kind: "Application" @@ -48,10 +44,16 @@ spec: targetRevision: "version" helm: releaseName: "releaseName" - values: |2 - - param1: value1 - param2: value2 + valueFiles: + - "\$values/apps/repoName/misc/repoName-gop-helm.yaml" + - "\$values/apps/repoName/misc/repoName-user-values.yaml" + ignoreMissingValueFiles: true + - repoURL: "http://scmm.scm-manager.svc.cluster.local/scm/repo/argocd/cluster-resources.git" + targetRevision: "main" + ref: "values" + path: "apps/repoName/misc" + directory: + recurse: true syncPolicy: automated: prune: true @@ -69,7 +71,7 @@ spec: strategy.deployFeature("repoURL", "repoName", "chartName", "version", "namespace", "releaseName", valuesYaml.toPath(), DeploymentStrategy.RepoType.GIT) - def argoCdApplicationYaml = new File("$localTempDir/argocd/releaseName.yaml") + def argoCdApplicationYaml = new File("$localTempDir/apps/argocd/applications/releaseName.yaml") def result = new YamlSlurper().parse(argoCdApplicationYaml) def sources = result['spec']['sources'] as List assertThat(sources[0] as Map).containsKey('path') @@ -87,7 +89,7 @@ spec: strategy.deployFeature("repoURL", "repoName", "chartName", "version", "namespace", "releaseName", valuesYaml.toPath()) - def argoCdApplicationYaml = new File("$localTempDir/argocd/releaseName.yaml") + def argoCdApplicationYaml = new File("$localTempDir/apps/argocd/applications/releaseName.yaml") assertThat(argoCdApplicationYaml.text).contains("CreateNamespace=false") } @@ -102,7 +104,7 @@ spec: strategy.deployFeature("repoURL", "repoName", "chartName", "version", "namespace", "releaseName", valuesYaml.toPath()) - def argoCdApplicationYaml = new File("$localTempDir/argocd/releaseName.yaml") + def argoCdApplicationYaml = new File("$localTempDir/apps/argocd/applications/releaseName.yaml") assertThat(argoCdApplicationYaml.text).contains("CreateNamespace=true") } diff --git a/src/test/groovy/com/cloudogu/gitops/features/git/GitHandlerTest.groovy b/src/test/groovy/com/cloudogu/gitops/features/git/GitHandlerTest.groovy index 5d173ae8c..255c7269a 100644 --- a/src/test/groovy/com/cloudogu/gitops/features/git/GitHandlerTest.groovy +++ b/src/test/groovy/com/cloudogu/gitops/features/git/GitHandlerTest.groovy @@ -141,13 +141,12 @@ class GitHandlerTest { assertEquals('scm-manager', cfg.scm.scmManager.namespace) - assertTrue(tenant.createdRepos.contains('argocd/argocd')) assertTrue(tenant.createdRepos.contains('argocd/cluster-resources')) assertTrue(tenant.createdRepos.contains('3rd-party-dependencies/spring-boot-helm-chart')) assertTrue(tenant.createdRepos.contains('3rd-party-dependencies/spring-boot-helm-chart-with-dependency')) assertTrue(tenant.createdRepos.contains('3rd-party-dependencies/gitops-build-lib')) assertTrue(tenant.createdRepos.contains('3rd-party-dependencies/ces-build-lib')) - assertEquals(6, tenant.createdRepos.size()) + assertEquals(5, tenant.createdRepos.size()) // No central provider in tenant-only scenario assertNull(gitHandler.getCentral()) @@ -176,13 +175,11 @@ class GitHandlerTest { gitHandler.enable() // Central: argocd + cluster-resources = 2 - assertTrue(central.createdRepos.contains('fv40-argocd/argocd')) assertTrue(central.createdRepos.contains('fv40-argocd/cluster-resources')) - assertEquals(2, central.createdRepos.size()) + assertEquals(1, central.createdRepos.size()) // Tenant: only argocd + 4 dependencies = 5 (no cluster-resources) - assertTrue(tenant.createdRepos.contains('fv40-argocd/argocd')) - assertFalse(tenant.createdRepos.contains('fv40-argocd/cluster-resources')) + assertTrue(tenant.createdRepos.contains('fv40-argocd/cluster-resources')) assertTrue(tenant.createdRepos.contains('fv40-3rd-party-dependencies/spring-boot-helm-chart')) assertTrue(tenant.createdRepos.contains('fv40-3rd-party-dependencies/spring-boot-helm-chart-with-dependency')) assertTrue(tenant.createdRepos.contains('fv40-3rd-party-dependencies/gitops-build-lib')) @@ -214,13 +211,11 @@ class GitHandlerTest { gitHandler.enable() // Central: argocd + cluster-resources - assertTrue(central.createdRepos.contains('fv40-argocd/argocd')) assertTrue(central.createdRepos.contains('fv40-argocd/cluster-resources')) - assertEquals(2, central.createdRepos.size()) + assertEquals(1, central.createdRepos.size()) // Tenant: argocd only + 4 dependencies - assertTrue(tenant.createdRepos.contains('fv40-argocd/argocd')) - assertFalse(tenant.createdRepos.contains('fv40-argocd/cluster-resources')) + assertTrue(tenant.createdRepos.contains('fv40-argocd/cluster-resources')) assertTrue(tenant.createdRepos.contains('fv40-3rd-party-dependencies/spring-boot-helm-chart')) assertTrue(tenant.createdRepos.contains('fv40-3rd-party-dependencies/spring-boot-helm-chart-with-dependency')) assertTrue(tenant.createdRepos.contains('fv40-3rd-party-dependencies/gitops-build-lib')) diff --git a/src/test/groovy/com/cloudogu/gitops/git/providers/scmmanager/ScmManagerUrlResolverTest.groovy b/src/test/groovy/com/cloudogu/gitops/git/providers/scmmanager/ScmManagerUrlResolverTest.groovy index 75868c2a4..1282a129e 100644 --- a/src/test/groovy/com/cloudogu/gitops/git/providers/scmmanager/ScmManagerUrlResolverTest.groovy +++ b/src/test/groovy/com/cloudogu/gitops/git/providers/scmmanager/ScmManagerUrlResolverTest.groovy @@ -25,6 +25,7 @@ class ScmManagerUrlResolverTest { @Mock private NetworkingUtils net + @BeforeEach void setUp() { config = new Config( @@ -69,8 +70,8 @@ class ScmManagerUrlResolverTest { when(k8s.waitForNodePort("scmm", "scm-manager")).thenReturn("30080") when(net.findClusterBindAddress()).thenReturn("10.0.0.1") - var r = resolverWith() - assertEquals("http://10.0.0.1:30080/scm/api/", r.clientApiBase().toString()) + var urlResolver = resolverWith() + assertEquals("http://10.0.0.1:30080/scm/api/", urlResolver.clientApiBase().toString()) } // ---------- Repo base & URLs ---------- @@ -79,9 +80,9 @@ class ScmManagerUrlResolverTest { when(k8s.waitForNodePort("scmm", "scm-manager")).thenReturn("30080") when(net.findClusterBindAddress()).thenReturn("10.0.0.1") - var r = resolverWith() + var urlResolver = resolverWith() assertEquals("http://10.0.0.1:30080/scm/repo/ns/project", - r.clientRepoUrl(" ns/project ")) + urlResolver.clientRepoUrl(" ns/project ")) } // ---------- In-cluster base & URLs ---------- @@ -101,9 +102,9 @@ class ScmManagerUrlResolverTest { @Test void "inClusterRepoUrl(): builds full in-cluster repo URL without trailing slash"() { - var r = resolverWith() + var urlResolver = resolverWith() assertEquals("http://scmm.scm-manager.svc.cluster.local/scm/repo/admin/admin", - r.inClusterRepoUrl("admin/admin")) + urlResolver.inClusterRepoUrl("admin/admin")) } @Test diff --git a/src/test/groovy/com/cloudogu/gitops/utils/git/GitHandlerForTests.groovy b/src/test/groovy/com/cloudogu/gitops/utils/git/GitHandlerForTests.groovy index c61909176..e20869616 100644 --- a/src/test/groovy/com/cloudogu/gitops/utils/git/GitHandlerForTests.groovy +++ b/src/test/groovy/com/cloudogu/gitops/utils/git/GitHandlerForTests.groovy @@ -35,9 +35,9 @@ class GitHandlerForTests extends GitHandler { final String namePrefix = (config?.application?.namePrefix ?: "").trim() if (this.central) { setupRepos(this.central, namePrefix) - setupRepos(this.tenant, namePrefix, false) + setupRepos(this.tenant, namePrefix) } else { - setupRepos(this.tenant, namePrefix, true) + setupRepos(this.tenant, namePrefix) } create3thPartyDependencies(this.tenant, namePrefix)