Features 11017 and 11018: setup of mgmt cluster and git repo 10/14410/21
authorgarciadeblas <gerardo.garciadeblas@telefonica.com>
Tue, 21 May 2024 14:04:14 +0000 (16:04 +0200)
committergarciadeblas <gerardo.garciadeblas@telefonica.com>
Tue, 20 Aug 2024 21:23:27 +0000 (23:23 +0200)
This change incorporates the changes to setup a mgmt cluster for
cloud-native operations in OSM following a GitOps model, which includes
the setup of an internal git repository.

Change-Id: If828d18ad64d852a9a89ec9ba7c2d3a96d281565
Signed-off-by: garciadeblas <gerardo.garciadeblas@telefonica.com>
190 files changed:
installers/full_install_osm.sh
installers/helm/osm/templates/lcm/lcm-deployment.yaml
installers/helm/osm/values.yaml
installers/install_kubeadm_cluster.sh
installers/install_osm.sh
installers/mgmt-cluster/00-base-config.rc [new file with mode: 0644]
installers/mgmt-cluster/01-provision-aux-svc.sh [new file with mode: 0755]
installers/mgmt-cluster/02-provision-local-git-user.sh [new file with mode: 0755]
installers/mgmt-cluster/03-provision-mgmt-cluster.sh [new file with mode: 0755]
installers/mgmt-cluster/README.md [new file with mode: 0644]
installers/mgmt-cluster/flux/scripts/add-age-key-to-cluster.sh [new file with mode: 0755]
installers/mgmt-cluster/flux/scripts/clone-relevant-repos.sh [new file with mode: 0755]
installers/mgmt-cluster/flux/scripts/create-age-keypair.sh [new file with mode: 0755]
installers/mgmt-cluster/flux/scripts/create-new-cluster-folder-structure.sh [new file with mode: 0755]
installers/mgmt-cluster/flux/scripts/helper-functions.rc [new file with mode: 0644]
installers/mgmt-cluster/flux/scripts/library/functions.sh [new file with mode: 0755]
installers/mgmt-cluster/flux/scripts/library/trap.sh [new file with mode: 0755]
installers/mgmt-cluster/flux/scripts/mgmt-cluster-bootstrap.sh [new file with mode: 0755]
installers/mgmt-cluster/flux/scripts/watch-mgmt-cluster.sh [new file with mode: 0755]
installers/mgmt-cluster/flux/templates/fleet/clusters/_management/apps.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/fleet/clusters/_management/fleet-repo.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/fleet/clusters/_management/infra-configs.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/fleet/clusters/_management/infra-controllers.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/fleet/clusters/_management/kustomization.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/fleet/clusters/_management/managed-resources.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/fleet/clusters/_management/sw-catalogs-repo.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/apps/jenkins/manifests/bitnamicharts-repo.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/apps/jenkins/manifests/jenkins-hr.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/apps/jenkins/templates/jenkins-ks.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/apps/jenkins/templates/jenkins-ns.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/aks/manifests/aks.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/aks/templates/aks01.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/azure-mysql/manifests/dbformysql.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/azure-mysql/templates/azure-mysql01.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/eks/manifests/eks-cluster/eks-cluster.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/eks/manifests/eks-cluster/nodegroup.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/eks/manifests/iam/role-policy-attachment.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/eks/manifests/iam/roles.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/eks/manifests/network/gateways.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/eks/manifests/network/routes.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/eks/manifests/network/subnets.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/eks/manifests/network/vpc.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/eks/templates/eks01.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/bootstrap/manifests/namespaces/namespaces.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/bootstrap/manifests/secret/secret-template.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/bootstrap/templates/remote-cluster-bootstrap.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/apps.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/fleet-repo.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/flux-system/gotk-components.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/flux-system/gotk-sync.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/flux-system/kustomization.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/infra-configs.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/infra-controllers.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/kustomization.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/managed-resources.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/sw-catalogs-repo.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/empty-kustomization/manifests/configmap/reference-cm.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/empty-kustomization/templates/kustomization-placeholder.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/gke/manifests/gke.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/gke/templates/gke01.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/crossplane/providers/aws/templates/crossplane-providerconfig-aws.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/crossplane/providers/azure/templates/crossplane-providerconfig-azure.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/crossplane/providers/gcp/templates/crossplane-providerconfig-gcp.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/kubernetes-dashboard/templates/cluster-role-binding-dashboard.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/kubernetes-dashboard/templates/sa-dashboard.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/kubernetes-dashboard/templates/secret-token-dashboard.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/sa-and-role.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/building-blocks/clone-transform-push-wft.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/building-blocks/cloud-accounts-wft.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/building-blocks/cluster-management-wft.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/building-blocks/debugging-wft.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/building-blocks/git-wft.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/building-blocks/k8s-resources-wft.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/building-blocks/ksu-management-wft.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/building-blocks/oka-management-wft.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/building-blocks/profile-management-wft.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-attach-profile.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-bootstrap-cluster-wft.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-clone-ksu.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-create-aks-cluster-and-bootstrap-wft.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-create-crossplane-cluster-and-bootstrap-wft.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-create-ksu-generated-hr.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-create-ksu-hr.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-create-oka.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-create-profile.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-create-providerconfig-wft.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-delete-cluster-wft.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-delete-ksu.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-delete-oka.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-delete-profile.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-delete-providerconfig-wft.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-detach-profile.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-disconnect-flux-remote-cluster-wft.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-update-aks-cluster.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-update-crossplane-cluster-and-bootstrap-wft.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-update-ksu-generated-hr.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-update-ksu-hr.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-update-oka.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-update-providerconfig-wft.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/argo-workflows/manifests/argo-namespace.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/argo-workflows/manifests/argo-wf-controller.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/argo-workflows/templates/argo-workflows.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/cert-manager/manifests/cert-manager-chart.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/cert-manager/templates/cert-manager-ks.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/controller/manifests/crossplane-helmrelease.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/controller/manifests/crossplane-helmrepo.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/controller/manifests/crossplane-namespace.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/controller/manifests/kustomization.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/controller/templates/crossplane.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/aws/manifests/provider-ec2.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/aws/manifests/provider-eks.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/aws/manifests/provider-iam.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/aws/manifests/provider-vpc.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/aws/templates/crossplane-aws-providers.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/azure/manifests/provider-azure-container.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/azure/manifests/provider-azure-dbformysql.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/azure/templates/crossplane-azure-providers.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/gcp/manifests/provider-gcp-cloudplatform.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/gcp/manifests/provider-gcp-container.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/gcp/templates/crossplane-gcp-providers.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/ingress-nginx/manifests/ingress-nginx.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/ingress-nginx/templates/ingress-nginx-ks.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/manifests/addons/grafana.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/manifests/addons/jaeger.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/manifests/addons/kiali.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/manifests/addons/loki.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/manifests/addons/prometheus.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/manifests/core/istio-hr.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/manifests/core/istio-namespace.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/manifests/core/istio-repo.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/templates/istio-addons-ks.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/templates/istio-core-ks.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/komoplane/manifests/komodorio-repo.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/komoplane/manifests/komoplane-hr.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/komoplane/templates/komoplane-ks.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/kubernetes-dashboard/manifests/kubernetes-dashboard-hr.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/kubernetes-dashboard/manifests/kubernetes-dashboard-repo.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/kubernetes-dashboard/templates/kubernetes-dashboard-ks.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/weave-gitops/manifests/weave-gitops-dashboard.yaml [new file with mode: 0644]
installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/weave-gitops/templates/weave-gitops-ks.yaml [new file with mode: 0644]
installers/mgmt-cluster/gitea/00-custom-config.rc [new file with mode: 0644]
installers/mgmt-cluster/gitea/01-base-config.rc [new file with mode: 0644]
installers/mgmt-cluster/gitea/02-deploy-gitea.sh [new file with mode: 0755]
installers/mgmt-cluster/gitea/03-get-gitea-connection-info.rc [new file with mode: 0644]
installers/mgmt-cluster/gitea/04-fix-and-use-external-gitea-urls.sh [new file with mode: 0755]
installers/mgmt-cluster/gitea/05-export-connection-info.sh [new file with mode: 0755]
installers/mgmt-cluster/gitea/90-provision-gitea-for-osm.sh [new file with mode: 0755]
installers/mgmt-cluster/gitea/91-provision-local-git-user.sh [new file with mode: 0755]
installers/mgmt-cluster/gitea/ALL-IN-ONE-Gitea-install.sh [new file with mode: 0755]
installers/mgmt-cluster/gitea/README.md [new file with mode: 0644]
installers/mgmt-cluster/gitea/admin/add-collaborator-to-user-repo.sh [new file with mode: 0755]
installers/mgmt-cluster/gitea/admin/api.sh [new file with mode: 0755]
installers/mgmt-cluster/gitea/admin/create-api-access-token.sh [new file with mode: 0755]
installers/mgmt-cluster/gitea/admin/create-cmd-access-token.sh [new file with mode: 0755]
installers/mgmt-cluster/gitea/admin/create-org-repository.sh [new file with mode: 0755]
installers/mgmt-cluster/gitea/admin/create-org.sh [new file with mode: 0755]
installers/mgmt-cluster/gitea/admin/create-user-repository.sh [new file with mode: 0755]
installers/mgmt-cluster/gitea/admin/create-user-ssh-key.sh [new file with mode: 0755]
installers/mgmt-cluster/gitea/admin/create-user.sh [new file with mode: 0755]
installers/mgmt-cluster/gitea/admin/delete-org-repository.sh [new file with mode: 0755]
installers/mgmt-cluster/gitea/admin/delete-org.sh [new file with mode: 0755]
installers/mgmt-cluster/gitea/admin/delete-user-repository.sh [new file with mode: 0755]
installers/mgmt-cluster/gitea/admin/gitea.sh [new file with mode: 0755]
installers/mgmt-cluster/gitea/admin/shell.sh [new file with mode: 0755]
installers/mgmt-cluster/gitea/library/functions.sh [new file with mode: 0755]
installers/mgmt-cluster/gitea/library/trap.sh [new file with mode: 0755]
installers/mgmt-cluster/gitea/values-all.yaml [new file with mode: 0644]
installers/mgmt-cluster/gitea/values-standalone-ingress-ssh2222.yaml [new file with mode: 0644]
installers/mgmt-cluster/gitea/values-standalone-ingress.yaml [new file with mode: 0644]
installers/mgmt-cluster/gitea/values-standalone.yaml [new file with mode: 0644]
installers/mgmt-cluster/install_mgmt_cluster.sh [new file with mode: 0755]
installers/mgmt-cluster/library/functions.sh [new file with mode: 0755]
installers/mgmt-cluster/library/trap.sh [new file with mode: 0755]
installers/mgmt-cluster/mgmt-operators-and-crds/add-operators-and-crds.sh [new file with mode: 0755]
installers/mgmt-cluster/mgmt-operators-and-crds/configure-workflows.sh [new file with mode: 0755]
installers/mgmt-cluster/mgmt-operators-and-crds/library/functions.sh [new file with mode: 0755]
installers/mgmt-cluster/mgmt-operators-and-crds/library/trap.sh [new file with mode: 0755]
installers/mgmt-cluster/minio/00-base-config.rc [new file with mode: 0644]
installers/mgmt-cluster/minio/01-deploy-minio-operator.sh [new file with mode: 0755]
installers/mgmt-cluster/minio/02-create-minio-tenant.sh [new file with mode: 0755]
installers/mgmt-cluster/minio/03-deploy-ingress-for-minio.sh [new file with mode: 0755]
installers/mgmt-cluster/minio/04-get-minio-connection-info.rc [new file with mode: 0644]
installers/mgmt-cluster/minio/05-export-connection-info.sh [new file with mode: 0755]
installers/mgmt-cluster/minio/ALL-IN-ONE-Minio-install.sh [new file with mode: 0755]
installers/mgmt-cluster/minio/README.md [new file with mode: 0644]
installers/mgmt-cluster/minio/ingress-manifests/console/ingress-console.yaml [new file with mode: 0644]
installers/mgmt-cluster/minio/ingress-manifests/tenant/ingress-tenant.yaml [new file with mode: 0644]
installers/mgmt-cluster/minio/library/functions.sh [new file with mode: 0755]
installers/mgmt-cluster/minio/library/trap.sh [new file with mode: 0755]
installers/mgmt-cluster/setup-cli-tools.sh [new file with mode: 0755]

index ba692c1..1b18334 100755 (executable)
@@ -26,6 +26,12 @@ function usage(){
     echo -e "     -k <repo key>:  use specified repository public key url"
     echo -e "     -a <apt proxy url>: use this apt proxy url when downloading apt packages (air-gapped installation)"
     echo -e "     -c <kubernetes engine>: use a specific kubernetes engine (options: kubeadm, k3s), default is kubeadm"
+    echo -e "     -t <docker tag> specify osm docker tag (default is latest)"
+    echo -e "     -M <KUBECONFIG_FILE>: Kubeconfig of an existing cluster to be used as mgmt cluster instead of OSM cluster"
+    echo -e "     -G <KUBECONFIG_FILE>: Kubeconfig of an existing cluster to be used as auxiliary cluster instead of OSM cluster"
+    echo -e "     --no-mgmt-cluster: Do not provision a mgmt cluster for cloud-native gitops operations in OSM (NEW in Release SIXTEEN) (by default, it is installed)"
+    echo -e "     --no-aux-cluster: Do not provision an auxiliary cluster for cloud-native gitops operations in OSM (NEW in Release SIXTEEN) (by default, it is installed)"
+    echo -e "     -D <devops path>:   use local devops installation path"
     echo -e "     -s <namespace>  namespace when installed using k8s, default is osm"
     echo -e "     -H <VCA host>   use specific juju host controller IP"
     echo -e "     -S <VCA secret> use VCA/juju secret key"
@@ -35,13 +41,11 @@ function usage(){
     echo -e "     --old-sa:       install old Service Assurance framework (MON, POL); do not install Airflow and Pushgateway"
     echo -e "     --ng-sa:        install new Service Assurance framework (Airflow, AlertManager and Pushgateway) (enabled by default)"
     echo -e "     -o <COMPONENT>: ONLY installs the specified component (k8s_monitor, ng-sa, k8scluster, docker, deploy-osm)"
-    echo -e "     -O <openrc file path/cloud name>: Install OSM to an OpenStack infrastructure. <openrc file/cloud name> is required. If a <cloud name> is used, the clouds.yaml file should be under ~/.config/openstack/ or /etc/openstack/"
-    echo -e "     -N <openstack public network name/ID>: Public network name required to setup OSM to OpenStack"
-    echo -e "     -f <path to SSH public key>: Public SSH key to use to deploy OSM to OpenStack"
-    echo -e "     -F <path to cloud-init file>: Cloud-Init userdata file to deploy OSM to OpenStack"
-    echo -e "     -D <devops path> use local devops installation path"
-    echo -e "     -w <work dir>   Location to store runtime installation"
-    echo -e "     -t <docker tag> specify osm docker tag (default is latest)"
+    echo -e "     -O <openrc file path/cloud name>: install OSM to an OpenStack infrastructure. <openrc file/cloud name> is required. If a <cloud name> is used, the clouds.yaml file should be under ~/.config/openstack/ or /etc/openstack/"
+    echo -e "     -N <openstack public network name/ID>: public network name required to setup OSM to OpenStack"
+    echo -e "     -f <path to SSH public key>: public SSH key to use to deploy OSM to OpenStack"
+    echo -e "     -F <path to cloud-init file>: cloud-init userdata file to deploy OSM to OpenStack"
+    echo -e "     -w <work dir>:   Location to store runtime installation"
     echo -e "     -l:             LXD cloud yaml file"
     echo -e "     -L:             LXD credentials yaml file"
     echo -e "     -K:             Specifies the name of the controller to use - The controller must be already bootstrapped"
@@ -222,6 +226,7 @@ EOF"
     OSM_HELM_OPTS="${OSM_HELM_OPTS} --set grafana.ingress.hosts={grafana.${OSM_DEFAULT_IP}.nip.io}"
     OSM_HELM_OPTS="${OSM_HELM_OPTS} --set prometheus.server.ingress.hosts={prometheus.${OSM_DEFAULT_IP}.nip.io}"
     # OSM_HELM_OPTS="${OSM_HELM_OPTS} --set prometheus.alertmanager.ingress.hosts={alertmanager.${OSM_DEFAULT_IP}.nip.io}"
+    [ -z "${INSTALL_MGMT_CLUSTER}" ] && OSM_HELM_OPTS="${OSM_HELM_OPTS} --set global.gitops.enabled=false}"
 
     if [ -n "${INSTALL_JUJU}" ]; then
         OSM_HELM_OPTS="${OSM_HELM_OPTS} --set vca.enabled=true"
@@ -497,14 +502,18 @@ function install_osm() {
     fi
     track docker_ce docker_ce_ok
 
+    echo "Installing helm client ..."
     $OSM_DEVOPS/installers/install_helm_client.sh -D ${OSM_DEVOPS} ${DEBUG_INSTALL} || \
     FATAL_TRACK k8scluster "install_helm_client.sh failed"
     track helm_client install_helm_client_ok
 
+    echo "Installing K8s cluster ..."
     install_k8s_cluster
+    kubectl create namespace ${OSM_NAMESPACE}
     track k8scluster k8scluster_ok
 
     if [ -n "${INSTALL_JUJU}" ]; then
+        echo "Installing Juju ..."
         JUJU_OPTS="-D ${OSM_DEVOPS} -s ${OSM_NAMESPACE} -i ${OSM_DEFAULT_IP} ${DEBUG_INSTALL} ${INSTALL_CACHELXDIMAGES}"
         [ -n "${OSM_VCA_HOST}" ] && JUJU_OPTS="$JUJU_OPTS -H ${OSM_VCA_HOST}"
         [ -n "${LXD_CLOUD_FILE}" ] && JUJU_OPTS="$JUJU_OPTS -l ${LXD_CLOUD_FILE}"
@@ -519,7 +528,22 @@ function install_osm() {
     # This track is maintained for backwards compatibility
     track docker_images docker_images_ok
 
+    # Install mgmt cluster
+    echo "Installing mgmt cluster ..."
+    MGMTCLUSTER_INSTALL_OPTS="-D ${OSM_DEVOPS} ${DEBUG_INSTALL}"
+    [ -n "${INSTALL_MGMT_CLUSTER}" ] || MGMTCLUSTER_INSTALL_OPTS="${MGMTCLUSTER_INSTALL_OPTS} --no-mgmt-cluster"
+    [ -n "${INSTALL_AUX_CLUSTER}" ] || MGMTCLUSTER_INSTALL_OPTS="${MGMTCLUSTER_INSTALL_OPTS} --no-aux-cluster"
+    export KUBECONFIG_MGMT_CLUSTER=${KUBECONFIG_MGMT_CLUSTER:-"$HOME/.kube/config"}
+    export KUBECONFIG_AUX_CLUSTER=${KUBECONFIG_AUX_CLUSTER:-"$HOME/.kube/config"}
+    MGMTCLUSTER_INSTALL_OPTS="${MGMTCLUSTER_INSTALL_OPTS} -M ${KUBECONFIG_MGMT_CLUSTER}"
+    MGMTCLUSTER_INSTALL_OPTS="${MGMTCLUSTER_INSTALL_OPTS} -G ${KUBECONFIG_AUX_CLUSTER}"
+    echo "Options: ${MGMTCLUSTER_INSTALL_OPTS}"
+    $OSM_DEVOPS/installers/mgmt-cluster/install_mgmt_cluster.sh ${MGMTCLUSTER_INSTALL_OPTS} || \
+    FATAL_TRACK mgmtcluster "install_mgmt_cluster.sh failed"
+    track mgmtcluster mgmt_and_aux_cluster_ok
+
     # Deploy OSM (mongodb, OSM helm chart, NGSA)
+    echo "Deploying OSM in the K8s cluster ..."
     deploy_osm
 
     if [ -n "$INSTALL_K8S_MONITOR" ]; then
@@ -528,7 +552,7 @@ function install_osm() {
         track deploy_osm install_k8s_monitoring_ok
     fi
 
-    [ -z "$INSTALL_NOHOSTCLIENT" ] && install_osmclient
+    [ -z "$INSTALL_NOHOSTCLIENT" ] && echo "Installing osmclient ..." && install_osmclient
     track osmclient osmclient_ok
 
     echo -e "Checking OSM health state..."
@@ -538,6 +562,7 @@ function install_osm() {
     track healthchecks osm_unhealthy didnotconverge)
     track healthchecks after_healthcheck_ok
 
+    echo -e "Adding local K8s cluster _system-osm-k8s to OSM ..."
     add_local_k8scluster
     track final_ops add_local_k8scluster_ok
 
@@ -643,7 +668,6 @@ function dump_vars(){
     echo "INSTALL_PLA=$INSTALL_PLA"
     echo "INSTALL_TO_OPENSTACK=$INSTALL_TO_OPENSTACK"
     echo "INSTALL_VIMEMU=$INSTALL_VIMEMU"
-    echo "NO_HOST_PORTS=$NO_HOST_PORTS"
     echo "OPENSTACK_PUBLIC_NET_NAME=$OPENSTACK_PUBLIC_NET_NAME"
     echo "OPENSTACK_OPENRC_FILE_OR_CLOUD=$OPENSTACK_OPENRC_FILE_OR_CLOUD"
     echo "OPENSTACK_ATTACH_VOLUME=$OPENSTACK_ATTACH_VOLUME"
@@ -721,6 +745,8 @@ INSTALL_DOCKER=""
 INSTALL_JUJU=""
 INSTALL_NOHOSTCLIENT=""
 INSTALL_CACHELXDIMAGES=""
+INSTALL_AUX_CLUSTER="y"
+INSTALL_MGMT_CLUSTER="y"
 OSM_DEVOPS=
 OSM_VCA_HOST=
 OSM_VCA_SECRET=
@@ -728,7 +754,6 @@ OSM_VCA_PUBKEY=
 OSM_VCA_CLOUDNAME="localhost"
 OSM_VCA_K8S_CLOUDNAME="k8scloud"
 OSM_NAMESPACE=osm
-NO_HOST_PORTS=""
 REPOSITORY_KEY="OSM%20ETSI%20Release%20Key.gpg"
 REPOSITORY_BASE="https://osm-download.etsi.org/repository/osm/debian"
 OSM_WORK_DIR="/etc/osm"
@@ -756,7 +781,7 @@ DOCKER_PROXY_URL=
 MODULE_DOCKER_TAG=
 OSM_INSTALLATION_TYPE="Default"
 
-while getopts ":a:c:r:n:k:u:R:D:o:O:N:H:S:s:t:U:P:A:l:L:K:d:p:T:f:F:-: hy" o; do
+while getopts ":a:c:r:n:k:u:R:D:o:O:N:H:S:s:t:U:P:A:l:L:K:d:p:T:f:F:G:M:-: hy" o; do
     case "${o}" in
         a)
             APT_PROXY_URL=${OPTARG}
@@ -853,10 +878,18 @@ while getopts ":a:c:r:n:k:u:R:D:o:O:N:H:S:s:t:U:P:A:l:L:K:d:p:T:f:F:-: hy" o; do
         T)
             MODULE_DOCKER_TAG="${OPTARG}"
             ;;
+        M)
+            KUBECONFIG_MGMT_CLUSTER="${OPTARG}"
+            ;;
+        G)
+            KUBECONFIG_AUX_CLUSTER="${OPTARG}"
+            ;;
         -)
             [ "${OPTARG}" == "help" ] && usage && exit 0
             [ "${OPTARG}" == "debug" ] && DEBUG_INSTALL="--debug" && continue
             [ "${OPTARG}" == "uninstall" ] && UNINSTALL="y" && continue
+            [ "${OPTARG}" == "no-mgmt-cluster" ] && INSTALL_MGMT_CLUSTER="" && continue
+            [ "${OPTARG}" == "no-aux-cluster" ] && INSTALL_AUX_CLUSTER="" && continue
             [ "${OPTARG}" == "update" ] && UPDATE="y" && continue
             [ "${OPTARG}" == "reconfigure" ] && RECONFIGURE="y" && continue
             [ "${OPTARG}" == "test" ] && TEST_INSTALLER="y" && continue
@@ -866,7 +899,6 @@ while getopts ":a:c:r:n:k:u:R:D:o:O:N:H:S:s:t:U:P:A:l:L:K:d:p:T:f:F:-: hy" o; do
             [ "${OPTARG}" == "docker" ] && INSTALL_DOCKER="y" && continue
             [ "${OPTARG}" == "nodocker" ] && INSTALL_DOCKER="" && continue
             [ "${OPTARG}" == "showopts" ] && SHOWOPTS="y" && continue
-            [ "${OPTARG}" == "nohostports" ] && NO_HOST_PORTS="y" && continue
             [ "${OPTARG}" == "juju" ] && INSTALL_JUJU="y" && continue
             [ "${OPTARG}" == "nojuju" ] && INSTALL_JUJU="" && continue
             [ "${OPTARG}" == "nohostclient" ] && INSTALL_NOHOSTCLIENT="y" && continue
index b28c286..fd01923 100644 (file)
@@ -119,6 +119,12 @@ spec:
             - mountPath: /etc/ssl/lcm-client/
               name: lcm-client-cert
               readOnly: true
+            {{- if .Values.global.gitops.enabled }}
+            - mountPath: /etc/osm/mgmtcluster-kubeconfig.yaml
+              name: mgmtcluster-kubeconfig
+              readOnly: true
+              subPath: mgmtcluster-kubeconfig.yaml
+            {{- end }}
       volumes:
         - name: osm-ca
           secret:
@@ -131,6 +137,15 @@ spec:
           secret:
             defaultMode: 420
             secretName: lcm-client-cert
+        {{- if .Values.global.gitops.enabled }}
+        - name: mgmtcluster-kubeconfig
+          secret:
+            defaultMode: 420
+            items:
+            - key: kubeconfig
+              path: mgmtcluster-kubeconfig.yaml
+            secretName: mgmtcluster-secret
+        {{- end }}
       {{- with .Values.global.nodeSelector }}
       nodeSelector:
         {{- toYaml . | nindent 8 }}
index 41a2be2..af9f71a 100644 (file)
@@ -54,6 +54,15 @@ global:
         # secretName: mongodb-k8s
         # secretKeyRootPassword: mongodb-root-password
 
+  gitops:
+    enabled: true
+    auxcluster:
+      secretName: auxcluster-secret
+      secretKey: kubeconfig
+    mgmtcluster:
+      secretName: mgmtcluster-secret
+      secretKey: kubeconfig
+
   podAnnotations: {}
 
   podSecurityContext:
index 1a4aedf..be97814 100755 (executable)
@@ -189,6 +189,7 @@ check_and_track_k8s_ready_before_helm
 
 install_k8s_metrics
 
+# Clean existing namespace (idempotent installation)
 remove_k8s_namespace osm
 
 # install_helm has been moved to install_helm_client.sh, run from full_install_osm.sh,
index 476115e..5ea7116 100755 (executable)
@@ -29,6 +29,13 @@ function usage(){
     echo -e "     -u <repo base>: use specified repository url for osm packages"
     echo -e "     -k <repo key>:  use specified repository public key url"
     echo -e "     -a <apt proxy url>: use this apt proxy url when downloading apt packages (air-gapped installation)"
+    echo -e "     -c <kubernetes engine>: use a specific kubernetes engine (options: kubeadm, k3s), default is kubeadm"
+    echo -e "     -t <docker tag> specify osm docker tag (default is latest)"
+    echo -e "     -M <KUBECONFIG_FILE>: Kubeconfig of an existing cluster to be used as mgmt cluster instead of OSM cluster"
+    echo -e "     -G <KUBECONFIG_FILE>: Kubeconfig of an existing cluster to be used as auxiliary cluster instead of OSM cluster"
+    echo -e "     --no-mgmt-cluster: Do not provision a mgmt cluster for cloud-native gitops operations in OSM (NEW in Release SIXTEEN) (by default, it is installed)"
+    echo -e "     --no-aux-cluster: Do not provision an auxiliary cluster for cloud-native gitops operations in OSM (NEW in Release SIXTEEN) (by default, it is installed)"
+    echo -e "     -D <devops path>:   use local devops installation path"
     echo -e "     -s <namespace>  namespace when installed using k8s, default is osm"
     echo -e "     -H <VCA host>   use specific juju host controller IP"
     echo -e "     -S <VCA secret> use VCA/juju secret key"
@@ -38,13 +45,11 @@ function usage(){
     echo -e "     --old-sa:       install old Service Assurance framework (MON, POL); do not install Airflow and Pushgateway"
     echo -e "     --ng-sa:        install new Service Assurance framework (Airflow, AlertManager and Pushgateway) (enabled by default)"
     echo -e "     -o <COMPONENT>: ONLY installs the specified component (k8s_monitor, ng-sa, k8scluster, docker, deploy-osm)"
-    echo -e "     -O <openrc file path/cloud name>: Install OSM to an OpenStack infrastructure. <openrc file/cloud name> is required. If a <cloud name> is used, the clouds.yaml file should be under ~/.config/openstack/ or /etc/openstack/"
-    echo -e "     -N <openstack public network name/ID>: Public network name required to setup OSM to OpenStack"
-    echo -e "     -f <path to SSH public key>: Public SSH key to use to deploy OSM to OpenStack"
-    echo -e "     -F <path to cloud-init file>: Cloud-Init userdata file to deploy OSM to OpenStack"
-    echo -e "     -D <devops path> use local devops installation path"
-    echo -e "     -w <work dir>   Location to store runtime installation"
-    echo -e "     -t <docker tag> specify osm docker tag (default is latest)"
+    echo -e "     -O <openrc file path/cloud name>: install OSM to an OpenStack infrastructure. <openrc file/cloud name> is required. If a <cloud name> is used, the clouds.yaml file should be under ~/.config/openstack/ or /etc/openstack/"
+    echo -e "     -N <openstack public network name/ID>: public network name required to setup OSM to OpenStack"
+    echo -e "     -f <path to SSH public key>: public SSH key to use to deploy OSM to OpenStack"
+    echo -e "     -F <path to cloud-init file>: cloud-init userdata file to deploy OSM to OpenStack"
+    echo -e "     -w <work dir>:   Location to store runtime installation"
     echo -e "     -l:             LXD cloud yaml file"
     echo -e "     -L:             LXD credentials yaml file"
     echo -e "     -K:             Specifies the name of the controller to use - The controller must be already bootstrapped"
@@ -130,7 +135,8 @@ EOF"
     [ -z "${DEBUG_INSTALL}" ] || DEBUG end of function
 }
 
-while getopts ":a:b:r:n:k:u:R:D:o:O:m:N:H:S:s:t:U:P:A:l:L:K:d:p:T:f:F:-: hy" o; do
+while getopts ":a:c:r:n:k:u:R:D:o:O:N:H:S:s:t:U:P:A:l:L:K:d:p:T:f:F:G:M:-: hy" o; do
+
     case "${o}" in
         D)
             DEVOPS_PATH="${OPTARG}"
diff --git a/installers/mgmt-cluster/00-base-config.rc b/installers/mgmt-cluster/00-base-config.rc
new file mode 100644 (file)
index 0000000..56cc28b
--- /dev/null
@@ -0,0 +1,38 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+# Location where credentials should be saved
+export CREDENTIALS_DIR=${CREDENTIALS_DIR:-../../.credentials}; export CREDENTIALS_DIR=$(readlink -f "${CREDENTIALS_DIR}")
+
+# Base location where repos are cloned
+export WORK_REPOS_DIR=${WORK_REPOS_DIR:-../../repos}; export WORK_REPOS_DIR=$(readlink -f "${WORK_REPOS_DIR}")
+
+# Locations where each relevant repo is cloned
+export FLEET_REPO_DIR=${FLEET_REPO_DIR:-"${WORK_REPOS_DIR}/fleet-osm"}
+export SW_CATALOGS_REPO_DIR=${SW_CATALOGS_REPO_DIR:-"${WORK_REPOS_DIR}/sw-catalogs-osm"}
+
+# Remove local folders prior to clone?
+export REMOVE_LOCAL_DIR_BEFORE_CLONING=${REMOVE_LOCAL_DIR_BEFORE_CLONING:-"true"}
+
+# Gitea's default values file
+export GITEA_CHART_VALUES_FILE=values-standalone-ingress-ssh2222.yaml
+
+# Base name for age keys for management cluster
+export AGE_KEY_NAME_MGMT=${AGE_KEY_NAME_MGMT:-age.mgmt}
+
+# Name of the project for the OSM administrator
+export MGMT_PROJECT_NAME=${MGMT_PROJECT_NAME:-"osm_admin"}
diff --git a/installers/mgmt-cluster/01-provision-aux-svc.sh b/installers/mgmt-cluster/01-provision-aux-svc.sh
new file mode 100755 (executable)
index 0000000..cafbd51
--- /dev/null
@@ -0,0 +1,89 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e -o pipefail
+
+# Warning!!!: Remember to select the desired kubeconfig profile before launching this script
+
+export HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+source "${HERE}/library/functions.sh"
+source "${HERE}/library/trap.sh"
+
+
+############################ NGINX Ingress controller
+m "\n#####################################################################" "${CYAN}"
+m "(1/3) Installing NGINX Ingress controller..." "${CYAN}"
+m "#####################################################################\n" "${CYAN}"
+
+# Install NGINX Ingress controller (NOTE: this command is idempotent)
+## Uncomment for AKS:
+NGINX_VERSION="4.10.0"
+ANNOTATIONS='--set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz'
+ANNOTATIONS=${ANNOTATIONS:-""}
+helm upgrade --install ingress-nginx ingress-nginx \
+  --repo https://kubernetes.github.io/ingress-nginx --version ${NGINX_VERSION} \
+  --namespace ingress-nginx --create-namespace ${ANNOTATIONS}
+
+# Wait until ready
+kubectl wait --namespace ingress-nginx \
+  --for=condition=ready pod \
+  --selector=app.kubernetes.io/component=controller \
+  --timeout=120s
+
+#####################################################################
+
+
+############################ Gitea
+m "\n#####################################################################" "${CYAN}"
+m "(2/3) Installing Gitea..." "${CYAN}"
+m "#####################################################################\n" "${CYAN}"
+
+# Enter the Gitea folder
+pushd gitea > /dev/null
+
+# Install Gitea and expose web with Ingress
+export GITEA_CHART_VALUES_FILE=${GITEA_CHART_VALUES_FILE:-values-standalone-ingress.yaml}
+./ALL-IN-ONE-Gitea-install.sh
+
+# Provision for OSM
+m "\nProvisioning Gitea for OSM use..."
+source "${CREDENTIALS_DIR}/gitea_environment.rc"
+./90-provision-gitea-for-osm.sh
+
+# Return to base folder
+popd > /dev/null
+
+#####################################################################
+
+
+############################ Minio
+m "\n#####################################################################" "${CYAN}"
+m "(3/3) Installing Minio..." "${CYAN}"
+m "#####################################################################\n" "${CYAN}"
+
+export INSTALL_MINIO=${INSTALL_MINIO:-"y"}
+
+if [ -n "${INSTALL_MINIO}" ]; then
+    # Enter the Minio folder
+    pushd minio > /dev/null
+    # Install Minio and expose Console and tenant endpoint with Ingress
+    ./ALL-IN-ONE-Minio-install.sh
+    # Return to base folder
+    popd > /dev/null
+fi
+#####################################################################
diff --git a/installers/mgmt-cluster/02-provision-local-git-user.sh b/installers/mgmt-cluster/02-provision-local-git-user.sh
new file mode 100755 (executable)
index 0000000..12346eb
--- /dev/null
@@ -0,0 +1,33 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e -o pipefail
+
+# Warning!!!: Remember to select the desired kubeconfig profile before launching this script
+
+export HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+source "${HERE}/library/functions.sh"
+source "${HERE}/library/trap.sh"
+
+
+# Source credentials
+source "${CREDENTIALS_DIR}/gitea_environment.rc"
+source "${CREDENTIALS_DIR}/gitea_tokens.rc"
+
+# Add the local Git user to Gitea as a profile, upload the public SSH key (to allow SSH operations), and add the user as "collaborator" to both repos
+"${HERE}/gitea/91-provision-local-git-user.sh"
diff --git a/installers/mgmt-cluster/03-provision-mgmt-cluster.sh b/installers/mgmt-cluster/03-provision-mgmt-cluster.sh
new file mode 100755 (executable)
index 0000000..7b8fbf6
--- /dev/null
@@ -0,0 +1,164 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e -o pipefail
+
+# Warning!!!: Remember to select the desired kubeconfig profile before launching this script
+
+export HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+source "${HERE}/library/functions.sh"
+source "${HERE}/library/trap.sh"
+
+
+############################ Clone repos
+m "\n#####################################################################" "${CYAN}"
+m "(1/8) Cloning relevant repos..." "${CYAN}"
+m "#####################################################################\n" "${CYAN}"
+
+# Load Gitea credentials
+source "${CREDENTIALS_DIR}/gitea_environment.rc"
+source "${CREDENTIALS_DIR}/gitea_tokens.rc"
+
+# clone the relevant repos to well-known local folders
+"${HERE}/flux/scripts/clone-relevant-repos.sh"
+
+#####################################################################
+
+
+############################ Flux bootstrap
+m "\n#####################################################################" "${CYAN}"
+m "(2/8) Running Flux bootstrap on the management cluster..." "${CYAN}"
+m "#####################################################################\n" "${CYAN}"
+
+# Bootstrap
+"${HERE}/flux/scripts/mgmt-cluster-bootstrap.sh"
+
+# Pull the latest changes from the `fleet` repo
+git -C "${FLEET_REPO_DIR}" pull origin main
+
+#####################################################################
+
+
+############################ SOPS setup for the management cluster
+m "\n#####################################################################" "${CYAN}"
+m "(3/8) Setting up SOPS in the management cluster..." "${CYAN}"
+m "#####################################################################\n" "${CYAN}"
+
+# Create a new `age` key pair for the management cluster
+"${HERE}/flux/scripts/create-age-keypair.sh" "${AGE_KEY_NAME_MGMT}"
+
+# Add the `age` key pair to the cluster
+"${HERE}/flux/scripts/add-age-key-to-cluster.sh" \
+  "${AGE_KEY_NAME_MGMT}" \
+  "${FLEET_REPO_DIR}/clusters/_management"
+
+#####################################################################
+
+
+############################ Base kustomizations and default cluster profiles
+m "\n#####################################################################" "${CYAN}"
+m "(4/8) Creating base kustomizations and default cluster profiles..." "${CYAN}"
+m "#####################################################################\n" "${CYAN}"
+
+TEMPLATES_DIR="flux/templates/fleet/clusters/_management"
+TEMPLATES_DIR=$(readlink -f "${TEMPLATES_DIR}")
+
+# ARGUMENTS:
+# 1: Cluster folder
+# 2: Project folder
+# 3: Profile name
+# 4: Templates folder
+"${HERE}/flux/scripts/create-new-cluster-folder-structure.sh" \
+  "${FLEET_REPO_DIR}/clusters/_management" \
+  "${FLEET_REPO_DIR}/${MGMT_PROJECT_NAME}" \
+  "_management" \
+  "${TEMPLATES_DIR}" \
+  $(<"${CREDENTIALS_DIR}/${AGE_KEY_NAME_MGMT}.pub")
+
+
+#####################################################################
+
+
+############################ Populate the SW-Catalogs repo folder
+m "\n#####################################################################" "${CYAN}"
+m "(5/8) Populating the SW-Catalogs repo folder..." "${CYAN}"
+m "#####################################################################\n" "${CYAN}"
+
+TEMPLATES_DIR="flux/templates/sw-catalogs"
+TEMPLATES_DIR=$(readlink -f "${TEMPLATES_DIR}")
+# rsync -varhP "${TEMPLATES_DIR}" "${SW_CATALOGS_REPO_DIR}/"
+cp -r "${TEMPLATES_DIR}"/* "${SW_CATALOGS_REPO_DIR}/"
+
+#####################################################################
+
+
+############################ Add all the required operators and CRDs
+m "\n#####################################################################" "${CYAN}"
+m "(6/8) Add all the required operators and CRDs..." "${CYAN}"
+m "#####################################################################\n" "${CYAN}"
+
+# ARGUMENTS:
+# 1: Project folder
+# 2: Profile name
+"${HERE}/mgmt-operators-and-crds/add-operators-and-crds.sh" \
+  "${FLEET_REPO_DIR}/${MGMT_PROJECT_NAME}" \
+  "_management"
+
+#####################################################################
+
+
+############################ Configure for running OSM workflows
+m "\n#####################################################################" "${CYAN}"
+m "(7/8) Configure for running OSM workflows..." "${CYAN}"
+m "#####################################################################\n" "${CYAN}"
+
+# ARGUMENTS:
+# 1: Project folder
+# 2: Profile name
+
+"${HERE}/mgmt-operators-and-crds/configure-workflows.sh" \
+  "${FLEET_REPO_DIR}/${MGMT_PROJECT_NAME}" \
+  "_management" \
+  $(<"${CREDENTIALS_DIR}/${AGE_KEY_NAME_MGMT}.pub")
+
+
+#####################################################################
+
+
+############################ Push changes to Git repos
+m "\n#####################################################################" "${CYAN}"
+m "(8/8) Pushing all changes to Git repos..." "${CYAN}"
+m "#####################################################################\n" "${CYAN}"
+
+# SW Catalogs
+pushd "${SW_CATALOGS_REPO_DIR}" > /dev/null
+# git status
+git add -A
+git commit -m "Sync from sw-catalogs template"
+git push -u origin main
+popd > /dev/null
+
+# Fleet
+pushd "${FLEET_REPO_DIR}" > /dev/null
+# git status
+git add -A
+git commit -m "Full profile structure after bootstrap + SOPS config + operators and CRDs"
+git push -u origin main
+popd > /dev/null
+
+#####################################################################
diff --git a/installers/mgmt-cluster/README.md b/installers/mgmt-cluster/README.md
new file mode 100644 (file)
index 0000000..7581cda
--- /dev/null
@@ -0,0 +1,689 @@
+<!--
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+implied.
+See the License for the specific language governing permissions and
+limitations under the License
+-->
+# Provisioning of K8s clusters to meet pre-requirements for cloud-native OSM
+
+[TOC]
+
+## 0. Introduction
+
+This folder provides all required scripts and instructions for the full provisioning of the cluster(s) required for enabling a cloud-native way of work in OSM:
+
+- **Cluster for Auxiliary Services.** This cluster runs auxiliary services that are required for a cloud native operation, but do not need to run necessarily in a `Management Cluster`.
+  - Note that the services served from this cluster might be replaced by standalone PaaS/SaaS services if needed, such as GitHub or Amazon S3, with the proper configurations.
+  - At the time of this writing, this cluster provides:
+    - **Git repo service** based on Gitea.
+    - **Object storage service** based on Minio. This service **should not be installed by default**, although users may want to run the automatic installation at their own discretion.
+  - For convenience, the web endpoints of these services are exposed via a NGINX _Ingress_.
+- **Management cluster.** This cluster runs the core CRDs and Operators required for a successful cloud-native operation assisted by a Kubernetes control plane.
+  - This includes a cluster successfully bootstrapped with **Flux**, where:
+    - Secrets are encrypted with SOPS.
+    - With Crossplane operator and desired providers installed.
+    - CAPI operators installed.
+  - For achieving that goal, the corresponding Git repositories are initialized with all required manifests and folder structure, so that all installations happen along the bootstrap operation. By default, the Git repositories created at the _Cluster for Auxiliary Services_ will be used.
+
+## 1. Cluster for Auxiliary Services
+
+First, you should load the environment variables with the key folders and configuration parameters. By default, in case some of them where still undefined, you may load sensible defaults by doing:
+
+```bash
+source 00-base-config.rc
+```
+
+Then, you should select the appropriate `kubeconfig` to point to the cluster where you want to install the auxiliary services. For instance:
+
+```bash
+export KUBECONFIG="${CREDENTIALS_DIR}/kubeconfig-aux-svc.yaml"
+# Alternatively:
+# kubectl config use-context osm-aux-svc-admin
+```
+
+Then run the all-in-one installer and, optionally, add the local Git user for more a more convenient setup to commit changes to the repos:
+
+```bash
+./01-provision-aux-svc.sh
+
+# (optional)
+./02-provision-local-git-user.sh
+```
+
+### 1.1 Test auxiliary services
+
+First retrieve service's credentials and endpoints as environment variables:
+
+```bash
+# Load Gitea environment
+source "${CREDENTIALS_DIR}/gitea_environment.rc"
+source "${CREDENTIALS_DIR}/gitea_tokens.rc"
+
+# Load Minio environment
+source "${CREDENTIALS_DIR}/minio_environment.rc"
+```
+
+#### 1.1.1 Test Gitea service
+
+```bash
+# Get URL and credentials to go with browser
+echo "Gitea HTTP URL: ${GITEA_HTTP_URL}"
+echo "Gitea admin user:"
+echo -e "- \tUser name: ${GITEA_ADMINISTRATOR_USERNAME}"
+echo -e "- \tPassword: ${GITEA_ADMINISTRATOR_PASSWORD}"
+echo "Gitea regular user:"
+echo -e "- \tUser name: ${GITEA_STD_USERNAME}"
+echo -e "- \tPassword: ${GITEA_STD_USER_PASS}"
+
+# SSH URL
+echo "Gitea SSH URL: ${GITEA_SSH_URL}"
+```
+
+#### 1.1.2 Test Minio service
+
+Get the URL and the JWT token to access the Minio Operator Console with the browser:
+
+```bash
+# Open URL in browser using the JWT as access token
+echo "Console URL: ${MINIO_CONSOLE_URL}"
+echo -e "JWT token:\n${MINIO_SA_TOKEN}"
+```
+
+Then test the tenant:
+
+```bash
+# Add alias to connect to the tenant
+ALIAS=osm
+echo "Minio Tenant URL: ${MINIO_TENANT_URL}"
+minioc alias set ${ALIAS} ${MINIO_TENANT_URL} ${MINIO_OSM_USERNAME} ${MINIO_OSM_PASSWORD} --insecure
+
+# Test
+minioc admin info ${ALIAS} --insecure
+
+# (optional) Delete the alias
+minioc alias remove ${ALIAS}
+```
+
+## 2. Management Cluster
+
+First, you should load the environment variables with the key folders and configuration parameters (in case your had not done it before). By default, in case some of them where still undefined, you may load sensible defaults by doing:
+
+```bash
+source 00-base-config.rc
+```
+
+Then, you should select the appropriate `kubeconfig` to point to the cluster that you want to make a management cluster for OSM. For instance:
+
+```bash
+export KUBECONFIG="${CREDENTIALS_DIR}/kubeconfig-mgmt.yaml"
+# Alternatively:
+# kubectl config use-context osm-mgmt-admin
+```
+
+Depending on your situation, you can choose among these three procedures:
+
+1. Quickstart (recommended).
+   - Based on regular Flux bootstrap with a new `age` key pair, reusing a set of pre-created manifests so that the process is simplified.
+2. Restore a prior management cluster (from Git repo and `age` key pair).
+   - Flux bootstrap over the Git repo used by a pre-existing management cluster, using the previous `age` key pair.
+3. Create management cluster from scratch (useful for development and evolution of reference manifests)
+   - Based on regular Flux bootstrap with a new `age` key pair.
+   - Manifests are created from scratch.
+
+### 2.1 Quickstart (recommended)
+
+**NOTE:** Before proceeding, please ensure the appropriate `kubeconfig` and make sure to source the required base configuration at `00-base-config.rc`.
+
+```bash
+./03-provision-mgmt-cluster.sh
+```
+
+(optional) Watch sync progress:
+
+```bash
+./flux/scripts/watch-mgmt-cluster.sh
+```
+
+#### 2.1.1 (optional) Test creation of secrets using SOPS encryption
+
+```bash
+# Sources helper functions
+source ./flux/scripts/helper-functions.rc
+
+# Creates a secret and encrypts it with age
+SECRET_NAME="test-secret"
+PROJECT_DIR="${FLEET_REPO_DIR}/${MGMT_PROJECT_NAME}"
+PROFILE_NAME="_management"
+RESOURCES_DIR="${PROJECT_DIR}/managed-resources/${PROFILE_NAME}"
+kubectl create secret generic "${SECRET_NAME}" \
+  --namespace managed-resources \
+  --from-literal=foo=bar \
+  -o yaml --dry-run=client | tee "${RESOURCES_DIR}/secret-${SECRET_NAME}.yaml"
+
+# Encrypt in-place
+encrypt_secret_inplace "${RESOURCES_DIR}/secret-${SECRET_NAME}.yaml"
+
+# (Optional) View the secret manifest once encrypted
+cat "${RESOURCES_DIR}/secret-${SECRET_NAME}.yaml"
+```
+
+Push the new manifest:
+
+```bash
+pushd "${FLEET_REPO_DIR}"
+git status
+git add -A
+git commit -m "Test of encrypted secret"
+git push
+popd
+```
+
+Check that the secret was successfully decrypted by Flux and created properly:
+
+```bash
+kubectl get secret ${SECRET_NAME} -n managed-resources -o yaml
+kubectl get secret ${SECRET_NAME} -n managed-resources -o jsonpath='{.data.foo}' | base64 -d
+```
+
+Cleanup:
+
+```bash
+rm "${RESOURCES_DIR}/secret-${SECRET_NAME}.yaml"
+
+pushd "${FLEET_REPO_DIR}"
+git status
+git add -A
+git commit -m "Cleanup: Remove test secret"
+git push
+popd
+```
+
+After a while it should be deleted:
+
+```bash
+watch kubectl get secret ${SECRET_NAME} -n managed-resources
+```
+
+#### 2.1.2 (optional) Check the readiness of management cluster add-ons
+
+```bash
+# Check the health of Crossplane providers
+kubectl get providers.pkg.crossplane.io
+kubectl get crd | grep upbound
+# kubectl get crd | grep azure
+# kubectl get crd | grep gcp
+
+# Check the availability of Argo WorkFlows
+kubectl port-forward deployment/argo-server -n argo 2746:2746
+# Open <https://localhost:2746>
+```
+
+### 2.2 Restore a prior management cluster from Git repo and `age` key pair
+
+TODO:
+
+### 2.3 Creation from scratch
+
+#### 2.3.1 Preparation
+
+Load the environment:
+
+```bash
+source 00-base-config.rc
+source "${CREDENTIALS_DIR}/gitea_environment.rc"
+source "${CREDENTIALS_DIR}/gitea_tokens.rc"
+```
+
+For convenience, create in Gitea a local user's profile, add public SSH key, and add as collaborator to the repo of the standard Gitea user (NOTE: We have to force the `kubeconfig` profile for the cluster for auxiliary services):
+
+```bash
+# Create new user
+export USER_NAME=$(git config --get user.name)
+export USER_MAIL=$(git config --get user.email)
+export USER_PASS="${GITEA_STD_USER_PASS}" # Same as standard user
+KUBECONFIG="${CREDENTIALS_DIR}/kubeconfig-aux-svc.yaml" "gitea/admin/create-user.sh" \
+  "${USER_NAME}" \
+  "${USER_PASS}" \
+  "${USER_MAIL}"
+
+# Create token
+export USER_TOKEN_NAME=user_token_name
+export USER_TOKEN=$( \
+    KUBECONFIG="${CREDENTIALS_DIR}/kubeconfig-aux-svc.yaml" "gitea/admin/create-cmd-access-token.sh" "${USER_NAME}" "${USER_TOKEN_NAME}" | \
+    grep 'Access token was successfully created' | \
+    cut -d ' ' -f 6 \
+)
+```
+
+Add public SSH key:
+
+```bash
+# PARAMETERS:
+# ==========
+# 1) Server URL
+# 2) Username
+# 3) Token
+# 4) SSH key content
+# 5) SSH key name in Gitea's user profile
+# 6) Read only?
+KUBECONFIG="${CREDENTIALS_DIR}/kubeconfig-aux-svc.yaml" "gitea/admin/create-user-ssh-key.sh" \
+  "${GITEA_HTTP_URL}" \
+  "${USER_NAME}" \
+  "${USER_TOKEN}" \
+  "$(<${HOME}/.ssh/id_rsa.pub)" \
+  "local_user_ssh_key" \
+  false
+```
+
+Add user as collaborator of the relevant repos:
+
+```bash
+# Fleet repo
+KUBECONFIG="${CREDENTIALS_DIR}/kubeconfig-aux-svc.yaml" "gitea/admin/add-collaborator-to-user-repo.sh" \
+  "${GITEA_HTTP_URL}" \
+  "${GITEA_STD_USERNAME}" \
+  "${GITEA_STD_TOKEN}" \
+  "fleet-osm" \
+  "${USER_NAME}" \
+  "write"
+
+# SW-Catalogs repo
+KUBECONFIG="${CREDENTIALS_DIR}/kubeconfig-aux-svc.yaml" "gitea/admin/add-collaborator-to-user-repo.sh" \
+  "${GITEA_HTTP_URL}" \
+  "${GITEA_STD_USERNAME}" \
+  "${GITEA_STD_TOKEN}" \
+  "sw-catalogs-osm" \
+  "${USER_NAME}" \
+  "write"
+```
+
+Finally, clone both repos in a well-known location:
+
+```bash
+mkdir -p "${WORK_REPOS_DIR}"
+export FLEET_REPO_DIR="${WORK_REPOS_DIR}/fleet-osm"
+export SW_CATALOGS_REPO_DIR="${WORK_REPOS_DIR}/sw-catalogs-osm"
+
+# git@<GITEA_SSH_URL>:osm-developer/fleet-osm.git
+git clone ${GITEA_SSH_URL}/${GITEA_STD_USERNAME}/fleet-osm.git "${FLEET_REPO_DIR}"
+
+# git@<GITEA_SSH_URL>:osm-developer/sw-catalogs-osm.git
+git clone ${GITEA_SSH_URL}/${GITEA_STD_USERNAME}/sw-catalogs-osm.git "${SW_CATALOGS_REPO_DIR}"
+
+# Forces main instead of master
+pushd "${SW_CATALOGS_REPO_DIR}"
+# git branch -m master main
+git symbolic-ref HEAD refs/heads/main
+popd
+```
+
+#### 2.3.2 Bootstrap
+
+Now we can run a regular Flux bootstrap (without encryption):
+
+```bash
+# Regular bootstrap
+REPO=fleet-osm
+GIT_PATH=./clusters/_management
+GIT_BRANCH=main
+GIT_HTTP_URL=${GITEA_HTTP_URL}/${GITEA_STD_USERNAME}/${REPO}.git
+flux bootstrap git \
+    --url=${GIT_HTTP_URL} \
+    --allow-insecure-http=true \
+    --username=${GITEA_STD_USERNAME} \
+    --password="${GITEA_STD_USER_PASS}" \
+    --token-auth=true \
+    --branch=${GIT_BRANCH} \
+    --path=${GIT_PATH}
+
+# (optional) Check if successful
+flux check
+```
+
+Once completed the bootstrap, we will pull the latest changes from the `fleet` repo so that we can work conveniently:
+
+```bash
+git -C "${FLEET_REPO_DIR}" pull
+```
+
+#### 2.3.3 SOPS setup
+
+Create a new `age` key pair for the management cluster:
+
+```bash
+# Create private key and extract public key
+export AGE_KEY_NAME_MGMT=age.mgmt
+rm "${CREDENTIALS_DIR}/${AGE_KEY_NAME_MGMT}.key" "${CREDENTIALS_DIR}/${AGE_KEY_NAME_MGMT}.pub"
+age-keygen -o "${CREDENTIALS_DIR}/${AGE_KEY_NAME_MGMT}.key"
+age-keygen -y "${CREDENTIALS_DIR}/${AGE_KEY_NAME_MGMT}.key" > "${CREDENTIALS_DIR}/${AGE_KEY_NAME_MGMT}.pub"
+
+# Save the contents in environment variables for easier consumption
+export PRIVATE_KEY_MGMT=$(<"${CREDENTIALS_DIR}/${AGE_KEY_NAME_MGMT}.key")
+export PUBLIC_KEY_MGMT=$(<"${CREDENTIALS_DIR}/${AGE_KEY_NAME_MGMT}.pub")
+echo "${PRIVATE_KEY_MGMT}"
+echo "${PUBLIC_KEY_MGMT}"
+```
+
+Add the `age` private key to the cluster as secret:
+
+```bash
+cat "${CREDENTIALS_DIR}/${AGE_KEY_NAME_MGMT}.key" |
+kubectl create secret generic sops-age \
+  --namespace=flux-system \
+  --from-file=age.agekey=/dev/stdin
+```
+
+Create SOPS configuration at the root folder of the management cluster:
+
+```bash
+cat <<EOF > "${FLEET_REPO_DIR}/clusters/_management/.sops.yaml"
+creation_rules:
+  - encrypted_regex: ^(data|stringData)$
+    age: ${PUBLIC_KEY_MGMT}
+  # - path_regex: .*.yaml
+  #   encrypted_regex: ^(data|stringData)$
+  #   age: ${PUBLIC_KEY_MGMT}
+EOF
+```
+
+(optional) Add also the public key to the repository so that others who clone the repo can encrypt new files:
+
+```bash
+cp "${CREDENTIALS_DIR}/${AGE_KEY_NAME_MGMT}.pub" "${FLEET_REPO_DIR}/clusters/_management/.sops.pub.asc"
+```
+
+#### 2.3.4 Base folder structure and profile kustomizations
+
+Create the base folder structure + all profile folders for the management cluster:
+
+```bash
+# Name of the project for the OSM administrator
+export MGMT_PROJECT_NAME="osm_admin"
+
+# Creates all possible profile folders (as well as env var aliases)
+export MGMT_ADDON_CTRL_DIR="${FLEET_REPO_DIR}/${MGMT_PROJECT_NAME}/infra-controller-profiles/_management"
+export MGMT_ADDON_CONFIG_DIR="${FLEET_REPO_DIR}/${MGMT_PROJECT_NAME}/infra-config-profiles/_management"
+export MGMT_RESOURCES_DIR="${FLEET_REPO_DIR}/${MGMT_PROJECT_NAME}/managed-resources/_management"
+export MGMT_APPS_DIR="${FLEET_REPO_DIR}/${MGMT_PROJECT_NAME}/app-profiles/_management"
+mkdir -p "${MGMT_ADDON_CTRL_DIR}"
+mkdir -p "${MGMT_ADDON_CONFIG_DIR}"
+mkdir -p "${MGMT_RESOURCES_DIR}"
+mkdir -p "${MGMT_APPS_DIR}"
+
+# Copies the templates for management cluster setup
+export TEMPLATES_DIR="flux/templates"
+export TEMPLATES_DIR=$(readlink -f "${TEMPLATES_DIR}")
+export MGMT_CLUSTER_DIR="${FLEET_REPO_DIR}/clusters/_management"
+cp "${TEMPLATES_DIR}/fleet/clusters/_management"/* "${MGMT_CLUSTER_DIR}/"
+```
+
+Overrides the Git repo references and adds their secrets as needed (**NOTE:** these are the last secrets to be added imperatively):
+
+```bash
+# Repo URLs
+export FLEET_REPO_URL="${GITEA_HTTP_URL}/${GITEA_STD_USERNAME}/fleet-osm.git"
+export SW_CATALOGS_REPO_URL="${GITEA_HTTP_URL}/${GITEA_STD_USERNAME}/sw-catalogs-osm.git"
+export INFRA_CONTROLLERS_PATH="./${MGMT_PROJECT_NAME}/infra-controller-profiles/_management"
+export INFRA_CONFIGS_PATH="./${MGMT_PROJECT_NAME}/infra-config-profiles/_management"
+export MANAGED_RESOURCES_PATH="./${MGMT_PROJECT_NAME}/managed-resources/_management"
+export APPS_PATH="./${MGMT_PROJECT_NAME}/app-profiles/_management"
+
+# Fleet repo
+envsubst < "${TEMPLATES_DIR}/fleet/clusters/_management/fleet-repo.yaml" > "${MGMT_CLUSTER_DIR}/fleet-repo.yaml"
+
+# SW-Catalogs repo
+envsubst < "${TEMPLATES_DIR}/fleet/clusters/_management/sw-catalogs-repo.yaml" > "${MGMT_CLUSTER_DIR}/sw-catalogs-repo.yaml"
+
+# Secrets to access both Git repos
+kubectl create secret generic fleet-repo \
+    --namespace flux-system \
+    --from-literal=username="${GITEA_STD_USERNAME}" \
+    --from-literal=password="${GITEA_STD_USER_PASS}"
+
+kubectl create secret generic sw-catalogs \
+    --namespace flux-system \
+    --from-literal=username="${GITEA_STD_USERNAME}" \
+    --from-literal=password="${GITEA_STD_USER_PASS}"
+
+# Kustomization to sync infra controllers profile
+envsubst < "${TEMPLATES_DIR}/fleet/clusters/_management/infra-controllers.yaml" > "${MGMT_CLUSTER_DIR}/infra-controllers.yaml"
+
+# Kustomization to sync infra configs profile
+envsubst < "${TEMPLATES_DIR}/fleet/clusters/_management/infra-configs.yaml" > "${MGMT_CLUSTER_DIR}/infra-configs.yaml"
+
+# Kustomization to sync managed resources profile
+envsubst < "${TEMPLATES_DIR}/fleet/clusters/_management/managed-resources.yaml" > "${MGMT_CLUSTER_DIR}/managed-resources.yaml"
+
+# Kustomization to sync apps profile
+envsubst < "${TEMPLATES_DIR}/fleet/clusters/_management/apps.yaml" > "${MGMT_CLUSTER_DIR}/apps.yaml"
+```
+
+Create `ConfigMap` into profiles (and `Namespace` specs when needed) to avoid sync errors:
+
+```bash
+# Helper functions to create the profile ConfigMaps
+function safe_name() {
+  echo "$1" | \
+    sed '/\.\// s|./||' | \
+    sed 's|\.|-|g' | \
+    sed 's|/|-|g' | \
+    sed 's|_|-|g' | \
+    sed 's| |-|g'
+}
+
+function create_profile_configmap() {
+  local CONFIGMAP_NAME=$(safe_name "$1")
+  local PROFILE_REPO_URL="$2"
+  local PROFILE_PATH="$3"
+  kubectl create configmap ${CONFIGMAP_NAME} \
+    --namespace flux-system \
+    --from-literal=repo="${PROFILE_REPO_URL}" \
+    --from-literal=path="${PROFILE_PATH}" \
+    -o yaml \
+    --dry-run=client
+}
+
+# Infra controllers ConfigMap
+# Same name as the corresponding kustomization name
+CONFIGMAP_NAME="infra-controllers"
+PROFILE_REPO_URL="${FLEET_REPO_URL}"
+PROFILE_PATH="${INFRA_CONTROLLERS_PATH}"
+create_profile_configmap \
+  "${CONFIGMAP_NAME}" \
+  "${PROFILE_REPO_URL}" \
+  "${PROFILE_PATH}" \
+  > "${MGMT_ADDON_CTRL_DIR}/profile-configmap.yaml"
+
+# Infra configurations ConfigMap
+CONFIGMAP_NAME="infra-configs"
+PROFILE_REPO_URL="${FLEET_REPO_URL}"
+PROFILE_PATH="${INFRA_CONFIGS_PATH}"
+create_profile_configmap \
+  "${CONFIGMAP_NAME}" \
+  "${PROFILE_REPO_URL}" \
+  "${PROFILE_PATH}" \
+  > "${MGMT_ADDON_CONFIG_DIR}/profile-configmap.yaml"
+
+# Managed resources ConfigMap
+CONFIGMAP_NAME="managed-resources"
+PROFILE_REPO_URL="${FLEET_REPO_URL}"
+PROFILE_PATH="${MANAGED_RESOURCES_PATH}"
+create_profile_configmap \
+  "${CONFIGMAP_NAME}" \
+  "${PROFILE_REPO_URL}" \
+  "${PROFILE_PATH}" \
+  > "${MGMT_RESOURCES_DIR}/profile-configmap.yaml"
+
+# Managed resources namespace
+kubectl create ns ${CONFIGMAP_NAME} \
+    -o yaml     --dry-run=client \
+    > "${MGMT_RESOURCES_DIR}/namespace.yaml"
+
+# Apps ConfigMap
+CONFIGMAP_NAME="apps"
+PROFILE_REPO_URL="${FLEET_REPO_URL}"
+PROFILE_PATH="${APPS_PATH}"
+create_profile_configmap \
+  "${CONFIGMAP_NAME}" \
+  "${PROFILE_REPO_URL}" \
+  "${PROFILE_PATH}" \
+  > "${MGMT_APPS_DIR}/profile-configmap.yaml"
+```
+
+#### 2.3.5 Push to Git to update management cluster
+
+Push to Git all new manifests:
+
+```bash
+pushd "${FLEET_REPO_DIR}"
+git status
+git add -A
+git commit -m "Full profile structure after bootstrap + SOPS config"
+git push
+popd
+```
+
+(optional) Watch sync progress:
+
+```bash
+./flux/scripts/watch-mgmt-cluster.sh
+```
+
+#### 2.3.6 (optional) Test the creation of secrets using SOPS encryption
+
+```bash
+# Helper function to in-place encrypt secrets in manifest
+function encrypt_secret_inplace() {
+  local FILE="$1"
+
+  sops \
+    --age=${PUBLIC_KEY_MGMT} \
+    --encrypt \
+    --encrypted-regex '^(data|stringData)$' \
+    --in-place "${FILE}"
+}
+
+# Creates a secret and encrypts it with age
+SECRET_NAME="prueba"
+kubectl create secret generic "${SECRET_NAME}" \
+  --namespace managed-resources \
+  --from-literal=foo=bar \
+  -o yaml --dry-run=client | tee "${MGMT_RESOURCES_DIR}/secret-${SECRET_NAME}.yaml"
+encrypt_secret_inplace "${MGMT_RESOURCES_DIR}/secret-${SECRET_NAME}.yaml"
+
+# (Optional) View the secret manifest once encrypted
+cat "${MGMT_RESOURCES_DIR}/secret-${SECRET_NAME}.yaml"
+```
+
+Push the new manifest:
+
+```bash
+pushd "${FLEET_REPO_DIR}"
+git status
+git add -A
+git commit -m "Test of encrypted secret"
+git push
+popd
+```
+
+Check that the secret was successfully decrypted by Flux and created properly:
+
+```bash
+kubectl get secret ${SECRET_NAME} -n managed-resources -o yaml
+kubectl get secret ${SECRET_NAME} -n managed-resources -o jsonpath='{.data.foo}' | base64 -d
+```
+
+Cleanup:
+
+```bash
+rm "${MGMT_RESOURCES_DIR}/secret-${SECRET_NAME}.yaml"
+
+pushd "${FLEET_REPO_DIR}"
+git status
+git add -A
+git commit -m "Cleanup: Remove test secret"
+git push
+popd
+```
+
+After a while it should be deleted:
+
+```bash
+watch kubectl get secret ${SECRET_NAME} -n managed-resources
+```
+
+#### 2.3.7 Add required operators and CRDs
+
+First, we populate the SW-Catalogs repo:
+
+```bash
+rsync -varhP "${TEMPLATES_DIR}/sw-catalogs/" "${SW_CATALOGS_REPO_DIR}/"
+
+pushd "${SW_CATALOGS_REPO_DIR}"
+git status
+git add -A
+git commit -m "Sync from sw-catalogs template"
+git push -u origin main
+popd
+```
+
+Add the CrossPlane controller:
+
+```bash
+PACKAGE="${SW_CATALOGS_REPO_DIR}/infra-controllers/crossplane/controller"
+cp "${PACKAGE}/templates"/* "${MGMT_ADDON_CTRL_DIR}/"
+```
+
+Add the CrossPlane providers:
+
+```bash
+# Azure providers
+PACKAGE="${SW_CATALOGS_REPO_DIR}/infra-controllers/crossplane/providers/azure"
+cp "${PACKAGE}/templates"/* "${MGMT_ADDON_CTRL_DIR}/"
+
+# GCP providers
+PACKAGE="${SW_CATALOGS_REPO_DIR}/infra-controllers/crossplane/providers/gcp"
+cp "${PACKAGE}/templates"/* "${MGMT_ADDON_CTRL_DIR}/"
+
+# TODO: AWS providers
+```
+
+Add the Argo WorkFlows controller:
+
+```bash
+PACKAGE="${SW_CATALOGS_REPO_DIR}/infra-controllers/argo-workflows"
+cp "${PACKAGE}/templates"/* "${MGMT_ADDON_CTRL_DIR}/"
+```
+
+Push all changes to the fleet repo:
+
+```bash
+pushd "${FLEET_REPO_DIR}"
+git status
+git add -A
+git commit -m "Install base controllers and CRDs into mgmt cluster"
+git push -u origin main
+popd
+```
+
+(optional) Checks:
+
+```bash
+# Check the health of Crossplane providers
+kubectl get providers.pkg.crossplane.io
+kubectl get crd | grep upbound
+# kubectl get crd | grep azure
+# kubectl get crd | grep gcp
+
+# Check the availability of Argo WorkFlows
+kubectl port-forward deployment/argo-server -n argo 2746:2746
+# <https://localhost:2746>
+```
diff --git a/installers/mgmt-cluster/flux/scripts/add-age-key-to-cluster.sh b/installers/mgmt-cluster/flux/scripts/add-age-key-to-cluster.sh
new file mode 100755 (executable)
index 0000000..9d5e52b
--- /dev/null
@@ -0,0 +1,51 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e -o pipefail
+
+export HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+source "${HERE}/library/functions.sh"
+source "${HERE}/library/trap.sh"
+
+
+AGE_KEY_NAME="$1"
+CLUSTER_DIR="$2"
+
+# Load the contents of both keys
+export PRIVATE_KEY=$(<"${CREDENTIALS_DIR}/${AGE_KEY_NAME}.key")
+export PUBLIC_KEY=$(<"${CREDENTIALS_DIR}/${AGE_KEY_NAME}.pub")
+
+# Add the `age` private key to the cluster as secret:
+kubectl delete secret sops-age --namespace=flux-system 2> /dev/null || true
+# cat "${CREDENTIALS_DIR}/${AGE_KEY_NAME}.key" |
+echo "${PRIVATE_KEY}" |
+    kubectl create secret generic sops-age \
+    --namespace=flux-system \
+    --from-file=age.agekey=/dev/stdin
+
+# Create SOPS configuration at the root folder of the management cluster:
+cat <<EOF > "${CLUSTER_DIR}/.sops.yaml"
+creation_rules:
+  - encrypted_regex: ^(data|stringData)$
+    age: ${PUBLIC_KEY}
+  # - path_regex: .*.yaml
+  #   encrypted_regex: ^(data|stringData)$
+  #   age: ${PUBLIC_KEY}
+EOF
+
+# Add also the public key to the repository so that others who clone the repo can encrypt new files:
+cp "${CREDENTIALS_DIR}/${AGE_KEY_NAME}.pub" "${CLUSTER_DIR}/.sops.pub.asc"
diff --git a/installers/mgmt-cluster/flux/scripts/clone-relevant-repos.sh b/installers/mgmt-cluster/flux/scripts/clone-relevant-repos.sh
new file mode 100755 (executable)
index 0000000..93ffad9
--- /dev/null
@@ -0,0 +1,43 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e -o pipefail
+
+export HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+source "${HERE}/library/functions.sh"
+source "${HERE}/library/trap.sh"
+
+
+# Creates base dir in case it did not exist
+mkdir -p "${WORK_REPOS_DIR}"
+
+# Clones `fleet-osm` repo
+[[ "${REMOVE_LOCAL_DIR_BEFORE_CLONING}" == "true" ]] && rm -rf "${FLEET_REPO_DIR}"
+git clone ${GITEA_SSH_URL}/${GITEA_STD_USERNAME}/fleet-osm.git "${FLEET_REPO_DIR}"
+
+# Clones `sw-catalogs-osm` repo
+[[ "${REMOVE_LOCAL_DIR_BEFORE_CLONING}" == "true" ]] && rm -rf "${SW_CATALOGS_REPO_DIR}"
+git clone ${GITEA_SSH_URL}/${GITEA_STD_USERNAME}/sw-catalogs-osm.git "${SW_CATALOGS_REPO_DIR}"
+
+# Forces `main` instead of `master` as default branch
+pushd "${FLEET_REPO_DIR}" > /dev/null
+git symbolic-ref HEAD refs/heads/main
+popd > /dev/null
+pushd "${SW_CATALOGS_REPO_DIR}" > /dev/null
+git symbolic-ref HEAD refs/heads/main
+popd > /dev/null
diff --git a/installers/mgmt-cluster/flux/scripts/create-age-keypair.sh b/installers/mgmt-cluster/flux/scripts/create-age-keypair.sh
new file mode 100755 (executable)
index 0000000..d3dd9b1
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e -o pipefail
+
+export HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+source "${HERE}/library/functions.sh"
+source "${HERE}/library/trap.sh"
+
+
+AGE_KEY_NAME="$1"
+
+# Delete the keys in case they existed already
+rm -f "${CREDENTIALS_DIR}/${AGE_KEY_NAME}.key" "${CREDENTIALS_DIR}/${AGE_KEY_NAME}.pub"
+
+# Private key
+age-keygen -o "${CREDENTIALS_DIR}/${AGE_KEY_NAME}.key"
+
+# Public key (extracted from comment at private key)
+age-keygen -y "${CREDENTIALS_DIR}/${AGE_KEY_NAME}.key" > "${CREDENTIALS_DIR}/${AGE_KEY_NAME}.pub"
diff --git a/installers/mgmt-cluster/flux/scripts/create-new-cluster-folder-structure.sh b/installers/mgmt-cluster/flux/scripts/create-new-cluster-folder-structure.sh
new file mode 100755 (executable)
index 0000000..9263d74
--- /dev/null
@@ -0,0 +1,201 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e -o pipefail
+
+export HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+source "${HERE}/library/functions.sh"
+source "${HERE}/library/trap.sh"
+
+
+
+# Input values
+export CLUSTER_DIR="$1"
+export PROJECT_DIR="$2"
+export PROFILE_NAME="$3"
+export TEMPLATES_DIR="$4"
+export PUBLIC_KEY="$5"
+
+
+# Helper functions to create the profile ConfigMaps
+function safe_name() {
+  echo "$1" | \
+    sed '/\.\// s|./||' | \
+    sed 's|\.|-|g' | \
+    sed 's|/|-|g' | \
+    sed 's|_|-|g' | \
+    sed 's| |-|g'
+}
+
+function create_profile_configmap() {
+  local CONFIGMAP_NAME=$(safe_name "$1")
+  local PROFILE_REPO_URL="$2"
+  local PROFILE_PATH="$3"
+  kubectl create configmap ${CONFIGMAP_NAME} \
+    --namespace flux-system \
+    --from-literal=repo="${PROFILE_REPO_URL}" \
+    --from-literal=path="${PROFILE_PATH}" \
+    -o yaml \
+    --dry-run=client
+}
+
+# Helper functions to clone secret from one namespace to other
+function clone_secret_to_new_ns_stdout() {
+  local SECRET_NAME="$1"
+  local SOURCE_NS="$2"
+  local DESTINATION_NS="$3"
+
+  kubectl get secret "${SECRET_NAME}" -n "${SOURCE_NS}" -o yaml | \
+  yq 'del(.metadata.uid) | del(.metadata.resourceVersion) | del(.metadata.creationTimestamp)' | \
+  yq ".metadata.namespace = \"${DESTINATION_NS}\""
+}
+
+# Helper function to encrypt secrets from stdin
+function encrypt_secret_from_stdin() {
+  local PUBLIC_KEY="$1"
+
+  # Save secret manifest to temporary file
+  local TMPFILE=$(mktemp /tmp/secret.XXXXXXXXXX.yaml) || exit 1
+  cat > "${TMPFILE}"
+
+  # Encrypt
+  sops \
+    --age=${PUBLIC_KEY} \
+    --encrypt \
+    --encrypted-regex '^(data|stringData)$' \
+    --in-place "${TMPFILE}"
+
+  # Outputs the result and removes the temporary file
+  cat "${TMPFILE}" && rm -f "${TMPFILE}"
+}
+
+# Creates all folders in the profile (as well as env var aliases)
+export ADDON_CTRL_DIR="${PROJECT_DIR}/infra-controller-profiles/${PROFILE_NAME}"
+export ADDON_CONFIG_DIR="${PROJECT_DIR}/infra-config-profiles/${PROFILE_NAME}"
+export RESOURCES_DIR="${PROJECT_DIR}/managed-resources/${PROFILE_NAME}"
+export APPS_DIR="${PROJECT_DIR}/app-profiles/${PROFILE_NAME}"
+mkdir -p "${ADDON_CTRL_DIR}"
+mkdir -p "${ADDON_CONFIG_DIR}"
+mkdir -p "${RESOURCES_DIR}"
+mkdir -p "${APPS_DIR}"
+
+# Copies the templates for cluster setup
+cp "${TEMPLATES_DIR}"/* "${CLUSTER_DIR}/"
+
+# Repo URLs
+export FLEET_REPO_URL="${GITEA_HTTP_URL}/${GITEA_STD_USERNAME}/fleet-osm.git"
+export SW_CATALOGS_REPO_URL="${GITEA_HTTP_URL}/${GITEA_STD_USERNAME}/sw-catalogs-osm.git"
+export INFRA_CONTROLLERS_PATH="./${MGMT_PROJECT_NAME}/infra-controller-profiles/_management"
+export INFRA_CONFIGS_PATH="./${MGMT_PROJECT_NAME}/infra-config-profiles/_management"
+export MANAGED_RESOURCES_PATH="./${MGMT_PROJECT_NAME}/managed-resources/_management"
+export APPS_PATH="./${MGMT_PROJECT_NAME}/app-profiles/_management"
+
+# Render Flux `GitRepository` objects with proper Git URL and relative repo paths
+envsubst < "${TEMPLATES_DIR}/fleet-repo.yaml" > "${CLUSTER_DIR}/fleet-repo.yaml"
+envsubst < "${TEMPLATES_DIR}/sw-catalogs-repo.yaml" > "${CLUSTER_DIR}/sw-catalogs-repo.yaml"
+
+# Secrets to access both Git repos
+# (NOTE: these are the last secrets to be added imperatively)
+kubectl delete secret fleet-repo --namespace flux-system 2> /dev/null || true
+kubectl create secret generic fleet-repo \
+    --namespace flux-system \
+    --from-literal=username="${GITEA_STD_USERNAME}" \
+    --from-literal=password="${GITEA_STD_USER_PASS}"
+
+kubectl delete secret sw-catalogs --namespace flux-system 2> /dev/null || true
+kubectl create secret generic sw-catalogs \
+    --namespace flux-system \
+    --from-literal=username="${GITEA_STD_USERNAME}" \
+    --from-literal=password="${GITEA_STD_USER_PASS}"
+
+# Render Flux `Kustomizations` to sync with default profiles
+envsubst < "${TEMPLATES_DIR}/infra-controllers.yaml" > "${CLUSTER_DIR}/infra-controllers.yaml"
+envsubst < "${TEMPLATES_DIR}/infra-configs.yaml" > "${CLUSTER_DIR}/infra-configs.yaml"
+envsubst < "${TEMPLATES_DIR}/managed-resources.yaml" > "${CLUSTER_DIR}/managed-resources.yaml"
+envsubst < "${TEMPLATES_DIR}/apps.yaml" > "${CLUSTER_DIR}/apps.yaml"
+
+# Create `ConfigMaps` into profiles (and `Namespace` specs when needed) to avoid sync errors
+## Infra controllers ConfigMap
+CONFIGMAP_NAME="infra-controllers"
+PROFILE_REPO_URL="${FLEET_REPO_URL}"
+PROFILE_PATH="${INFRA_CONTROLLERS_PATH}"
+create_profile_configmap \
+  "${CONFIGMAP_NAME}" \
+  "${PROFILE_REPO_URL}" \
+  "${PROFILE_PATH}" \
+  > "${ADDON_CTRL_DIR}/profile-configmap.yaml"
+
+## Infra configurations ConfigMap
+CONFIGMAP_NAME="infra-configs"
+PROFILE_REPO_URL="${FLEET_REPO_URL}"
+PROFILE_PATH="${INFRA_CONFIGS_PATH}"
+create_profile_configmap \
+  "${CONFIGMAP_NAME}" \
+  "${PROFILE_REPO_URL}" \
+  "${PROFILE_PATH}" \
+  > "${ADDON_CONFIG_DIR}/profile-configmap.yaml"
+
+## Managed resources ConfigMap
+CONFIGMAP_NAME="managed-resources"
+PROFILE_REPO_URL="${FLEET_REPO_URL}"
+PROFILE_PATH="${MANAGED_RESOURCES_PATH}"
+create_profile_configmap \
+  "${CONFIGMAP_NAME}" \
+  "${PROFILE_REPO_URL}" \
+  "${PROFILE_PATH}" \
+  > "${RESOURCES_DIR}/profile-configmap.yaml"
+
+## Managed resources namespace
+kubectl create ns ${CONFIGMAP_NAME} \
+    -o yaml \
+    --dry-run=client \
+    > "${RESOURCES_DIR}/namespace.yaml"
+
+### Copy secrets for Git repos from `flux-system` to `managed-resources` namespace
+clone_secret_to_new_ns_stdout \
+  flux-system \
+  flux-system \
+  "${CONFIGMAP_NAME}" | \
+encrypt_secret_from_stdin \
+  "${PUBLIC_KEY}" \
+> "${RESOURCES_DIR}/secret-flux-system.yaml"
+
+clone_secret_to_new_ns_stdout \
+  fleet-repo \
+  flux-system \
+  "${CONFIGMAP_NAME}" | \
+encrypt_secret_from_stdin \
+  "${PUBLIC_KEY}" \
+> "${RESOURCES_DIR}/secret-fleet-repo.yaml"
+
+clone_secret_to_new_ns_stdout \
+  sw-catalogs \
+  flux-system \
+  "${CONFIGMAP_NAME}" | \
+encrypt_secret_from_stdin \
+  "${PUBLIC_KEY}" \
+> "${RESOURCES_DIR}/secret-sw-catalogs.yaml"
+
+## Apps ConfigMap
+CONFIGMAP_NAME="apps"
+PROFILE_REPO_URL="${FLEET_REPO_URL}"
+PROFILE_PATH="${APPS_PATH}"
+create_profile_configmap \
+  "${CONFIGMAP_NAME}" \
+  "${PROFILE_REPO_URL}" \
+  "${PROFILE_PATH}" \
+  > "${APPS_DIR}/profile-configmap.yaml"
diff --git a/installers/mgmt-cluster/flux/scripts/helper-functions.rc b/installers/mgmt-cluster/flux/scripts/helper-functions.rc
new file mode 100644 (file)
index 0000000..adc326d
--- /dev/null
@@ -0,0 +1,34 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+
+# Helper function to encrypt secrets in-place in manifest file
+function encrypt_secret_inplace() {
+  local FILE="$1"
+  local AGE_KEY_NAME=${AGE_KEY_NAME_MGMT:-"$2"}
+
+  # Load the contents of both keys
+  local PUBLIC_KEY=$(<"${CREDENTIALS_DIR}/${AGE_KEY_NAME}.pub")
+  # local PRIVATE_KEY=$(<"${CREDENTIALS_DIR}/${AGE_KEY_NAME}.key")
+
+  sops \
+    --age=${PUBLIC_KEY} \
+    --encrypt \
+    --encrypted-regex '^(data|stringData)$' \
+    --in-place "${FILE}"
+}
diff --git a/installers/mgmt-cluster/flux/scripts/library/functions.sh b/installers/mgmt-cluster/flux/scripts/library/functions.sh
new file mode 100755 (executable)
index 0000000..638a1d2
--- /dev/null
@@ -0,0 +1,91 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+BLUE='\033[0;34m'
+CYAN='\033[0;36m'
+RESET='\033[0m'
+
+# Colored messages (blue is the default)
+# Examples:
+#   m "hello world"
+#   m "hello world" "$GREEN"
+function m() {
+  local COLOR=${2:-$BLUE}
+  echo -e "$COLOR$1$RESET"
+}
+
+function copy_function() {
+  local ORIG_FUNC=$(declare -f $1)
+  local NEWNAME_FUNC="$2${ORIG_FUNC#$1}"
+  eval "$NEWNAME_FUNC"
+}
+
+function replace_text() {
+  local FILE=$1
+  local START=$2
+  local END=$3
+  local NEW=$4
+  local T=$(mktemp)
+  head -n $((START-1)) "$FILE" > "$T"
+  echo "$NEW" >> "$T"
+  tail -n +$((END+1)) "$FILE" >> "$T"
+  mv "$T" "$FILE"
+}
+
+function insert_text() {
+  local FILE=$1
+  local START=$2
+  local NEW=$3
+  local T=$(mktemp)
+  head -n $((START-1)) "$FILE" > "$T"
+  echo "$NEW" >> "$T"
+  tail -n +$START "$FILE" >> "$T"
+  mv "$T" "$FILE"
+}
+
+function remove_text() {
+  local FILE=$1
+  local START=$2
+  local END=$3
+  local T=$(mktemp)
+  head -n $((START-1)) "$FILE" > "$T"
+  tail -n +$((END+1)) "$FILE" >> "$T"
+  mv "$T" "$FILE"
+}
+
+function envsubst_cp() {
+  local FROM_FILE=$1
+  local TO_FILE=$2
+  mkdir --parents "$(dirname "$TO_FILE")"
+  cat "$FROM_FILE" | envsubst > "$TO_FILE"
+}
+
+function envsubst_dir() {
+  local FROM_DIR=$1
+  local TO_DIR=$2
+  rm --recursive --force "$TO_DIR"
+  mkdir --parents "$TO_DIR"
+  pushd "$FROM_DIR" > /dev/null
+  local F
+  find . -type f | while read F; do
+    envsubst_cp "$F" "$TO_DIR/$F"
+  done
+  popd > /dev/null
+}
diff --git a/installers/mgmt-cluster/flux/scripts/library/trap.sh b/installers/mgmt-cluster/flux/scripts/library/trap.sh
new file mode 100755 (executable)
index 0000000..2a1156d
--- /dev/null
@@ -0,0 +1,48 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+function goodbye() {
+  local DURATION=$(date --date=@$(( "$(date +%s)" - "$TRAP_START_TIME" )) --utc +%T)
+  local CODE=$1
+  cd "$TRAP_DIR"
+  if [ "$CODE" == 0 ]; then
+    m "$(realpath --relative-to="$HERE" "$0") succeeded! $DURATION" "$GREEN"
+  elif [ "$CODE" == abort ]; then
+    m "Aborted $(realpath --relative-to="$HERE" "$0")! $DURATION" "$RED"
+  else
+    m "Oh no! $(realpath --relative-to="$HERE" "$0") failed! $DURATION" "$RED"
+  fi
+}
+
+function trap_EXIT() {
+  local ERR=$?
+  goodbye "$ERR"
+  exit "$ERR"
+}
+
+function trap_INT() {
+  goodbye abort
+  trap - EXIT
+  exit 1
+}
+
+TRAP_DIR=$PWD
+TRAP_START_TIME=$(date +%s)
+
+trap trap_INT INT
+
+trap trap_EXIT EXIT
diff --git a/installers/mgmt-cluster/flux/scripts/mgmt-cluster-bootstrap.sh b/installers/mgmt-cluster/flux/scripts/mgmt-cluster-bootstrap.sh
new file mode 100755 (executable)
index 0000000..9cbda51
--- /dev/null
@@ -0,0 +1,41 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e -o pipefail
+
+export HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+source "${HERE}/library/functions.sh"
+source "${HERE}/library/trap.sh"
+
+
+# Bootstrap
+REPO=fleet-osm
+GIT_PATH=./clusters/_management
+GIT_BRANCH=main
+GIT_HTTP_URL=${GITEA_HTTP_URL}/${GITEA_STD_USERNAME}/${REPO}.git
+flux bootstrap git \
+    --url=${GIT_HTTP_URL} \
+    --allow-insecure-http=true \
+    --username=${GITEA_STD_USERNAME} \
+    --password="${GITEA_STD_USER_PASS}" \
+    --token-auth=true \
+    --branch=${GIT_BRANCH} \
+    --path=${GIT_PATH}
+
+# Check if successful
+flux check
diff --git a/installers/mgmt-cluster/flux/scripts/watch-mgmt-cluster.sh b/installers/mgmt-cluster/flux/scripts/watch-mgmt-cluster.sh
new file mode 100755 (executable)
index 0000000..f934ee8
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+
+watch "kubectl get managed; kubectl get kustomizations -A; kubectl get helmreleases -A"
diff --git a/installers/mgmt-cluster/flux/templates/fleet/clusters/_management/apps.yaml b/installers/mgmt-cluster/flux/templates/fleet/clusters/_management/apps.yaml
new file mode 100644 (file)
index 0000000..607b8c9
--- /dev/null
@@ -0,0 +1,41 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: apps
+  namespace: flux-system
+  labels:
+    osm_profile_type: apps
+spec:
+  interval: 10m0s
+  dependsOn:
+    - name: infra-configs
+  sourceRef:
+    kind: GitRepository
+    name: fleet-repo
+  path: ${APPS_PATH}
+  prune: true
+  wait: true
+  timeout: 5m0s
+  # Decryption configuration starts here
+  decryption:
+    provider: sops
+    secretRef:
+      name: sops-age
diff --git a/installers/mgmt-cluster/flux/templates/fleet/clusters/_management/fleet-repo.yaml b/installers/mgmt-cluster/flux/templates/fleet/clusters/_management/fleet-repo.yaml
new file mode 100644 (file)
index 0000000..4f70cd7
--- /dev/null
@@ -0,0 +1,30 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: source.toolkit.fluxcd.io/v1
+kind: GitRepository
+metadata:
+  name: fleet-repo
+  namespace: flux-system
+spec:
+  interval: 1m0s
+  ref:
+    branch: main
+  secretRef:
+    name: fleet-repo
+  url: ${FLEET_REPO_URL}
diff --git a/installers/mgmt-cluster/flux/templates/fleet/clusters/_management/infra-configs.yaml b/installers/mgmt-cluster/flux/templates/fleet/clusters/_management/infra-configs.yaml
new file mode 100644 (file)
index 0000000..d2879eb
--- /dev/null
@@ -0,0 +1,49 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: infra-configs
+  namespace: flux-system
+  labels:
+    osm_profile_type: infra-configs
+spec:
+  dependsOn:
+    - name: infra-controllers
+  interval: 1h
+  retryInterval: 1m
+  timeout: 5m
+  sourceRef:
+    kind: GitRepository
+    name: fleet-repo
+  path: ${INFRA_CONFIGS_PATH}
+  prune: true
+  # Decryption configuration starts here
+  decryption:
+    provider: sops
+    secretRef:
+      name: sops-age
+  # patches:
+  #   - patch: |
+  #       - op: replace
+  #         path: /spec/acme/server
+  #         value: https://acme-v02.api.letsencrypt.org/directory
+  #     target:
+  #       kind: ClusterIssuer
+  #       name: letsencrypt
diff --git a/installers/mgmt-cluster/flux/templates/fleet/clusters/_management/infra-controllers.yaml b/installers/mgmt-cluster/flux/templates/fleet/clusters/_management/infra-controllers.yaml
new file mode 100644 (file)
index 0000000..671afc8
--- /dev/null
@@ -0,0 +1,40 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: infra-controllers
+  namespace: flux-system
+  labels:
+    osm_profile_type: infra-controllers
+spec:
+  interval: 1h
+  retryInterval: 1m
+  timeout: 5m
+  sourceRef:
+    kind: GitRepository
+    name: fleet-repo
+  path: ${INFRA_CONTROLLERS_PATH}
+  prune: true
+  wait: true
+  # Decryption configuration starts here
+  decryption:
+    provider: sops
+    secretRef:
+      name: sops-age
diff --git a/installers/mgmt-cluster/flux/templates/fleet/clusters/_management/kustomization.yaml b/installers/mgmt-cluster/flux/templates/fleet/clusters/_management/kustomization.yaml
new file mode 100644 (file)
index 0000000..6e3c9af
--- /dev/null
@@ -0,0 +1,36 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
+resources:
+  # Repos
+  - fleet-repo.yaml
+  - sw-catalogs-repo.yaml
+
+  # Base cluster structure (CRDs, operators and their configs)
+  - infra-controllers.yaml
+  - infra-configs.yaml
+
+  # Managed resources
+  - managed-resources.yaml
+
+  # Managed apps
+  - apps.yaml
+
+  # Adds also the `flux-system` folder to preserve bootstrap structure
+  - flux-system
diff --git a/installers/mgmt-cluster/flux/templates/fleet/clusters/_management/managed-resources.yaml b/installers/mgmt-cluster/flux/templates/fleet/clusters/_management/managed-resources.yaml
new file mode 100644 (file)
index 0000000..2d59cc9
--- /dev/null
@@ -0,0 +1,52 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# Namespace
+# apiVersion: v1
+# kind: Namespace
+# metadata:
+#   name: managed-resources
+
+---
+# Managed resources
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: managed-resources
+  namespace: flux-system
+  labels:
+    osm_profile_type: managed-resources
+spec:
+  # interval: 10m0s
+  interval: 7m0s
+  dependsOn:
+    - name: infra-configs
+  sourceRef:
+    kind: GitRepository
+    name: fleet-repo
+  path: ${MANAGED_RESOURCES_PATH}
+  prune: true
+  wait: true
+  # timeout: 5m0s
+  timeout: 7m0s
+  retryInterval: 2m0s
+  # Decryption configuration starts here
+  decryption:
+    provider: sops
+    secretRef:
+      name: sops-age
diff --git a/installers/mgmt-cluster/flux/templates/fleet/clusters/_management/sw-catalogs-repo.yaml b/installers/mgmt-cluster/flux/templates/fleet/clusters/_management/sw-catalogs-repo.yaml
new file mode 100644 (file)
index 0000000..75bc138
--- /dev/null
@@ -0,0 +1,30 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: source.toolkit.fluxcd.io/v1
+kind: GitRepository
+metadata:
+  name: sw-catalogs
+  namespace: flux-system
+spec:
+  interval: 1m0s
+  ref:
+    branch: main
+  secretRef:
+    name: sw-catalogs
+  url: ${SW_CATALOGS_REPO_URL}
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/apps/jenkins/manifests/bitnamicharts-repo.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/apps/jenkins/manifests/bitnamicharts-repo.yaml
new file mode 100644 (file)
index 0000000..354b837
--- /dev/null
@@ -0,0 +1,27 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: source.toolkit.fluxcd.io/v1beta2
+kind: HelmRepository
+metadata:
+  name: bitnamicharts
+  namespace: jenkins
+spec:
+  interval: 10m0s
+  type: oci
+  url: oci://registry-1.docker.io/bitnamicharts
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/apps/jenkins/manifests/jenkins-hr.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/apps/jenkins/manifests/jenkins-hr.yaml
new file mode 100644 (file)
index 0000000..c87a95e
--- /dev/null
@@ -0,0 +1,37 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: helm.toolkit.fluxcd.io/v2beta1
+kind: HelmRelease
+metadata:
+  name: jenkins
+  namespace: jenkins
+spec:
+  chart:
+    spec:
+      chart: jenkins
+      reconcileStrategy: ChartVersion
+      sourceRef:
+        kind: HelmRepository
+        name: bitnamicharts
+        namespace: jenkins
+  install:
+    createNamespace: true
+  interval: 3m0s
+  targetNamespace: jenkins
+  values: {}
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/apps/jenkins/templates/jenkins-ks.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/apps/jenkins/templates/jenkins-ks.yaml
new file mode 100644 (file)
index 0000000..bbf4d7b
--- /dev/null
@@ -0,0 +1,31 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: jenkins
+  namespace: jenkins
+spec:
+  interval: 1h0m0s
+  path: ./apps/jenkins/manifests
+  prune: true
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/apps/jenkins/templates/jenkins-ns.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/apps/jenkins/templates/jenkins-ns.yaml
new file mode 100644 (file)
index 0000000..ca2fff8
--- /dev/null
@@ -0,0 +1,24 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: v1
+kind: Namespace
+metadata:
+  creationTimestamp: null
+  name: jenkins
+spec: {}
+status: {}
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/aks/manifests/aks.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/aks/manifests/aks.yaml
new file mode 100644 (file)
index 0000000..b27b714
--- /dev/null
@@ -0,0 +1,53 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: containerservice.azure.upbound.io/v1beta1
+kind: KubernetesCluster
+metadata:
+  name: ${cluster_resource_name}
+spec:
+  forProvider:
+    # Force K8s version
+    # kubernetesVersion: 1.26
+    defaultNodePool:
+    - name: default
+      nodeCount: 1
+      # nodeCount: ${node_count}
+      # vmSize: Standard_D2_v2
+      vmSize: ${vm_size}
+    dnsPrefix: pref-${cluster_resource_name}
+    identity:
+    - type: SystemAssigned
+    location: ${cluster_location}
+    resourceGroupName: ${rg_name}
+    # # In case we had created the RG with CrossPlane:
+    # resourceGroupNameSelector:
+    #   matchLabels:
+    #     testing.upbound.io/example-name: example
+    # tags:
+    #   Environment: Production
+  publishConnectionDetailsTo:
+    # name: kubeconfig-myakscluster01
+    name: kubeconfig-${cluster_resource_name}
+  writeConnectionSecretToRef:
+    # name: kubeconfig-myakscluster01
+    name: kubeconfig-${cluster_resource_name}
+    # namespace: crossplane-system
+    namespace: managed-resources
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/aks/templates/aks01.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/aks/templates/aks01.yaml
new file mode 100644 (file)
index 0000000..ad3e23d
--- /dev/null
@@ -0,0 +1,92 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# TEMPLATE_PARAMETERS:
+# ===================
+#
+# CLUSTER_KUSTOMIZATION_NAME: Name of the Kustomization in the management cluster representing the AKS cluster.
+# - Alternatively, it can be patched at:
+#   .metadata.name
+#   .metadata.labels.cluster
+#   .spec.commonMetadata.labels.cluster
+#
+# PARAMETERS TO PATCH:
+# ===================
+#
+# .spec.postBuild.substitute.providerconfig_name: Name of the Azure ProviderConfig to use to create the AKS cluster.
+# .spec.postBuild.substitute.cluster_name: Name of the cluster in the target cloud. It may differ from `CLUSTER_KUSTOMIZATION_NAME` since naming restrictions are often different from K8s resource naming restrictions (e.g., hyphens vs. underscores).
+# .spec.postBuild.substitute.k8s_version: Kubernetes version.
+# .spec.postBuild.substitute.node_count: Number of worker nodes.
+# .spec.postBuild.substitute.vm_size: Flavor of worker node VMs.
+# .spec.postBuild.substitute.cluster_location: Target cluster region.
+# .spec.postBuild.substitute.rg_name: Target Resource Group.
+
+# Cluster resource
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: ${CLUSTER_KUSTOMIZATION_NAME}
+  namespace: managed-resources
+  labels:
+    cluster: ${CLUSTER_KUSTOMIZATION_NAME}
+spec:
+  commonMetadata:
+    labels:
+      cluster: ${CLUSTER_KUSTOMIZATION_NAME}
+  interval: 1h
+  retryInterval: 1m
+  timeout: 5m
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
+  path: ./cloud-resources/aks/manifests
+  prune: true
+  wait: true
+  # force: true
+  patches:
+    - patch: |-
+        apiVersion: containerservice.azure.upbound.io/v1beta1
+        kind: KubernetesCluster
+        metadata:
+          name: ${cluster_resource_name}
+        spec:
+          forProvider:
+            # Comment for latest version (creation only):
+            kubernetesVersion: "${k8s_version}"
+
+            defaultNodePool:
+            - name: default
+              # nodeCount: 1  # Edit to change no. workers
+              nodeCount: ${node_count}
+
+              # Comment for latest version (creation only):
+              orchestratorVersion: "${k8s_version}"
+              vmSize: ${vm_size}
+  # Input parameters
+  postBuild:
+    substitute:
+      providerconfig_name: default
+      cluster_resource_name: ${CLUSTER_KUSTOMIZATION_NAME}
+      cluster_name: myakscluster01
+      k8s_version: "'1.27'"
+      node_count: "1"
+      vm_size: Standard_D2_v2
+      cluster_location: West Europe
+      # AKS only
+      rg_name: CloudNative-OSM
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/azure-mysql/manifests/dbformysql.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/azure-mysql/manifests/dbformysql.yaml
new file mode 100644 (file)
index 0000000..e50d695
--- /dev/null
@@ -0,0 +1,97 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: dbformysql.azure.upbound.io/v1beta1
+kind: Database
+metadata:
+  # annotations:
+  #   meta.upbound.io/example-id: dbformysql/v1beta1/database
+  labels:
+    testing.upbound.io/name: ${database_name}
+  name: ${database_name}
+spec:
+  forProvider:
+    charset: utf8
+    collation: utf8_unicode_ci
+    resourceGroupName: ${resource_group}
+    # resourceGroupNameSelector:
+    #   matchLabels:
+    #     testing.upbound.io/name: ${database_name}
+    serverNameSelector:
+      matchLabels:
+        testing.upbound.io/name: ${database_name}
+
+---
+
+apiVersion: dbformysql.azure.upbound.io/v1beta1
+kind: Server
+metadata:
+  # annotations:
+  #   meta.upbound.io/example-id: dbformysql/v1beta1/database
+  labels:
+    testing.upbound.io/name: ${database_name}
+  name: server-${database_name}
+spec:
+  forProvider:
+    administratorLogin: ${admin_user}
+    administratorLoginPasswordSecretRef:
+      key: key
+      name: ${database_secret_name}
+      namespace: ${database_secret_namespace}
+    autoGrowEnabled: true
+    backupRetentionDays: 7
+    geoRedundantBackupEnabled: true
+    infrastructureEncryptionEnabled: true
+    location: ${region}
+    publicNetworkAccessEnabled: false
+    resourceGroupName: ${resource_group}
+    # resourceGroupNameSelector:
+    #   matchLabels:
+    #     testing.upbound.io/name: ${database_name}
+    # skuName: GP_Gen5_2
+    skuName: ${sku_name:=GP_Gen5_2}
+    sslEnforcementEnabled: true
+    sslMinimalTlsVersionEnforced: TLS1_2
+    # storageMb: 5120
+    storageMb: ${storage_mb:=5120}
+    version: "5.7"
+
+# ---
+
+# apiVersion: v1
+# kind: Secret
+# metadata:
+#   name: example-secret
+#   namespace: upbound-system
+# type: Opaque
+# stringData:
+#   example-key: dGVzdFBhc3N3b3JkITEyMw==
+
+# ---
+
+# apiVersion: azure.upbound.io/v1beta1
+# kind: ResourceGroup
+# metadata:
+#   annotations:
+#     meta.upbound.io/example-id: dbformysql/v1beta1/database
+#   labels:
+#     testing.upbound.io/name: ${database_name}
+#   name: ${database_name}
+# spec:
+#   forProvider:
+#     location: West Europe
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/azure-mysql/templates/azure-mysql01.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/azure-mysql/templates/azure-mysql01.yaml
new file mode 100644 (file)
index 0000000..3150e1b
--- /dev/null
@@ -0,0 +1,47 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# Database resource
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: azure-mysql01
+  namespace: managed-resources
+spec:
+  interval: 1h
+  retryInterval: 1m
+  timeout: 5m
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
+  path: ./cloud-resources/azure-mysql/resources
+  prune: true
+  wait: true
+
+  # Input parameters
+  postBuild:
+    substitute:
+      database_name: azure-mysql01
+      resource_group: CloudNative-InfraMgmt-CTIO
+      region: West Europe
+      admin_user: MyDemoUser123
+      database_secret_name: database-secret
+      database_secret_namespace: managed-resources
+      # sku_name: GP_Gen5_2
+      # storage_mb: 5120
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/eks/manifests/eks-cluster/eks-cluster.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/eks/manifests/eks-cluster/eks-cluster.yaml
new file mode 100644 (file)
index 0000000..59b0b44
--- /dev/null
@@ -0,0 +1,67 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: eks.aws.upbound.io/v1beta1
+kind: Cluster
+metadata:
+  name: ${cluster_resource_name}-cluster
+  annotations:
+    crossplane.io/external-name: ${cluster_name}
+  labels:
+    provider: aws
+    cluster: ${cluster_resource_name}
+    type: cluster
+spec:
+  forProvider:
+    region: ${cluster_location}
+    version: ${k8s_version}
+    roleArnSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+        type: cluster
+    vpcConfig:
+      - endpointPrivateAccess: true
+        endpointPublicAccess: true
+        subnetIdSelector:
+          matchLabels:
+            provider: aws
+            cluster: ${cluster_resource_name}
+            type: subnet
+            access: private
+  publishConnectionDetailsTo:
+    name: kubeconfig-${cluster_resource_name}
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
+
+---
+apiVersion: eks.aws.upbound.io/v1beta1
+kind: ClusterAuth
+metadata:
+  name: ${cluster_resource_name}-clusterauth
+spec:
+  forProvider:
+    region: ${cluster_location}
+    clusterName: ${cluster_name}
+  writeConnectionSecretToRef:
+    namespace: managed-resources
+    name: kubeconfig-${cluster_resource_name}
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/eks/manifests/eks-cluster/nodegroup.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/eks/manifests/eks-cluster/nodegroup.yaml
new file mode 100644 (file)
index 0000000..f25f1d9
--- /dev/null
@@ -0,0 +1,55 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: eks.aws.upbound.io/v1beta1
+kind: NodeGroup
+metadata:
+  name: ${cluster_resource_name}-nodegroup
+  annotations:
+    crossplane.io/external-name: ${cluster_name}-nodegroup
+  labels:
+    provider: aws
+    cluster: ${cluster_resource_name}
+spec:
+  forProvider:
+    region: ${cluster_location}
+    clusterNameSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+        type: cluster
+    nodeRoleArnSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+        type: ec2
+    subnetIdSelector:
+        matchLabels:
+          type: subnet
+          access: private
+    scalingConfig:
+      - minSize: 1
+        desiredSize: ${node_count}
+        maxSize: 10
+    diskSize: 30
+    instanceTypes:
+      - ${vm_size}
+    tags:
+      Name: ${cluster_name}
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/eks/manifests/iam/role-policy-attachment.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/eks/manifests/iam/role-policy-attachment.yaml
new file mode 100644 (file)
index 0000000..3e61f81
--- /dev/null
@@ -0,0 +1,136 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: iam.aws.upbound.io/v1beta1
+kind: RolePolicyAttachment
+metadata:
+  name: ${cluster_resource_name}-cluster
+  labels:
+    provider: aws
+    cluster: ${cluster_resource_name}
+spec:
+  forProvider:
+    policyArn: arn:aws:iam::aws:policy/AmazonEKSClusterPolicy
+    roleSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+        type: cluster
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
+
+---
+apiVersion: iam.aws.upbound.io/v1beta1
+kind: RolePolicyAttachment
+metadata:
+  name: ${cluster_resource_name}-service
+  labels:
+    provider: aws
+    cluster: ${cluster_resource_name}
+spec:
+  forProvider:
+    policyArn: arn:aws:iam::aws:policy/AmazonEKSServicePolicy
+    roleSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+        type: cluster
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
+
+---
+apiVersion: iam.aws.upbound.io/v1beta1
+kind: RolePolicyAttachment
+metadata:
+  name: ${cluster_resource_name}-vpccontroller
+  labels:
+    provider: aws
+    cluster: ${cluster_resource_name}
+spec:
+  forProvider:
+    policyArn: arn:aws:iam::aws:policy/AmazonEKSVPCResourceController
+    roleSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+        type: cluster
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
+
+---
+apiVersion: iam.aws.upbound.io/v1beta1
+kind: RolePolicyAttachment
+metadata:
+  name: ${cluster_resource_name}-worker
+  labels:
+    provider: aws
+    cluster: ${cluster_resource_name}
+spec:
+  forProvider:
+    policyArn: arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy
+    roleSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+        type: ec2
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
+
+---
+apiVersion: iam.aws.upbound.io/v1beta1
+kind: RolePolicyAttachment
+metadata:
+  name: ${cluster_resource_name}-cni
+  labels:
+    provider: aws
+    cluster: ${cluster_resource_name}
+spec:
+  forProvider:
+    policyArn: arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy
+    roleSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+        type: ec2
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
+
+---
+apiVersion: iam.aws.upbound.io/v1beta1
+kind: RolePolicyAttachment
+metadata:
+  name: ${cluster_resource_name}-registry
+  labels:
+    provider: aws
+    cluster: ${cluster_resource_name}
+spec:
+  forProvider:
+    policyArn: arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
+    roleSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+        type: ec2
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/eks/manifests/iam/roles.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/eks/manifests/iam/roles.yaml
new file mode 100644 (file)
index 0000000..03ae559
--- /dev/null
@@ -0,0 +1,84 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: iam.aws.upbound.io/v1beta1
+kind: Role
+metadata:
+  name: ${cluster_resource_name}-eks
+  annotations:
+    crossplane.io/external-name: ${cluster_name}-masterRole
+  labels:
+    provider: aws
+    cluster: eks
+    type: cluster
+spec:
+  forProvider:
+    assumeRolePolicy: |
+      {
+        "Version": "2012-10-17",
+        "Statement": [
+            {
+                "Effect": "Allow",
+                "Principal": {
+                    "Service": [
+                        "eks.amazonaws.com"
+                    ]
+                },
+                "Action": [
+                    "sts:AssumeRole"
+                ]
+            }
+        ]
+      }
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
+
+---
+apiVersion: iam.aws.upbound.io/v1beta1
+kind: Role
+metadata:
+  name: ${cluster_resource_name}-ec2
+  annotations:
+    crossplane.io/external-name: ${cluster_name}-nodeRole
+  labels:
+    provider: aws
+    cluster: eks
+    type: ec2
+spec:
+  forProvider:
+    assumeRolePolicy: |
+      {
+        "Version": "2012-10-17",
+        "Statement": [
+            {
+                "Effect": "Allow",
+                "Principal": {
+                    "Service": [
+                        "ec2.amazonaws.com"
+                    ]
+                },
+                "Action": [
+                    "sts:AssumeRole"
+                ]
+            }
+        ]
+      }
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/eks/manifests/network/gateways.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/eks/manifests/network/gateways.yaml
new file mode 100644 (file)
index 0000000..96255f8
--- /dev/null
@@ -0,0 +1,89 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: ec2.aws.upbound.io/v1beta1
+kind: EIP
+metadata:
+  name: ${cluster_resource_name}-eip
+  labels:
+    provider: aws
+    cluster: ${cluster_resource_name}
+    type: eip
+spec:
+  forProvider:
+    region: ${cluster_location}
+    domain: vpc
+    tags:
+      key: Name
+      value: ${cluster_name}-eip
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
+
+---
+apiVersion: ec2.aws.upbound.io/v1beta1
+kind: InternetGateway
+metadata:
+  name: ${cluster_resource_name}-igw
+  labels:
+    provider: aws
+    cluster: ${cluster_resource_name}
+    type: igw
+spec:
+  forProvider:
+    region: ${cluster_location}
+    vpcIdSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+    tags:
+      Name: ${cluster_name}-igw
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
+
+---
+apiVersion: ec2.aws.upbound.io/v1beta1
+kind: NATGateway
+metadata:
+  name: ${cluster_resource_name}-natgw
+  labels:
+    provider: aws
+    cluster: ${cluster_resource_name}
+    type: natgw
+spec:
+  forProvider:
+    region: ${cluster_location}
+    connectivityType: public
+    allocationIdSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+        type: eip
+    subnetIdSelector:
+      matchLabels:
+        type: subnet
+        provider: aws
+        cluster: ${cluster_resource_name}
+        zone: ${cluster_location}a
+        access: public
+    tags:
+      Name: ${cluster_name}-natgw
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/eks/manifests/network/routes.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/eks/manifests/network/routes.yaml
new file mode 100644 (file)
index 0000000..b9d57ba
--- /dev/null
@@ -0,0 +1,228 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: ec2.aws.upbound.io/v1beta2
+kind: Route
+metadata:
+  name: ${cluster_resource_name}-public-route
+  labels:
+    provider: aws
+    cluster: ${cluster_resource_name}
+spec:
+  forProvider:
+    region: ${cluster_location}
+    destinationCidrBlock: 0.0.0.0/0
+    gatewayIdSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+        type: igw
+    routeTableIdSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+        type: routetable
+        access: public
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
+
+---
+apiVersion: ec2.aws.upbound.io/v1beta2
+kind: Route
+metadata:
+  name: ${cluster_resource_name}-private-route
+  labels:
+    provider: aws
+    cluster: ${cluster_resource_name}
+spec:
+  forProvider:
+    region: ${cluster_location}
+    destinationCidrBlock: 0.0.0.0/0
+    natGatewayIdSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+        type: natgw
+    routeTableIdSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+        type: routetable
+        access: private
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
+
+---
+apiVersion: ec2.aws.upbound.io/v1beta1
+kind: RouteTable
+metadata:
+  name: ${cluster_resource_name}-public-route-table
+  labels:
+    provider: aws
+    cluster: ${cluster_resource_name}
+    type: routetable
+    access: public
+spec:
+  forProvider:
+    region: ${cluster_location}
+    vpcIdSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+    tags:
+      Name: ${cluster_name}-public-route-table
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
+
+---
+apiVersion: ec2.aws.upbound.io/v1beta1
+kind: RouteTable
+metadata:
+  name: ${cluster_resource_name}-private-route-table
+  labels:
+    provider: aws
+    cluster: ${cluster_resource_name}
+    type: routetable
+    access: private
+spec:
+  forProvider:
+    region: ${cluster_location}
+    vpcIdSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+    tags:
+      Name: ${cluster_name}-private-route-table
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
+
+---
+apiVersion: ec2.aws.upbound.io/v1beta1
+kind: RouteTableAssociation
+metadata:
+  name: ${cluster_resource_name}-public-route-association-1a
+  labels:
+    provider: aws
+    cluster: ${cluster_resource_name}
+spec:
+  forProvider:
+    region: ${cluster_location}
+    subnetIdSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+        type: subnet
+        access: public
+        zone: ${cluster_location}a
+    routeTableIdSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+        type: routetable
+        access: public
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
+
+---
+apiVersion: ec2.aws.upbound.io/v1beta1
+kind: RouteTableAssociation
+metadata:
+  name: ${cluster_resource_name}-public-route-association-1b
+  labels:
+    provider: aws
+    cluster: ${cluster_resource_name}
+spec:
+  forProvider:
+    region: ${cluster_location}
+    subnetIdSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+        type: subnet
+        access: public
+        zone: ${cluster_location}b
+    routeTableIdSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+        type: routetable
+        access: public
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
+
+---
+apiVersion: ec2.aws.upbound.io/v1beta1
+kind: RouteTableAssociation
+metadata:
+  name: ${cluster_resource_name}-private-route-association-1a
+  labels:
+    provider: aws
+    cluster: ${cluster_resource_name}
+spec:
+  forProvider:
+    region: ${cluster_location}
+    subnetIdSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+        type: subnet
+        access: private
+        zone: ${cluster_location}a
+    routeTableIdSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+        type: routetable
+        access: private
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
+
+---
+apiVersion: ec2.aws.upbound.io/v1beta1
+kind: RouteTableAssociation
+metadata:
+  name: ${cluster_resource_name}-private-route-association-1b
+  labels:
+    provider: aws
+    cluster: ${cluster_resource_name}
+spec:
+  forProvider:
+    region: ${cluster_location}
+    subnetIdSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+        type: subnet
+        access: private
+        zone: ${cluster_location}b
+    routeTableIdSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+        type: routetable
+        access: private
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/eks/manifests/network/subnets.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/eks/manifests/network/subnets.yaml
new file mode 100644 (file)
index 0000000..bffbfc3
--- /dev/null
@@ -0,0 +1,130 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: ec2.aws.upbound.io/v1beta1
+kind: Subnet
+metadata:
+  name: ${cluster_resource_name}-public-subnet-${cluster_location}a
+  labels:
+    type: subnet
+    provider: aws
+    cluster: ${cluster_resource_name}
+    zone: ${cluster_location}a
+    access: public
+spec:
+  forProvider:
+    region: ${cluster_location}
+    availabilityZone: ${cluster_location}a
+    cidrBlock: 10.10.0.0/24
+    vpcIdSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+    mapPublicIpOnLaunch: true
+    tags:
+      kubernetes.io/role/elb: "1"
+      Name: ${cluster_name}-public-subnet-${cluster_location}a
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
+
+---
+apiVersion: ec2.aws.upbound.io/v1beta1
+kind: Subnet
+metadata:
+  name: ${cluster_resource_name}-public-subnet-${cluster_location}b
+  labels:
+    type: subnet
+    provider: aws
+    cluster: ${cluster_resource_name}
+    zone: ${cluster_location}b
+    access: public
+spec:
+  forProvider:
+    region: ${cluster_location}
+    availabilityZone: ${cluster_location}b
+    cidrBlock: 10.10.1.0/24
+    vpcIdSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+    mapPublicIpOnLaunch: true
+    tags:
+      kubernetes.io/role/elb: "1"
+      Name: ${cluster_name}-public-subnet-${cluster_location}b
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
+
+---
+apiVersion: ec2.aws.upbound.io/v1beta1
+kind: Subnet
+metadata:
+  name: ${cluster_resource_name}-private-subnet-${cluster_location}a
+  labels:
+    type: subnet
+    provider: aws
+    cluster: ${cluster_resource_name}
+    zone: ${cluster_location}a
+    access: private
+spec:
+  forProvider:
+    region: ${cluster_location}
+    availabilityZone: ${cluster_location}a
+    cidrBlock: 10.10.2.0/24
+    vpcIdSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+    mapPublicIpOnLaunch: false
+    tags:
+      kubernetes.io/role/elb: "1"
+      Name: ${cluster_name}-private-subnet-${cluster_location}a
+      kubernetes.io/cluster/{cluster_name}: shared
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
+
+---
+apiVersion: ec2.aws.upbound.io/v1beta1
+kind: Subnet
+metadata:
+  name: ${cluster_resource_name}-private-subnet-${cluster_location}b
+  labels:
+    type: subnet
+    provider: aws
+    cluster: ${cluster_resource_name}
+    zone: ${cluster_location}b
+    access: private
+spec:
+  forProvider:
+    region: ${cluster_location}
+    availabilityZone: ${cluster_location}b
+    cidrBlock: 10.10.3.0/24
+    vpcIdSelector:
+      matchLabels:
+        provider: aws
+        cluster: ${cluster_resource_name}
+    mapPublicIpOnLaunch: false
+    tags:
+      kubernetes.io/role/elb: "1"
+      Name: ${cluster_name}-private-subnet-${cluster_location}b
+      kubernetes.io/cluster/{cluster_name}: shared
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/eks/manifests/network/vpc.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/eks/manifests/network/vpc.yaml
new file mode 100644 (file)
index 0000000..b643ba3
--- /dev/null
@@ -0,0 +1,36 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: ec2.aws.upbound.io/v1beta1
+kind: VPC
+metadata:
+  name: ${cluster_resource_name}-vpc
+  labels:
+    provider: aws
+    cluster: eks
+spec:
+  forProvider:
+    region: ${cluster_location}
+    cidrBlock: 10.10.0.0/16
+    enableDnsHostnames: true
+    enableDnsSupport: true
+    tags:
+      Name: ${cluster_name}-vpc
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/eks/templates/eks01.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/eks/templates/eks01.yaml
new file mode 100644 (file)
index 0000000..0972827
--- /dev/null
@@ -0,0 +1,71 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# TEMPLATE_PARAMETERS:
+# ===================
+#
+# CLUSTER_KUSTOMIZATION_NAME: Name of the cluster in the management cluster (e.g., for `Kustomization`s).
+# - Alternatively, it can be patched at:
+#   .metadata.name
+#   .metadata.labels.cluster
+#   .spec.commonMetadata.labels.cluster
+#   .spec.postBuild.substitute.cluster_resource_name
+#
+# PARAMETERS TO PATCH:
+# ===================
+#
+# .spec.postBuild.substitute.providerconfig_name: Name of the AWS ProviderConfig to use to create the EKS cluster.
+# .spec.postBuild.substitute.cluster_name: Name of the cluster in the target cloud. It may differ from `CLUSTER_KUSTOMIZATION_NAME` since naming restrictions are often different from K8s resource naming restrictions (e.g., hyphens vs. underscores).
+# .spec.postBuild.substitute.k8s_version: Kubernetes version.
+# .spec.postBuild.substitute.node_count: Number of worker nodes.
+# .spec.postBuild.substitute.vm_size: Flavor of worker node VMs.
+# .spec.postBuild.substitute.cluster_location: Target cluster region.
+
+# Cluster resource
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: ${CLUSTER_KUSTOMIZATION_NAME}
+  namespace: managed-resources
+  labels:
+    cluster: ${CLUSTER_KUSTOMIZATION_NAME}
+spec:
+  commonMetadata:
+    labels:
+      cluster: ${CLUSTER_KUSTOMIZATION_NAME}
+  interval: 1h
+  retryInterval: 1m
+  timeout: 5m
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
+  path: ./cloud-resources/eks/manifests/
+  prune: true
+  # force: true
+  wait: true
+  # Input parameters
+  postBuild:
+    substitute:
+      providerconfig_name: default
+      cluster_resource_name: ${CLUSTER_KUSTOMIZATION_NAME}
+      cluster_name: ekscluster01
+      k8s_version: "'1.28'"
+      node_count: "1"
+      vm_size: t3.medium
+      cluster_location: ap-south-1
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/bootstrap/manifests/namespaces/namespaces.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/bootstrap/manifests/namespaces/namespaces.yaml
new file mode 100644 (file)
index 0000000..4bd715c
--- /dev/null
@@ -0,0 +1,31 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# Remote namespace `flux-system`
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: flux-system
+
+---
+# Remote namespace `managed-resources`
+# - Required for Helm deployments from management cluster
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: managed-resources
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/bootstrap/manifests/secret/secret-template.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/bootstrap/manifests/secret/secret-template.yaml
new file mode 100644 (file)
index 0000000..3a9d7eb
--- /dev/null
@@ -0,0 +1,26 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# Template for creating remote secrets
+apiVersion: v1
+kind: Secret
+metadata:
+  name: ${secret_name}
+  namespace: ${secret_namespace}
+type: Opaque
+stringData: {}
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/bootstrap/templates/remote-cluster-bootstrap.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/bootstrap/templates/remote-cluster-bootstrap.yaml
new file mode 100644 (file)
index 0000000..d138660
--- /dev/null
@@ -0,0 +1,265 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# TEMPLATE PARAMETERS:
+# ===================
+#
+# CLUSTER_KUSTOMIZATION_NAME: Name of the cluster in the management cluster (i.e., the `Kustomization`).
+# CLUSTER_NAME: Name of the cluster in the target cloud. It may differ from `CLUSTER_KUSTOMIZATION_NAME` since naming restrictions are often different from K8s resource naming restrictions (e.g., hyphens vs. underscores).
+# CLUSTER_AGE_SECRET_NAME: Name of the secret in the management cluster that keeps the private key for age/sops in the remote cluster.
+
+# Creates required remote namespaces
+apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
+kind: Kustomization
+metadata:
+  name: ${CLUSTER_KUSTOMIZATION_NAME}-bstrp-ns
+  namespace: managed-resources
+  labels:
+    cluster: ${CLUSTER_KUSTOMIZATION_NAME}
+spec:
+  # interval: 1h
+  interval: 5m
+  retryInterval: 1m
+  timeout: 5m
+  dependsOn:
+    - name: ${CLUSTER_KUSTOMIZATION_NAME}
+  prune: true
+  # wait: true
+  # force: true
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
+  path: ./cloud-resources/flux-remote-bootstrap/bootstrap/manifests/namespaces
+  kubeConfig:
+    secretRef:
+      name: kubeconfig-${CLUSTER_KUSTOMIZATION_NAME}
+      key: kubeconfig
+
+---
+# Creates remote `flux-system.flux-system` secret
+apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
+kind: Kustomization
+metadata:
+  name: ${CLUSTER_KUSTOMIZATION_NAME}-bstrp-secret-flux
+  namespace: managed-resources
+  labels:
+    cluster: ${CLUSTER_KUSTOMIZATION_NAME}
+spec:
+  # interval: 1h
+  interval: 5m
+  retryInterval: 1m
+  timeout: 5m
+  dependsOn:
+    - name: ${CLUSTER_KUSTOMIZATION_NAME}-bstrp-ns
+  prune: true
+  # wait: true
+  force: true
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
+  path: ./cloud-resources/flux-remote-bootstrap/bootstrap/manifests/secret
+  kubeConfig:
+    secretRef:
+      name: kubeconfig-${CLUSTER_KUSTOMIZATION_NAME}
+      key: kubeconfig
+  patches:
+    - patch: |-
+        apiVersion: v1
+        kind: Secret
+        metadata:
+          name: ${secret_name}
+          namespace: ${secret_namespace}
+        stringData:
+          username: ${username}
+          password: ${password}
+  # Inputs:
+  postBuild:
+    substitute:
+      secret_name: flux-system
+      secret_namespace: flux-system
+    substituteFrom:
+      - kind: Secret
+        name: flux-system
+
+---
+# Creates remote `sops-age` secret
+apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
+kind: Kustomization
+metadata:
+  name: ${CLUSTER_KUSTOMIZATION_NAME}-bstrp-secret-sops
+  namespace: managed-resources
+  labels:
+    cluster: ${CLUSTER_KUSTOMIZATION_NAME}
+spec:
+  # interval: 1h
+  interval: 5m
+  retryInterval: 1m
+  timeout: 5m
+  dependsOn:
+    - name: ${CLUSTER_KUSTOMIZATION_NAME}-bstrp-ns
+  prune: true
+  # wait: true
+  force: true
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
+  path: ./cloud-resources/flux-remote-bootstrap/bootstrap/manifests/secret
+  kubeConfig:
+    secretRef:
+      name: kubeconfig-${CLUSTER_KUSTOMIZATION_NAME}
+      key: kubeconfig
+  patches:
+    - patch: |-
+        apiVersion: v1
+        kind: Secret
+        metadata:
+          name: ${secret_name}
+          namespace: ${secret_namespace}
+        stringData:
+          age.agekey: ${agekey}
+  # Inputs:
+  postBuild:
+    substitute:
+      secret_name: sops-age
+      secret_namespace: flux-system
+    substituteFrom:
+      - kind: Secret
+        name: ${CLUSTER_AGE_SECRET_NAME}
+
+---
+# Creates remote `fleet-repo.flux-system` secret
+apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
+kind: Kustomization
+metadata:
+  name: ${CLUSTER_KUSTOMIZATION_NAME}-bstrp-secret-fleet
+  namespace: managed-resources
+  labels:
+    cluster: ${CLUSTER_KUSTOMIZATION_NAME}
+spec:
+  # interval: 1h
+  interval: 5m
+  retryInterval: 1m
+  timeout: 5m
+  dependsOn:
+    - name: ${CLUSTER_KUSTOMIZATION_NAME}-bstrp-ns
+  prune: true
+  # wait: true
+  force: true
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
+  path: ./cloud-resources/flux-remote-bootstrap/bootstrap/manifests/secret
+  kubeConfig:
+    secretRef:
+      name: kubeconfig-${CLUSTER_KUSTOMIZATION_NAME}
+      key: kubeconfig
+  patches:
+    - patch: |-
+        apiVersion: v1
+        kind: Secret
+        metadata:
+          name: ${secret_name}
+          namespace: ${secret_namespace}
+        stringData:
+          username: ${username}
+          password: ${password}
+  # Inputs:
+  postBuild:
+    substitute:
+      secret_name: fleet-repo
+      secret_namespace: flux-system
+    substituteFrom:
+      - kind: Secret
+        name: fleet-repo
+
+---
+# Creates remote `sw-catalogs.flux-system` secret
+apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
+kind: Kustomization
+metadata:
+  name: ${CLUSTER_KUSTOMIZATION_NAME}-bstrp-secret-catalogs
+  namespace: managed-resources
+  labels:
+    cluster: ${CLUSTER_KUSTOMIZATION_NAME}
+spec:
+  # interval: 1h
+  interval: 5m
+  retryInterval: 1m
+  timeout: 5m
+  dependsOn:
+    - name: ${CLUSTER_KUSTOMIZATION_NAME}-bstrp-ns
+  prune: true
+  # wait: true
+  force: true
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
+  path: ./cloud-resources/flux-remote-bootstrap/bootstrap/manifests/secret
+  kubeConfig:
+    secretRef:
+      name: kubeconfig-${CLUSTER_KUSTOMIZATION_NAME}
+      key: kubeconfig
+  patches:
+    - patch: |-
+        apiVersion: v1
+        kind: Secret
+        metadata:
+          name: ${secret_name}
+          namespace: ${secret_namespace}
+        stringData:
+          username: ${username}
+          password: ${password}
+  # Inputs:
+  postBuild:
+    substitute:
+      secret_name: sw-catalogs
+      secret_namespace: flux-system
+    substituteFrom:
+      - kind: Secret
+        name: sw-catalogs
+
+---
+# Remote installation of Flux controller (to let the cluster be autonomous)
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: ${CLUSTER_KUSTOMIZATION_NAME}-bstrp-fluxctrl
+  namespace: managed-resources
+  labels:
+    cluster: ${CLUSTER_KUSTOMIZATION_NAME}
+spec:
+  # Tune interval as needed
+  interval: 10m0s
+  path: ./clusters/${CLUSTER_KUSTOMIZATION_NAME}/flux-system
+  dependsOn:
+    - name: ${CLUSTER_KUSTOMIZATION_NAME}-bstrp-secret-flux
+  # Avoids removing resources unexpectedly
+  prune: false
+  sourceRef:
+    kind: GitRepository
+    name: flux-system
+    namespace: flux-system
+  kubeConfig:
+    secretRef:
+      name: kubeconfig-${CLUSTER_KUSTOMIZATION_NAME}
+      key: kubeconfig
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/apps.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/apps.yaml
new file mode 100644 (file)
index 0000000..607b8c9
--- /dev/null
@@ -0,0 +1,41 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: apps
+  namespace: flux-system
+  labels:
+    osm_profile_type: apps
+spec:
+  interval: 10m0s
+  dependsOn:
+    - name: infra-configs
+  sourceRef:
+    kind: GitRepository
+    name: fleet-repo
+  path: ${APPS_PATH}
+  prune: true
+  wait: true
+  timeout: 5m0s
+  # Decryption configuration starts here
+  decryption:
+    provider: sops
+    secretRef:
+      name: sops-age
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/fleet-repo.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/fleet-repo.yaml
new file mode 100644 (file)
index 0000000..4f70cd7
--- /dev/null
@@ -0,0 +1,30 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: source.toolkit.fluxcd.io/v1
+kind: GitRepository
+metadata:
+  name: fleet-repo
+  namespace: flux-system
+spec:
+  interval: 1m0s
+  ref:
+    branch: main
+  secretRef:
+    name: fleet-repo
+  url: ${FLEET_REPO_URL}
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/flux-system/gotk-components.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/flux-system/gotk-components.yaml
new file mode 100644 (file)
index 0000000..50cc8d3
--- /dev/null
@@ -0,0 +1,8046 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# This manifest was generated by flux. DO NOT EDIT.
+# Flux Version: v2.1.2
+# Components: source-controller,kustomize-controller,helm-controller,notification-controller
+apiVersion: v1
+kind: Namespace
+metadata:
+  labels:
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+    pod-security.kubernetes.io/warn: restricted
+    pod-security.kubernetes.io/warn-version: latest
+  name: flux-system
+---
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  labels:
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+  name: allow-egress
+  namespace: flux-system
+spec:
+  egress:
+  - {}
+  ingress:
+  - from:
+    - podSelector: {}
+  podSelector: {}
+  policyTypes:
+  - Ingress
+  - Egress
+---
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  labels:
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+  name: allow-scraping
+  namespace: flux-system
+spec:
+  ingress:
+  - from:
+    - namespaceSelector: {}
+    ports:
+    - port: 8080
+      protocol: TCP
+  podSelector: {}
+  policyTypes:
+  - Ingress
+---
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  labels:
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+  name: allow-webhooks
+  namespace: flux-system
+spec:
+  ingress:
+  - from:
+    - namespaceSelector: {}
+  podSelector:
+    matchLabels:
+      app: notification-controller
+  policyTypes:
+  - Ingress
+---
+apiVersion: v1
+kind: ResourceQuota
+metadata:
+  labels:
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+  name: critical-pods-flux-system
+  namespace: flux-system
+spec:
+  hard:
+    pods: "1000"
+  scopeSelector:
+    matchExpressions:
+    - operator: In
+      scopeName: PriorityClass
+      values:
+      - system-node-critical
+      - system-cluster-critical
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  labels:
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+  name: crd-controller-flux-system
+rules:
+- apiGroups:
+  - source.toolkit.fluxcd.io
+  resources:
+  - '*'
+  verbs:
+  - '*'
+- apiGroups:
+  - kustomize.toolkit.fluxcd.io
+  resources:
+  - '*'
+  verbs:
+  - '*'
+- apiGroups:
+  - helm.toolkit.fluxcd.io
+  resources:
+  - '*'
+  verbs:
+  - '*'
+- apiGroups:
+  - notification.toolkit.fluxcd.io
+  resources:
+  - '*'
+  verbs:
+  - '*'
+- apiGroups:
+  - image.toolkit.fluxcd.io
+  resources:
+  - '*'
+  verbs:
+  - '*'
+- apiGroups:
+  - ""
+  resources:
+  - namespaces
+  - secrets
+  - configmaps
+  - serviceaccounts
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - ""
+  resources:
+  - events
+  verbs:
+  - create
+  - patch
+- apiGroups:
+  - ""
+  resources:
+  - configmaps
+  verbs:
+  - get
+  - list
+  - watch
+  - create
+  - update
+  - patch
+  - delete
+- apiGroups:
+  - ""
+  resources:
+  - configmaps/status
+  verbs:
+  - get
+  - update
+  - patch
+- apiGroups:
+  - coordination.k8s.io
+  resources:
+  - leases
+  verbs:
+  - get
+  - list
+  - watch
+  - create
+  - update
+  - patch
+  - delete
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  labels:
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+    rbac.authorization.k8s.io/aggregate-to-admin: "true"
+    rbac.authorization.k8s.io/aggregate-to-edit: "true"
+  name: flux-edit-flux-system
+rules:
+- apiGroups:
+  - notification.toolkit.fluxcd.io
+  - source.toolkit.fluxcd.io
+  - helm.toolkit.fluxcd.io
+  - image.toolkit.fluxcd.io
+  - kustomize.toolkit.fluxcd.io
+  resources:
+  - '*'
+  verbs:
+  - create
+  - delete
+  - deletecollection
+  - patch
+  - update
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  labels:
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+    rbac.authorization.k8s.io/aggregate-to-admin: "true"
+    rbac.authorization.k8s.io/aggregate-to-edit: "true"
+    rbac.authorization.k8s.io/aggregate-to-view: "true"
+  name: flux-view-flux-system
+rules:
+- apiGroups:
+  - notification.toolkit.fluxcd.io
+  - source.toolkit.fluxcd.io
+  - helm.toolkit.fluxcd.io
+  - image.toolkit.fluxcd.io
+  - kustomize.toolkit.fluxcd.io
+  resources:
+  - '*'
+  verbs:
+  - get
+  - list
+  - watch
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  labels:
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+  name: cluster-reconciler-flux-system
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: cluster-admin
+subjects:
+- kind: ServiceAccount
+  name: kustomize-controller
+  namespace: flux-system
+- kind: ServiceAccount
+  name: helm-controller
+  namespace: flux-system
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  labels:
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+  name: crd-controller-flux-system
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: crd-controller-flux-system
+subjects:
+- kind: ServiceAccount
+  name: kustomize-controller
+  namespace: flux-system
+- kind: ServiceAccount
+  name: helm-controller
+  namespace: flux-system
+- kind: ServiceAccount
+  name: source-controller
+  namespace: flux-system
+- kind: ServiceAccount
+  name: notification-controller
+  namespace: flux-system
+- kind: ServiceAccount
+  name: image-reflector-controller
+  namespace: flux-system
+- kind: ServiceAccount
+  name: image-automation-controller
+  namespace: flux-system
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.12.0
+  labels:
+    app.kubernetes.io/component: source-controller
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+  name: buckets.source.toolkit.fluxcd.io
+spec:
+  group: source.toolkit.fluxcd.io
+  names:
+    kind: Bucket
+    listKind: BucketList
+    plural: buckets
+    singular: bucket
+  scope: Namespaced
+  versions:
+  - additionalPrinterColumns:
+    - jsonPath: .spec.endpoint
+      name: Endpoint
+      type: string
+    - jsonPath: .status.conditions[?(@.type=="Ready")].status
+      name: Ready
+      type: string
+    - jsonPath: .status.conditions[?(@.type=="Ready")].message
+      name: Status
+      type: string
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    name: v1beta1
+    schema:
+      openAPIV3Schema:
+        description: Bucket is the Schema for the buckets API
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: BucketSpec defines the desired state of an S3 compatible
+              bucket
+            properties:
+              accessFrom:
+                description: AccessFrom defines an Access Control List for allowing
+                  cross-namespace references to this object.
+                properties:
+                  namespaceSelectors:
+                    description: NamespaceSelectors is the list of namespace selectors
+                      to which this ACL applies. Items in this list are evaluated
+                      using a logical OR operation.
+                    items:
+                      description: NamespaceSelector selects the namespaces to which
+                        this ACL applies. An empty map of MatchLabels matches all
+                        namespaces in a cluster.
+                      properties:
+                        matchLabels:
+                          additionalProperties:
+                            type: string
+                          description: MatchLabels is a map of {key,value} pairs.
+                            A single {key,value} in the matchLabels map is equivalent
+                            to an element of matchExpressions, whose key field is
+                            "key", the operator is "In", and the values array contains
+                            only "value". The requirements are ANDed.
+                          type: object
+                      type: object
+                    type: array
+                required:
+                - namespaceSelectors
+                type: object
+              bucketName:
+                description: The bucket name.
+                type: string
+              endpoint:
+                description: The bucket endpoint address.
+                type: string
+              ignore:
+                description: Ignore overrides the set of excluded patterns in the
+                  .sourceignore format (which is the same as .gitignore). If not provided,
+                  a default will be used, consult the documentation for your version
+                  to find out what those are.
+                type: string
+              insecure:
+                description: Insecure allows connecting to a non-TLS S3 HTTP endpoint.
+                type: boolean
+              interval:
+                description: The interval at which to check for bucket updates.
+                type: string
+              provider:
+                default: generic
+                description: The S3 compatible storage provider name, default ('generic').
+                enum:
+                - generic
+                - aws
+                - gcp
+                type: string
+              region:
+                description: The bucket region.
+                type: string
+              secretRef:
+                description: The name of the secret containing authentication credentials
+                  for the Bucket.
+                properties:
+                  name:
+                    description: Name of the referent.
+                    type: string
+                required:
+                - name
+                type: object
+              suspend:
+                description: This flag tells the controller to suspend the reconciliation
+                  of this source.
+                type: boolean
+              timeout:
+                default: 60s
+                description: The timeout for download operations, defaults to 60s.
+                type: string
+            required:
+            - bucketName
+            - endpoint
+            - interval
+            type: object
+          status:
+            default:
+              observedGeneration: -1
+            description: BucketStatus defines the observed state of a bucket
+            properties:
+              artifact:
+                description: Artifact represents the output of the last successful
+                  Bucket sync.
+                properties:
+                  checksum:
+                    description: Checksum is the SHA256 checksum of the artifact.
+                    type: string
+                  lastUpdateTime:
+                    description: LastUpdateTime is the timestamp corresponding to
+                      the last update of this artifact.
+                    format: date-time
+                    type: string
+                  path:
+                    description: Path is the relative file path of this artifact.
+                    type: string
+                  revision:
+                    description: Revision is a human readable identifier traceable
+                      in the origin source system. It can be a Git commit SHA, Git
+                      tag, a Helm index timestamp, a Helm chart version, etc.
+                    type: string
+                  url:
+                    description: URL is the HTTP address of this artifact.
+                    type: string
+                required:
+                - path
+                - url
+                type: object
+              conditions:
+                description: Conditions holds the conditions for the Bucket.
+                items:
+                  description: "Condition contains details for one aspect of the current
+                    state of this API Resource. --- This struct is intended for direct
+                    use as an array at the field path .status.conditions.  For example,
+                    \n type FooStatus struct{ // Represents the observations of a
+                    foo's current state. // Known .status.conditions.type are: \"Available\",
+                    \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
+                    // +listType=map // +listMapKey=type Conditions []metav1.Condition
+                    `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
+                    protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
+                  properties:
+                    lastTransitionTime:
+                      description: lastTransitionTime is the last time the condition
+                        transitioned from one status to another. This should be when
+                        the underlying condition changed.  If that is not known, then
+                        using the time when the API field changed is acceptable.
+                      format: date-time
+                      type: string
+                    message:
+                      description: message is a human readable message indicating
+                        details about the transition. This may be an empty string.
+                      maxLength: 32768
+                      type: string
+                    observedGeneration:
+                      description: observedGeneration represents the .metadata.generation
+                        that the condition was set based upon. For instance, if .metadata.generation
+                        is currently 12, but the .status.conditions[x].observedGeneration
+                        is 9, the condition is out of date with respect to the current
+                        state of the instance.
+                      format: int64
+                      minimum: 0
+                      type: integer
+                    reason:
+                      description: reason contains a programmatic identifier indicating
+                        the reason for the condition's last transition. Producers
+                        of specific condition types may define expected values and
+                        meanings for this field, and whether the values are considered
+                        a guaranteed API. The value should be a CamelCase string.
+                        This field may not be empty.
+                      maxLength: 1024
+                      minLength: 1
+                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+                      type: string
+                    status:
+                      description: status of the condition, one of True, False, Unknown.
+                      enum:
+                      - "True"
+                      - "False"
+                      - Unknown
+                      type: string
+                    type:
+                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
+                        --- Many .condition.type values are consistent across resources
+                        like Available, but because arbitrary conditions can be useful
+                        (see .node.status.conditions), the ability to deconflict is
+                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
+                      maxLength: 316
+                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - message
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+              lastHandledReconcileAt:
+                description: LastHandledReconcileAt holds the value of the most recent
+                  reconcile request value, so a change of the annotation value can
+                  be detected.
+                type: string
+              observedGeneration:
+                description: ObservedGeneration is the last observed generation.
+                format: int64
+                type: integer
+              url:
+                description: URL is the download link for the artifact output of the
+                  last Bucket sync.
+                type: string
+            type: object
+        type: object
+    served: true
+    storage: false
+    subresources:
+      status: {}
+  - additionalPrinterColumns:
+    - jsonPath: .spec.endpoint
+      name: Endpoint
+      type: string
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    - jsonPath: .status.conditions[?(@.type=="Ready")].status
+      name: Ready
+      type: string
+    - jsonPath: .status.conditions[?(@.type=="Ready")].message
+      name: Status
+      type: string
+    name: v1beta2
+    schema:
+      openAPIV3Schema:
+        description: Bucket is the Schema for the buckets API.
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: BucketSpec specifies the required configuration to produce
+              an Artifact for an object storage bucket.
+            properties:
+              accessFrom:
+                description: 'AccessFrom specifies an Access Control List for allowing
+                  cross-namespace references to this object. NOTE: Not implemented,
+                  provisional as of https://github.com/fluxcd/flux2/pull/2092'
+                properties:
+                  namespaceSelectors:
+                    description: NamespaceSelectors is the list of namespace selectors
+                      to which this ACL applies. Items in this list are evaluated
+                      using a logical OR operation.
+                    items:
+                      description: NamespaceSelector selects the namespaces to which
+                        this ACL applies. An empty map of MatchLabels matches all
+                        namespaces in a cluster.
+                      properties:
+                        matchLabels:
+                          additionalProperties:
+                            type: string
+                          description: MatchLabels is a map of {key,value} pairs.
+                            A single {key,value} in the matchLabels map is equivalent
+                            to an element of matchExpressions, whose key field is
+                            "key", the operator is "In", and the values array contains
+                            only "value". The requirements are ANDed.
+                          type: object
+                      type: object
+                    type: array
+                required:
+                - namespaceSelectors
+                type: object
+              bucketName:
+                description: BucketName is the name of the object storage bucket.
+                type: string
+              endpoint:
+                description: Endpoint is the object storage address the BucketName
+                  is located at.
+                type: string
+              ignore:
+                description: Ignore overrides the set of excluded patterns in the
+                  .sourceignore format (which is the same as .gitignore). If not provided,
+                  a default will be used, consult the documentation for your version
+                  to find out what those are.
+                type: string
+              insecure:
+                description: Insecure allows connecting to a non-TLS HTTP Endpoint.
+                type: boolean
+              interval:
+                description: Interval at which the Bucket Endpoint is checked for
+                  updates. This interval is approximate and may be subject to jitter
+                  to ensure efficient use of resources.
+                pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
+                type: string
+              provider:
+                default: generic
+                description: Provider of the object storage bucket. Defaults to 'generic',
+                  which expects an S3 (API) compatible object storage.
+                enum:
+                - generic
+                - aws
+                - gcp
+                - azure
+                type: string
+              region:
+                description: Region of the Endpoint where the BucketName is located
+                  in.
+                type: string
+              secretRef:
+                description: SecretRef specifies the Secret containing authentication
+                  credentials for the Bucket.
+                properties:
+                  name:
+                    description: Name of the referent.
+                    type: string
+                required:
+                - name
+                type: object
+              suspend:
+                description: Suspend tells the controller to suspend the reconciliation
+                  of this Bucket.
+                type: boolean
+              timeout:
+                default: 60s
+                description: Timeout for fetch operations, defaults to 60s.
+                pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$
+                type: string
+            required:
+            - bucketName
+            - endpoint
+            - interval
+            type: object
+          status:
+            default:
+              observedGeneration: -1
+            description: BucketStatus records the observed state of a Bucket.
+            properties:
+              artifact:
+                description: Artifact represents the last successful Bucket reconciliation.
+                properties:
+                  digest:
+                    description: Digest is the digest of the file in the form of '<algorithm>:<checksum>'.
+                    pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$
+                    type: string
+                  lastUpdateTime:
+                    description: LastUpdateTime is the timestamp corresponding to
+                      the last update of the Artifact.
+                    format: date-time
+                    type: string
+                  metadata:
+                    additionalProperties:
+                      type: string
+                    description: Metadata holds upstream information such as OCI annotations.
+                    type: object
+                  path:
+                    description: Path is the relative file path of the Artifact. It
+                      can be used to locate the file in the root of the Artifact storage
+                      on the local file system of the controller managing the Source.
+                    type: string
+                  revision:
+                    description: Revision is a human-readable identifier traceable
+                      in the origin source system. It can be a Git commit SHA, Git
+                      tag, a Helm chart version, etc.
+                    type: string
+                  size:
+                    description: Size is the number of bytes in the file.
+                    format: int64
+                    type: integer
+                  url:
+                    description: URL is the HTTP address of the Artifact as exposed
+                      by the controller managing the Source. It can be used to retrieve
+                      the Artifact for consumption, e.g. by another controller applying
+                      the Artifact contents.
+                    type: string
+                required:
+                - lastUpdateTime
+                - path
+                - revision
+                - url
+                type: object
+              conditions:
+                description: Conditions holds the conditions for the Bucket.
+                items:
+                  description: "Condition contains details for one aspect of the current
+                    state of this API Resource. --- This struct is intended for direct
+                    use as an array at the field path .status.conditions.  For example,
+                    \n type FooStatus struct{ // Represents the observations of a
+                    foo's current state. // Known .status.conditions.type are: \"Available\",
+                    \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
+                    // +listType=map // +listMapKey=type Conditions []metav1.Condition
+                    `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
+                    protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
+                  properties:
+                    lastTransitionTime:
+                      description: lastTransitionTime is the last time the condition
+                        transitioned from one status to another. This should be when
+                        the underlying condition changed.  If that is not known, then
+                        using the time when the API field changed is acceptable.
+                      format: date-time
+                      type: string
+                    message:
+                      description: message is a human readable message indicating
+                        details about the transition. This may be an empty string.
+                      maxLength: 32768
+                      type: string
+                    observedGeneration:
+                      description: observedGeneration represents the .metadata.generation
+                        that the condition was set based upon. For instance, if .metadata.generation
+                        is currently 12, but the .status.conditions[x].observedGeneration
+                        is 9, the condition is out of date with respect to the current
+                        state of the instance.
+                      format: int64
+                      minimum: 0
+                      type: integer
+                    reason:
+                      description: reason contains a programmatic identifier indicating
+                        the reason for the condition's last transition. Producers
+                        of specific condition types may define expected values and
+                        meanings for this field, and whether the values are considered
+                        a guaranteed API. The value should be a CamelCase string.
+                        This field may not be empty.
+                      maxLength: 1024
+                      minLength: 1
+                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+                      type: string
+                    status:
+                      description: status of the condition, one of True, False, Unknown.
+                      enum:
+                      - "True"
+                      - "False"
+                      - Unknown
+                      type: string
+                    type:
+                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
+                        --- Many .condition.type values are consistent across resources
+                        like Available, but because arbitrary conditions can be useful
+                        (see .node.status.conditions), the ability to deconflict is
+                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
+                      maxLength: 316
+                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - message
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+              lastHandledReconcileAt:
+                description: LastHandledReconcileAt holds the value of the most recent
+                  reconcile request value, so a change of the annotation value can
+                  be detected.
+                type: string
+              observedGeneration:
+                description: ObservedGeneration is the last observed generation of
+                  the Bucket object.
+                format: int64
+                type: integer
+              observedIgnore:
+                description: ObservedIgnore is the observed exclusion patterns used
+                  for constructing the source artifact.
+                type: string
+              url:
+                description: URL is the dynamic fetch link for the latest Artifact.
+                  It is provided on a "best effort" basis, and using the precise BucketStatus.Artifact
+                  data is recommended.
+                type: string
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.12.0
+  labels:
+    app.kubernetes.io/component: source-controller
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+  name: gitrepositories.source.toolkit.fluxcd.io
+spec:
+  group: source.toolkit.fluxcd.io
+  names:
+    kind: GitRepository
+    listKind: GitRepositoryList
+    plural: gitrepositories
+    shortNames:
+    - gitrepo
+    singular: gitrepository
+  scope: Namespaced
+  versions:
+  - additionalPrinterColumns:
+    - jsonPath: .spec.url
+      name: URL
+      type: string
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    - jsonPath: .status.conditions[?(@.type=="Ready")].status
+      name: Ready
+      type: string
+    - jsonPath: .status.conditions[?(@.type=="Ready")].message
+      name: Status
+      type: string
+    name: v1
+    schema:
+      openAPIV3Schema:
+        description: GitRepository is the Schema for the gitrepositories API.
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: GitRepositorySpec specifies the required configuration to
+              produce an Artifact for a Git repository.
+            properties:
+              ignore:
+                description: Ignore overrides the set of excluded patterns in the
+                  .sourceignore format (which is the same as .gitignore). If not provided,
+                  a default will be used, consult the documentation for your version
+                  to find out what those are.
+                type: string
+              include:
+                description: Include specifies a list of GitRepository resources which
+                  Artifacts should be included in the Artifact produced for this GitRepository.
+                items:
+                  description: GitRepositoryInclude specifies a local reference to
+                    a GitRepository which Artifact (sub-)contents must be included,
+                    and where they should be placed.
+                  properties:
+                    fromPath:
+                      description: FromPath specifies the path to copy contents from,
+                        defaults to the root of the Artifact.
+                      type: string
+                    repository:
+                      description: GitRepositoryRef specifies the GitRepository which
+                        Artifact contents must be included.
+                      properties:
+                        name:
+                          description: Name of the referent.
+                          type: string
+                      required:
+                      - name
+                      type: object
+                    toPath:
+                      description: ToPath specifies the path to copy contents to,
+                        defaults to the name of the GitRepositoryRef.
+                      type: string
+                  required:
+                  - repository
+                  type: object
+                type: array
+              interval:
+                description: Interval at which the GitRepository URL is checked for
+                  updates. This interval is approximate and may be subject to jitter
+                  to ensure efficient use of resources.
+                pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
+                type: string
+              proxySecretRef:
+                description: ProxySecretRef specifies the Secret containing the proxy
+                  configuration to use while communicating with the Git server.
+                properties:
+                  name:
+                    description: Name of the referent.
+                    type: string
+                required:
+                - name
+                type: object
+              recurseSubmodules:
+                description: RecurseSubmodules enables the initialization of all submodules
+                  within the GitRepository as cloned from the URL, using their default
+                  settings.
+                type: boolean
+              ref:
+                description: Reference specifies the Git reference to resolve and
+                  monitor for changes, defaults to the 'master' branch.
+                properties:
+                  branch:
+                    description: Branch to check out, defaults to 'master' if no other
+                      field is defined.
+                    type: string
+                  commit:
+                    description: "Commit SHA to check out, takes precedence over all
+                      reference fields. \n This can be combined with Branch to shallow
+                      clone the branch, in which the commit is expected to exist."
+                    type: string
+                  name:
+                    description: "Name of the reference to check out; takes precedence
+                      over Branch, Tag and SemVer. \n It must be a valid Git reference:
+                      https://git-scm.com/docs/git-check-ref-format#_description Examples:
+                      \"refs/heads/main\", \"refs/tags/v0.1.0\", \"refs/pull/420/head\",
+                      \"refs/merge-requests/1/head\""
+                    type: string
+                  semver:
+                    description: SemVer tag expression to check out, takes precedence
+                      over Tag.
+                    type: string
+                  tag:
+                    description: Tag to check out, takes precedence over Branch.
+                    type: string
+                type: object
+              secretRef:
+                description: SecretRef specifies the Secret containing authentication
+                  credentials for the GitRepository. For HTTPS repositories the Secret
+                  must contain 'username' and 'password' fields for basic auth or
+                  'bearerToken' field for token auth. For SSH repositories the Secret
+                  must contain 'identity' and 'known_hosts' fields.
+                properties:
+                  name:
+                    description: Name of the referent.
+                    type: string
+                required:
+                - name
+                type: object
+              suspend:
+                description: Suspend tells the controller to suspend the reconciliation
+                  of this GitRepository.
+                type: boolean
+              timeout:
+                default: 60s
+                description: Timeout for Git operations like cloning, defaults to
+                  60s.
+                pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$
+                type: string
+              url:
+                description: URL specifies the Git repository URL, it can be an HTTP/S
+                  or SSH address.
+                pattern: ^(http|https|ssh)://.*$
+                type: string
+              verify:
+                description: Verification specifies the configuration to verify the
+                  Git commit signature(s).
+                properties:
+                  mode:
+                    default: HEAD
+                    description: "Mode specifies which Git object(s) should be verified.
+                      \n The variants \"head\" and \"HEAD\" both imply the same thing,
+                      i.e. verify the commit that the HEAD of the Git repository points
+                      to. The variant \"head\" solely exists to ensure backwards compatibility."
+                    enum:
+                    - head
+                    - HEAD
+                    - Tag
+                    - TagAndHEAD
+                    type: string
+                  secretRef:
+                    description: SecretRef specifies the Secret containing the public
+                      keys of trusted Git authors.
+                    properties:
+                      name:
+                        description: Name of the referent.
+                        type: string
+                    required:
+                    - name
+                    type: object
+                required:
+                - secretRef
+                type: object
+            required:
+            - interval
+            - url
+            type: object
+          status:
+            default:
+              observedGeneration: -1
+            description: GitRepositoryStatus records the observed state of a Git repository.
+            properties:
+              artifact:
+                description: Artifact represents the last successful GitRepository
+                  reconciliation.
+                properties:
+                  digest:
+                    description: Digest is the digest of the file in the form of '<algorithm>:<checksum>'.
+                    pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$
+                    type: string
+                  lastUpdateTime:
+                    description: LastUpdateTime is the timestamp corresponding to
+                      the last update of the Artifact.
+                    format: date-time
+                    type: string
+                  metadata:
+                    additionalProperties:
+                      type: string
+                    description: Metadata holds upstream information such as OCI annotations.
+                    type: object
+                  path:
+                    description: Path is the relative file path of the Artifact. It
+                      can be used to locate the file in the root of the Artifact storage
+                      on the local file system of the controller managing the Source.
+                    type: string
+                  revision:
+                    description: Revision is a human-readable identifier traceable
+                      in the origin source system. It can be a Git commit SHA, Git
+                      tag, a Helm chart version, etc.
+                    type: string
+                  size:
+                    description: Size is the number of bytes in the file.
+                    format: int64
+                    type: integer
+                  url:
+                    description: URL is the HTTP address of the Artifact as exposed
+                      by the controller managing the Source. It can be used to retrieve
+                      the Artifact for consumption, e.g. by another controller applying
+                      the Artifact contents.
+                    type: string
+                required:
+                - lastUpdateTime
+                - path
+                - revision
+                - url
+                type: object
+              conditions:
+                description: Conditions holds the conditions for the GitRepository.
+                items:
+                  description: "Condition contains details for one aspect of the current
+                    state of this API Resource. --- This struct is intended for direct
+                    use as an array at the field path .status.conditions.  For example,
+                    \n type FooStatus struct{ // Represents the observations of a
+                    foo's current state. // Known .status.conditions.type are: \"Available\",
+                    \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
+                    // +listType=map // +listMapKey=type Conditions []metav1.Condition
+                    `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
+                    protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
+                  properties:
+                    lastTransitionTime:
+                      description: lastTransitionTime is the last time the condition
+                        transitioned from one status to another. This should be when
+                        the underlying condition changed.  If that is not known, then
+                        using the time when the API field changed is acceptable.
+                      format: date-time
+                      type: string
+                    message:
+                      description: message is a human readable message indicating
+                        details about the transition. This may be an empty string.
+                      maxLength: 32768
+                      type: string
+                    observedGeneration:
+                      description: observedGeneration represents the .metadata.generation
+                        that the condition was set based upon. For instance, if .metadata.generation
+                        is currently 12, but the .status.conditions[x].observedGeneration
+                        is 9, the condition is out of date with respect to the current
+                        state of the instance.
+                      format: int64
+                      minimum: 0
+                      type: integer
+                    reason:
+                      description: reason contains a programmatic identifier indicating
+                        the reason for the condition's last transition. Producers
+                        of specific condition types may define expected values and
+                        meanings for this field, and whether the values are considered
+                        a guaranteed API. The value should be a CamelCase string.
+                        This field may not be empty.
+                      maxLength: 1024
+                      minLength: 1
+                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+                      type: string
+                    status:
+                      description: status of the condition, one of True, False, Unknown.
+                      enum:
+                      - "True"
+                      - "False"
+                      - Unknown
+                      type: string
+                    type:
+                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
+                        --- Many .condition.type values are consistent across resources
+                        like Available, but because arbitrary conditions can be useful
+                        (see .node.status.conditions), the ability to deconflict is
+                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
+                      maxLength: 316
+                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - message
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+              includedArtifacts:
+                description: IncludedArtifacts contains a list of the last successfully
+                  included Artifacts as instructed by GitRepositorySpec.Include.
+                items:
+                  description: Artifact represents the output of a Source reconciliation.
+                  properties:
+                    digest:
+                      description: Digest is the digest of the file in the form of
+                        '<algorithm>:<checksum>'.
+                      pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$
+                      type: string
+                    lastUpdateTime:
+                      description: LastUpdateTime is the timestamp corresponding to
+                        the last update of the Artifact.
+                      format: date-time
+                      type: string
+                    metadata:
+                      additionalProperties:
+                        type: string
+                      description: Metadata holds upstream information such as OCI
+                        annotations.
+                      type: object
+                    path:
+                      description: Path is the relative file path of the Artifact.
+                        It can be used to locate the file in the root of the Artifact
+                        storage on the local file system of the controller managing
+                        the Source.
+                      type: string
+                    revision:
+                      description: Revision is a human-readable identifier traceable
+                        in the origin source system. It can be a Git commit SHA, Git
+                        tag, a Helm chart version, etc.
+                      type: string
+                    size:
+                      description: Size is the number of bytes in the file.
+                      format: int64
+                      type: integer
+                    url:
+                      description: URL is the HTTP address of the Artifact as exposed
+                        by the controller managing the Source. It can be used to retrieve
+                        the Artifact for consumption, e.g. by another controller applying
+                        the Artifact contents.
+                      type: string
+                  required:
+                  - lastUpdateTime
+                  - path
+                  - revision
+                  - url
+                  type: object
+                type: array
+              lastHandledReconcileAt:
+                description: LastHandledReconcileAt holds the value of the most recent
+                  reconcile request value, so a change of the annotation value can
+                  be detected.
+                type: string
+              observedGeneration:
+                description: ObservedGeneration is the last observed generation of
+                  the GitRepository object.
+                format: int64
+                type: integer
+              observedIgnore:
+                description: ObservedIgnore is the observed exclusion patterns used
+                  for constructing the source artifact.
+                type: string
+              observedInclude:
+                description: ObservedInclude is the observed list of GitRepository
+                  resources used to produce the current Artifact.
+                items:
+                  description: GitRepositoryInclude specifies a local reference to
+                    a GitRepository which Artifact (sub-)contents must be included,
+                    and where they should be placed.
+                  properties:
+                    fromPath:
+                      description: FromPath specifies the path to copy contents from,
+                        defaults to the root of the Artifact.
+                      type: string
+                    repository:
+                      description: GitRepositoryRef specifies the GitRepository which
+                        Artifact contents must be included.
+                      properties:
+                        name:
+                          description: Name of the referent.
+                          type: string
+                      required:
+                      - name
+                      type: object
+                    toPath:
+                      description: ToPath specifies the path to copy contents to,
+                        defaults to the name of the GitRepositoryRef.
+                      type: string
+                  required:
+                  - repository
+                  type: object
+                type: array
+              observedRecurseSubmodules:
+                description: ObservedRecurseSubmodules is the observed resource submodules
+                  configuration used to produce the current Artifact.
+                type: boolean
+              sourceVerificationMode:
+                description: SourceVerificationMode is the last used verification
+                  mode indicating which Git object(s) have been verified.
+                type: string
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+  - additionalPrinterColumns:
+    - jsonPath: .spec.url
+      name: URL
+      type: string
+    - jsonPath: .status.conditions[?(@.type=="Ready")].status
+      name: Ready
+      type: string
+    - jsonPath: .status.conditions[?(@.type=="Ready")].message
+      name: Status
+      type: string
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    deprecated: true
+    deprecationWarning: v1beta1 GitRepository is deprecated, upgrade to v1
+    name: v1beta1
+    schema:
+      openAPIV3Schema:
+        description: GitRepository is the Schema for the gitrepositories API
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: GitRepositorySpec defines the desired state of a Git repository.
+            properties:
+              accessFrom:
+                description: AccessFrom defines an Access Control List for allowing
+                  cross-namespace references to this object.
+                properties:
+                  namespaceSelectors:
+                    description: NamespaceSelectors is the list of namespace selectors
+                      to which this ACL applies. Items in this list are evaluated
+                      using a logical OR operation.
+                    items:
+                      description: NamespaceSelector selects the namespaces to which
+                        this ACL applies. An empty map of MatchLabels matches all
+                        namespaces in a cluster.
+                      properties:
+                        matchLabels:
+                          additionalProperties:
+                            type: string
+                          description: MatchLabels is a map of {key,value} pairs.
+                            A single {key,value} in the matchLabels map is equivalent
+                            to an element of matchExpressions, whose key field is
+                            "key", the operator is "In", and the values array contains
+                            only "value". The requirements are ANDed.
+                          type: object
+                      type: object
+                    type: array
+                required:
+                - namespaceSelectors
+                type: object
+              gitImplementation:
+                default: go-git
+                description: Determines which git client library to use. Defaults
+                  to go-git, valid values are ('go-git', 'libgit2').
+                enum:
+                - go-git
+                - libgit2
+                type: string
+              ignore:
+                description: Ignore overrides the set of excluded patterns in the
+                  .sourceignore format (which is the same as .gitignore). If not provided,
+                  a default will be used, consult the documentation for your version
+                  to find out what those are.
+                type: string
+              include:
+                description: Extra git repositories to map into the repository
+                items:
+                  description: GitRepositoryInclude defines a source with a from and
+                    to path.
+                  properties:
+                    fromPath:
+                      description: The path to copy contents from, defaults to the
+                        root directory.
+                      type: string
+                    repository:
+                      description: Reference to a GitRepository to include.
+                      properties:
+                        name:
+                          description: Name of the referent.
+                          type: string
+                      required:
+                      - name
+                      type: object
+                    toPath:
+                      description: The path to copy contents to, defaults to the name
+                        of the source ref.
+                      type: string
+                  required:
+                  - repository
+                  type: object
+                type: array
+              interval:
+                description: The interval at which to check for repository updates.
+                type: string
+              recurseSubmodules:
+                description: When enabled, after the clone is created, initializes
+                  all submodules within, using their default settings. This option
+                  is available only when using the 'go-git' GitImplementation.
+                type: boolean
+              ref:
+                description: The Git reference to checkout and monitor for changes,
+                  defaults to master branch.
+                properties:
+                  branch:
+                    description: The Git branch to checkout, defaults to master.
+                    type: string
+                  commit:
+                    description: The Git commit SHA to checkout, if specified Tag
+                      filters will be ignored.
+                    type: string
+                  semver:
+                    description: The Git tag semver expression, takes precedence over
+                      Tag.
+                    type: string
+                  tag:
+                    description: The Git tag to checkout, takes precedence over Branch.
+                    type: string
+                type: object
+              secretRef:
+                description: The secret name containing the Git credentials. For HTTPS
+                  repositories the secret must contain username and password fields.
+                  For SSH repositories the secret must contain identity and known_hosts
+                  fields.
+                properties:
+                  name:
+                    description: Name of the referent.
+                    type: string
+                required:
+                - name
+                type: object
+              suspend:
+                description: This flag tells the controller to suspend the reconciliation
+                  of this source.
+                type: boolean
+              timeout:
+                default: 60s
+                description: The timeout for remote Git operations like cloning, defaults
+                  to 60s.
+                type: string
+              url:
+                description: The repository URL, can be a HTTP/S or SSH address.
+                pattern: ^(http|https|ssh)://.*$
+                type: string
+              verify:
+                description: Verify OpenPGP signature for the Git commit HEAD points
+                  to.
+                properties:
+                  mode:
+                    description: Mode describes what git object should be verified,
+                      currently ('head').
+                    enum:
+                    - head
+                    type: string
+                  secretRef:
+                    description: The secret name containing the public keys of all
+                      trusted Git authors.
+                    properties:
+                      name:
+                        description: Name of the referent.
+                        type: string
+                    required:
+                    - name
+                    type: object
+                required:
+                - mode
+                type: object
+            required:
+            - interval
+            - url
+            type: object
+          status:
+            default:
+              observedGeneration: -1
+            description: GitRepositoryStatus defines the observed state of a Git repository.
+            properties:
+              artifact:
+                description: Artifact represents the output of the last successful
+                  repository sync.
+                properties:
+                  checksum:
+                    description: Checksum is the SHA256 checksum of the artifact.
+                    type: string
+                  lastUpdateTime:
+                    description: LastUpdateTime is the timestamp corresponding to
+                      the last update of this artifact.
+                    format: date-time
+                    type: string
+                  path:
+                    description: Path is the relative file path of this artifact.
+                    type: string
+                  revision:
+                    description: Revision is a human readable identifier traceable
+                      in the origin source system. It can be a Git commit SHA, Git
+                      tag, a Helm index timestamp, a Helm chart version, etc.
+                    type: string
+                  url:
+                    description: URL is the HTTP address of this artifact.
+                    type: string
+                required:
+                - path
+                - url
+                type: object
+              conditions:
+                description: Conditions holds the conditions for the GitRepository.
+                items:
+                  description: "Condition contains details for one aspect of the current
+                    state of this API Resource. --- This struct is intended for direct
+                    use as an array at the field path .status.conditions.  For example,
+                    \n type FooStatus struct{ // Represents the observations of a
+                    foo's current state. // Known .status.conditions.type are: \"Available\",
+                    \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
+                    // +listType=map // +listMapKey=type Conditions []metav1.Condition
+                    `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
+                    protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
+                  properties:
+                    lastTransitionTime:
+                      description: lastTransitionTime is the last time the condition
+                        transitioned from one status to another. This should be when
+                        the underlying condition changed.  If that is not known, then
+                        using the time when the API field changed is acceptable.
+                      format: date-time
+                      type: string
+                    message:
+                      description: message is a human readable message indicating
+                        details about the transition. This may be an empty string.
+                      maxLength: 32768
+                      type: string
+                    observedGeneration:
+                      description: observedGeneration represents the .metadata.generation
+                        that the condition was set based upon. For instance, if .metadata.generation
+                        is currently 12, but the .status.conditions[x].observedGeneration
+                        is 9, the condition is out of date with respect to the current
+                        state of the instance.
+                      format: int64
+                      minimum: 0
+                      type: integer
+                    reason:
+                      description: reason contains a programmatic identifier indicating
+                        the reason for the condition's last transition. Producers
+                        of specific condition types may define expected values and
+                        meanings for this field, and whether the values are considered
+                        a guaranteed API. The value should be a CamelCase string.
+                        This field may not be empty.
+                      maxLength: 1024
+                      minLength: 1
+                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+                      type: string
+                    status:
+                      description: status of the condition, one of True, False, Unknown.
+                      enum:
+                      - "True"
+                      - "False"
+                      - Unknown
+                      type: string
+                    type:
+                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
+                        --- Many .condition.type values are consistent across resources
+                        like Available, but because arbitrary conditions can be useful
+                        (see .node.status.conditions), the ability to deconflict is
+                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
+                      maxLength: 316
+                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - message
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+              includedArtifacts:
+                description: IncludedArtifacts represents the included artifacts from
+                  the last successful repository sync.
+                items:
+                  description: Artifact represents the output of a source synchronisation.
+                  properties:
+                    checksum:
+                      description: Checksum is the SHA256 checksum of the artifact.
+                      type: string
+                    lastUpdateTime:
+                      description: LastUpdateTime is the timestamp corresponding to
+                        the last update of this artifact.
+                      format: date-time
+                      type: string
+                    path:
+                      description: Path is the relative file path of this artifact.
+                      type: string
+                    revision:
+                      description: Revision is a human readable identifier traceable
+                        in the origin source system. It can be a Git commit SHA, Git
+                        tag, a Helm index timestamp, a Helm chart version, etc.
+                      type: string
+                    url:
+                      description: URL is the HTTP address of this artifact.
+                      type: string
+                  required:
+                  - path
+                  - url
+                  type: object
+                type: array
+              lastHandledReconcileAt:
+                description: LastHandledReconcileAt holds the value of the most recent
+                  reconcile request value, so a change of the annotation value can
+                  be detected.
+                type: string
+              observedGeneration:
+                description: ObservedGeneration is the last observed generation.
+                format: int64
+                type: integer
+              url:
+                description: URL is the download link for the artifact output of the
+                  last repository sync.
+                type: string
+            type: object
+        type: object
+    served: true
+    storage: false
+    subresources:
+      status: {}
+  - additionalPrinterColumns:
+    - jsonPath: .spec.url
+      name: URL
+      type: string
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    - jsonPath: .status.conditions[?(@.type=="Ready")].status
+      name: Ready
+      type: string
+    - jsonPath: .status.conditions[?(@.type=="Ready")].message
+      name: Status
+      type: string
+    deprecated: true
+    deprecationWarning: v1beta2 GitRepository is deprecated, upgrade to v1
+    name: v1beta2
+    schema:
+      openAPIV3Schema:
+        description: GitRepository is the Schema for the gitrepositories API.
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: GitRepositorySpec specifies the required configuration to
+              produce an Artifact for a Git repository.
+            properties:
+              accessFrom:
+                description: 'AccessFrom specifies an Access Control List for allowing
+                  cross-namespace references to this object. NOTE: Not implemented,
+                  provisional as of https://github.com/fluxcd/flux2/pull/2092'
+                properties:
+                  namespaceSelectors:
+                    description: NamespaceSelectors is the list of namespace selectors
+                      to which this ACL applies. Items in this list are evaluated
+                      using a logical OR operation.
+                    items:
+                      description: NamespaceSelector selects the namespaces to which
+                        this ACL applies. An empty map of MatchLabels matches all
+                        namespaces in a cluster.
+                      properties:
+                        matchLabels:
+                          additionalProperties:
+                            type: string
+                          description: MatchLabels is a map of {key,value} pairs.
+                            A single {key,value} in the matchLabels map is equivalent
+                            to an element of matchExpressions, whose key field is
+                            "key", the operator is "In", and the values array contains
+                            only "value". The requirements are ANDed.
+                          type: object
+                      type: object
+                    type: array
+                required:
+                - namespaceSelectors
+                type: object
+              gitImplementation:
+                default: go-git
+                description: 'GitImplementation specifies which Git client library
+                  implementation to use. Defaults to ''go-git'', valid values are
+                  (''go-git'', ''libgit2''). Deprecated: gitImplementation is deprecated
+                  now that ''go-git'' is the only supported implementation.'
+                enum:
+                - go-git
+                - libgit2
+                type: string
+              ignore:
+                description: Ignore overrides the set of excluded patterns in the
+                  .sourceignore format (which is the same as .gitignore). If not provided,
+                  a default will be used, consult the documentation for your version
+                  to find out what those are.
+                type: string
+              include:
+                description: Include specifies a list of GitRepository resources which
+                  Artifacts should be included in the Artifact produced for this GitRepository.
+                items:
+                  description: GitRepositoryInclude specifies a local reference to
+                    a GitRepository which Artifact (sub-)contents must be included,
+                    and where they should be placed.
+                  properties:
+                    fromPath:
+                      description: FromPath specifies the path to copy contents from,
+                        defaults to the root of the Artifact.
+                      type: string
+                    repository:
+                      description: GitRepositoryRef specifies the GitRepository which
+                        Artifact contents must be included.
+                      properties:
+                        name:
+                          description: Name of the referent.
+                          type: string
+                      required:
+                      - name
+                      type: object
+                    toPath:
+                      description: ToPath specifies the path to copy contents to,
+                        defaults to the name of the GitRepositoryRef.
+                      type: string
+                  required:
+                  - repository
+                  type: object
+                type: array
+              interval:
+                description: Interval at which to check the GitRepository for updates.
+                pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
+                type: string
+              recurseSubmodules:
+                description: RecurseSubmodules enables the initialization of all submodules
+                  within the GitRepository as cloned from the URL, using their default
+                  settings.
+                type: boolean
+              ref:
+                description: Reference specifies the Git reference to resolve and
+                  monitor for changes, defaults to the 'master' branch.
+                properties:
+                  branch:
+                    description: Branch to check out, defaults to 'master' if no other
+                      field is defined.
+                    type: string
+                  commit:
+                    description: "Commit SHA to check out, takes precedence over all
+                      reference fields. \n This can be combined with Branch to shallow
+                      clone the branch, in which the commit is expected to exist."
+                    type: string
+                  name:
+                    description: "Name of the reference to check out; takes precedence
+                      over Branch, Tag and SemVer. \n It must be a valid Git reference:
+                      https://git-scm.com/docs/git-check-ref-format#_description Examples:
+                      \"refs/heads/main\", \"refs/tags/v0.1.0\", \"refs/pull/420/head\",
+                      \"refs/merge-requests/1/head\""
+                    type: string
+                  semver:
+                    description: SemVer tag expression to check out, takes precedence
+                      over Tag.
+                    type: string
+                  tag:
+                    description: Tag to check out, takes precedence over Branch.
+                    type: string
+                type: object
+              secretRef:
+                description: SecretRef specifies the Secret containing authentication
+                  credentials for the GitRepository. For HTTPS repositories the Secret
+                  must contain 'username' and 'password' fields for basic auth or
+                  'bearerToken' field for token auth. For SSH repositories the Secret
+                  must contain 'identity' and 'known_hosts' fields.
+                properties:
+                  name:
+                    description: Name of the referent.
+                    type: string
+                required:
+                - name
+                type: object
+              suspend:
+                description: Suspend tells the controller to suspend the reconciliation
+                  of this GitRepository.
+                type: boolean
+              timeout:
+                default: 60s
+                description: Timeout for Git operations like cloning, defaults to
+                  60s.
+                pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$
+                type: string
+              url:
+                description: URL specifies the Git repository URL, it can be an HTTP/S
+                  or SSH address.
+                pattern: ^(http|https|ssh)://.*$
+                type: string
+              verify:
+                description: Verification specifies the configuration to verify the
+                  Git commit signature(s).
+                properties:
+                  mode:
+                    description: Mode specifies what Git object should be verified,
+                      currently ('head').
+                    enum:
+                    - head
+                    type: string
+                  secretRef:
+                    description: SecretRef specifies the Secret containing the public
+                      keys of trusted Git authors.
+                    properties:
+                      name:
+                        description: Name of the referent.
+                        type: string
+                    required:
+                    - name
+                    type: object
+                required:
+                - mode
+                - secretRef
+                type: object
+            required:
+            - interval
+            - url
+            type: object
+          status:
+            default:
+              observedGeneration: -1
+            description: GitRepositoryStatus records the observed state of a Git repository.
+            properties:
+              artifact:
+                description: Artifact represents the last successful GitRepository
+                  reconciliation.
+                properties:
+                  digest:
+                    description: Digest is the digest of the file in the form of '<algorithm>:<checksum>'.
+                    pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$
+                    type: string
+                  lastUpdateTime:
+                    description: LastUpdateTime is the timestamp corresponding to
+                      the last update of the Artifact.
+                    format: date-time
+                    type: string
+                  metadata:
+                    additionalProperties:
+                      type: string
+                    description: Metadata holds upstream information such as OCI annotations.
+                    type: object
+                  path:
+                    description: Path is the relative file path of the Artifact. It
+                      can be used to locate the file in the root of the Artifact storage
+                      on the local file system of the controller managing the Source.
+                    type: string
+                  revision:
+                    description: Revision is a human-readable identifier traceable
+                      in the origin source system. It can be a Git commit SHA, Git
+                      tag, a Helm chart version, etc.
+                    type: string
+                  size:
+                    description: Size is the number of bytes in the file.
+                    format: int64
+                    type: integer
+                  url:
+                    description: URL is the HTTP address of the Artifact as exposed
+                      by the controller managing the Source. It can be used to retrieve
+                      the Artifact for consumption, e.g. by another controller applying
+                      the Artifact contents.
+                    type: string
+                required:
+                - lastUpdateTime
+                - path
+                - revision
+                - url
+                type: object
+              conditions:
+                description: Conditions holds the conditions for the GitRepository.
+                items:
+                  description: "Condition contains details for one aspect of the current
+                    state of this API Resource. --- This struct is intended for direct
+                    use as an array at the field path .status.conditions.  For example,
+                    \n type FooStatus struct{ // Represents the observations of a
+                    foo's current state. // Known .status.conditions.type are: \"Available\",
+                    \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
+                    // +listType=map // +listMapKey=type Conditions []metav1.Condition
+                    `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
+                    protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
+                  properties:
+                    lastTransitionTime:
+                      description: lastTransitionTime is the last time the condition
+                        transitioned from one status to another. This should be when
+                        the underlying condition changed.  If that is not known, then
+                        using the time when the API field changed is acceptable.
+                      format: date-time
+                      type: string
+                    message:
+                      description: message is a human readable message indicating
+                        details about the transition. This may be an empty string.
+                      maxLength: 32768
+                      type: string
+                    observedGeneration:
+                      description: observedGeneration represents the .metadata.generation
+                        that the condition was set based upon. For instance, if .metadata.generation
+                        is currently 12, but the .status.conditions[x].observedGeneration
+                        is 9, the condition is out of date with respect to the current
+                        state of the instance.
+                      format: int64
+                      minimum: 0
+                      type: integer
+                    reason:
+                      description: reason contains a programmatic identifier indicating
+                        the reason for the condition's last transition. Producers
+                        of specific condition types may define expected values and
+                        meanings for this field, and whether the values are considered
+                        a guaranteed API. The value should be a CamelCase string.
+                        This field may not be empty.
+                      maxLength: 1024
+                      minLength: 1
+                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+                      type: string
+                    status:
+                      description: status of the condition, one of True, False, Unknown.
+                      enum:
+                      - "True"
+                      - "False"
+                      - Unknown
+                      type: string
+                    type:
+                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
+                        --- Many .condition.type values are consistent across resources
+                        like Available, but because arbitrary conditions can be useful
+                        (see .node.status.conditions), the ability to deconflict is
+                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
+                      maxLength: 316
+                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - message
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+              contentConfigChecksum:
+                description: "ContentConfigChecksum is a checksum of all the configurations
+                  related to the content of the source artifact: - .spec.ignore -
+                  .spec.recurseSubmodules - .spec.included and the checksum of the
+                  included artifacts observed in .status.observedGeneration version
+                  of the object. This can be used to determine if the content of the
+                  included repository has changed. It has the format of `<algo>:<checksum>`,
+                  for example: `sha256:<checksum>`. \n Deprecated: Replaced with explicit
+                  fields for observed artifact content config in the status."
+                type: string
+              includedArtifacts:
+                description: IncludedArtifacts contains a list of the last successfully
+                  included Artifacts as instructed by GitRepositorySpec.Include.
+                items:
+                  description: Artifact represents the output of a Source reconciliation.
+                  properties:
+                    digest:
+                      description: Digest is the digest of the file in the form of
+                        '<algorithm>:<checksum>'.
+                      pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$
+                      type: string
+                    lastUpdateTime:
+                      description: LastUpdateTime is the timestamp corresponding to
+                        the last update of the Artifact.
+                      format: date-time
+                      type: string
+                    metadata:
+                      additionalProperties:
+                        type: string
+                      description: Metadata holds upstream information such as OCI
+                        annotations.
+                      type: object
+                    path:
+                      description: Path is the relative file path of the Artifact.
+                        It can be used to locate the file in the root of the Artifact
+                        storage on the local file system of the controller managing
+                        the Source.
+                      type: string
+                    revision:
+                      description: Revision is a human-readable identifier traceable
+                        in the origin source system. It can be a Git commit SHA, Git
+                        tag, a Helm chart version, etc.
+                      type: string
+                    size:
+                      description: Size is the number of bytes in the file.
+                      format: int64
+                      type: integer
+                    url:
+                      description: URL is the HTTP address of the Artifact as exposed
+                        by the controller managing the Source. It can be used to retrieve
+                        the Artifact for consumption, e.g. by another controller applying
+                        the Artifact contents.
+                      type: string
+                  required:
+                  - lastUpdateTime
+                  - path
+                  - revision
+                  - url
+                  type: object
+                type: array
+              lastHandledReconcileAt:
+                description: LastHandledReconcileAt holds the value of the most recent
+                  reconcile request value, so a change of the annotation value can
+                  be detected.
+                type: string
+              observedGeneration:
+                description: ObservedGeneration is the last observed generation of
+                  the GitRepository object.
+                format: int64
+                type: integer
+              observedIgnore:
+                description: ObservedIgnore is the observed exclusion patterns used
+                  for constructing the source artifact.
+                type: string
+              observedInclude:
+                description: ObservedInclude is the observed list of GitRepository
+                  resources used to to produce the current Artifact.
+                items:
+                  description: GitRepositoryInclude specifies a local reference to
+                    a GitRepository which Artifact (sub-)contents must be included,
+                    and where they should be placed.
+                  properties:
+                    fromPath:
+                      description: FromPath specifies the path to copy contents from,
+                        defaults to the root of the Artifact.
+                      type: string
+                    repository:
+                      description: GitRepositoryRef specifies the GitRepository which
+                        Artifact contents must be included.
+                      properties:
+                        name:
+                          description: Name of the referent.
+                          type: string
+                      required:
+                      - name
+                      type: object
+                    toPath:
+                      description: ToPath specifies the path to copy contents to,
+                        defaults to the name of the GitRepositoryRef.
+                      type: string
+                  required:
+                  - repository
+                  type: object
+                type: array
+              observedRecurseSubmodules:
+                description: ObservedRecurseSubmodules is the observed resource submodules
+                  configuration used to produce the current Artifact.
+                type: boolean
+              url:
+                description: URL is the dynamic fetch link for the latest Artifact.
+                  It is provided on a "best effort" basis, and using the precise GitRepositoryStatus.Artifact
+                  data is recommended.
+                type: string
+            type: object
+        type: object
+    served: true
+    storage: false
+    subresources:
+      status: {}
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.12.0
+  labels:
+    app.kubernetes.io/component: source-controller
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+  name: helmcharts.source.toolkit.fluxcd.io
+spec:
+  group: source.toolkit.fluxcd.io
+  names:
+    kind: HelmChart
+    listKind: HelmChartList
+    plural: helmcharts
+    shortNames:
+    - hc
+    singular: helmchart
+  scope: Namespaced
+  versions:
+  - additionalPrinterColumns:
+    - jsonPath: .spec.chart
+      name: Chart
+      type: string
+    - jsonPath: .spec.version
+      name: Version
+      type: string
+    - jsonPath: .spec.sourceRef.kind
+      name: Source Kind
+      type: string
+    - jsonPath: .spec.sourceRef.name
+      name: Source Name
+      type: string
+    - jsonPath: .status.conditions[?(@.type=="Ready")].status
+      name: Ready
+      type: string
+    - jsonPath: .status.conditions[?(@.type=="Ready")].message
+      name: Status
+      type: string
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    name: v1beta1
+    schema:
+      openAPIV3Schema:
+        description: HelmChart is the Schema for the helmcharts API
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: HelmChartSpec defines the desired state of a Helm chart.
+            properties:
+              accessFrom:
+                description: AccessFrom defines an Access Control List for allowing
+                  cross-namespace references to this object.
+                properties:
+                  namespaceSelectors:
+                    description: NamespaceSelectors is the list of namespace selectors
+                      to which this ACL applies. Items in this list are evaluated
+                      using a logical OR operation.
+                    items:
+                      description: NamespaceSelector selects the namespaces to which
+                        this ACL applies. An empty map of MatchLabels matches all
+                        namespaces in a cluster.
+                      properties:
+                        matchLabels:
+                          additionalProperties:
+                            type: string
+                          description: MatchLabels is a map of {key,value} pairs.
+                            A single {key,value} in the matchLabels map is equivalent
+                            to an element of matchExpressions, whose key field is
+                            "key", the operator is "In", and the values array contains
+                            only "value". The requirements are ANDed.
+                          type: object
+                      type: object
+                    type: array
+                required:
+                - namespaceSelectors
+                type: object
+              chart:
+                description: The name or path the Helm chart is available at in the
+                  SourceRef.
+                type: string
+              interval:
+                description: The interval at which to check the Source for updates.
+                type: string
+              reconcileStrategy:
+                default: ChartVersion
+                description: Determines what enables the creation of a new artifact.
+                  Valid values are ('ChartVersion', 'Revision'). See the documentation
+                  of the values for an explanation on their behavior. Defaults to
+                  ChartVersion when omitted.
+                enum:
+                - ChartVersion
+                - Revision
+                type: string
+              sourceRef:
+                description: The reference to the Source the chart is available at.
+                properties:
+                  apiVersion:
+                    description: APIVersion of the referent.
+                    type: string
+                  kind:
+                    description: Kind of the referent, valid values are ('HelmRepository',
+                      'GitRepository', 'Bucket').
+                    enum:
+                    - HelmRepository
+                    - GitRepository
+                    - Bucket
+                    type: string
+                  name:
+                    description: Name of the referent.
+                    type: string
+                required:
+                - kind
+                - name
+                type: object
+              suspend:
+                description: This flag tells the controller to suspend the reconciliation
+                  of this source.
+                type: boolean
+              valuesFile:
+                description: Alternative values file to use as the default chart values,
+                  expected to be a relative path in the SourceRef. Deprecated in favor
+                  of ValuesFiles, for backwards compatibility the file defined here
+                  is merged before the ValuesFiles items. Ignored when omitted.
+                type: string
+              valuesFiles:
+                description: Alternative list of values files to use as the chart
+                  values (values.yaml is not included by default), expected to be
+                  a relative path in the SourceRef. Values files are merged in the
+                  order of this list with the last file overriding the first. Ignored
+                  when omitted.
+                items:
+                  type: string
+                type: array
+              version:
+                default: '*'
+                description: The chart version semver expression, ignored for charts
+                  from GitRepository and Bucket sources. Defaults to latest when omitted.
+                type: string
+            required:
+            - chart
+            - interval
+            - sourceRef
+            type: object
+          status:
+            default:
+              observedGeneration: -1
+            description: HelmChartStatus defines the observed state of the HelmChart.
+            properties:
+              artifact:
+                description: Artifact represents the output of the last successful
+                  chart sync.
+                properties:
+                  checksum:
+                    description: Checksum is the SHA256 checksum of the artifact.
+                    type: string
+                  lastUpdateTime:
+                    description: LastUpdateTime is the timestamp corresponding to
+                      the last update of this artifact.
+                    format: date-time
+                    type: string
+                  path:
+                    description: Path is the relative file path of this artifact.
+                    type: string
+                  revision:
+                    description: Revision is a human readable identifier traceable
+                      in the origin source system. It can be a Git commit SHA, Git
+                      tag, a Helm index timestamp, a Helm chart version, etc.
+                    type: string
+                  url:
+                    description: URL is the HTTP address of this artifact.
+                    type: string
+                required:
+                - path
+                - url
+                type: object
+              conditions:
+                description: Conditions holds the conditions for the HelmChart.
+                items:
+                  description: "Condition contains details for one aspect of the current
+                    state of this API Resource. --- This struct is intended for direct
+                    use as an array at the field path .status.conditions.  For example,
+                    \n type FooStatus struct{ // Represents the observations of a
+                    foo's current state. // Known .status.conditions.type are: \"Available\",
+                    \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
+                    // +listType=map // +listMapKey=type Conditions []metav1.Condition
+                    `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
+                    protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
+                  properties:
+                    lastTransitionTime:
+                      description: lastTransitionTime is the last time the condition
+                        transitioned from one status to another. This should be when
+                        the underlying condition changed.  If that is not known, then
+                        using the time when the API field changed is acceptable.
+                      format: date-time
+                      type: string
+                    message:
+                      description: message is a human readable message indicating
+                        details about the transition. This may be an empty string.
+                      maxLength: 32768
+                      type: string
+                    observedGeneration:
+                      description: observedGeneration represents the .metadata.generation
+                        that the condition was set based upon. For instance, if .metadata.generation
+                        is currently 12, but the .status.conditions[x].observedGeneration
+                        is 9, the condition is out of date with respect to the current
+                        state of the instance.
+                      format: int64
+                      minimum: 0
+                      type: integer
+                    reason:
+                      description: reason contains a programmatic identifier indicating
+                        the reason for the condition's last transition. Producers
+                        of specific condition types may define expected values and
+                        meanings for this field, and whether the values are considered
+                        a guaranteed API. The value should be a CamelCase string.
+                        This field may not be empty.
+                      maxLength: 1024
+                      minLength: 1
+                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+                      type: string
+                    status:
+                      description: status of the condition, one of True, False, Unknown.
+                      enum:
+                      - "True"
+                      - "False"
+                      - Unknown
+                      type: string
+                    type:
+                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
+                        --- Many .condition.type values are consistent across resources
+                        like Available, but because arbitrary conditions can be useful
+                        (see .node.status.conditions), the ability to deconflict is
+                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
+                      maxLength: 316
+                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - message
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+              lastHandledReconcileAt:
+                description: LastHandledReconcileAt holds the value of the most recent
+                  reconcile request value, so a change of the annotation value can
+                  be detected.
+                type: string
+              observedGeneration:
+                description: ObservedGeneration is the last observed generation.
+                format: int64
+                type: integer
+              url:
+                description: URL is the download link for the last chart pulled.
+                type: string
+            type: object
+        type: object
+    served: true
+    storage: false
+    subresources:
+      status: {}
+  - additionalPrinterColumns:
+    - jsonPath: .spec.chart
+      name: Chart
+      type: string
+    - jsonPath: .spec.version
+      name: Version
+      type: string
+    - jsonPath: .spec.sourceRef.kind
+      name: Source Kind
+      type: string
+    - jsonPath: .spec.sourceRef.name
+      name: Source Name
+      type: string
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    - jsonPath: .status.conditions[?(@.type=="Ready")].status
+      name: Ready
+      type: string
+    - jsonPath: .status.conditions[?(@.type=="Ready")].message
+      name: Status
+      type: string
+    name: v1beta2
+    schema:
+      openAPIV3Schema:
+        description: HelmChart is the Schema for the helmcharts API.
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: HelmChartSpec specifies the desired state of a Helm chart.
+            properties:
+              accessFrom:
+                description: 'AccessFrom specifies an Access Control List for allowing
+                  cross-namespace references to this object. NOTE: Not implemented,
+                  provisional as of https://github.com/fluxcd/flux2/pull/2092'
+                properties:
+                  namespaceSelectors:
+                    description: NamespaceSelectors is the list of namespace selectors
+                      to which this ACL applies. Items in this list are evaluated
+                      using a logical OR operation.
+                    items:
+                      description: NamespaceSelector selects the namespaces to which
+                        this ACL applies. An empty map of MatchLabels matches all
+                        namespaces in a cluster.
+                      properties:
+                        matchLabels:
+                          additionalProperties:
+                            type: string
+                          description: MatchLabels is a map of {key,value} pairs.
+                            A single {key,value} in the matchLabels map is equivalent
+                            to an element of matchExpressions, whose key field is
+                            "key", the operator is "In", and the values array contains
+                            only "value". The requirements are ANDed.
+                          type: object
+                      type: object
+                    type: array
+                required:
+                - namespaceSelectors
+                type: object
+              chart:
+                description: Chart is the name or path the Helm chart is available
+                  at in the SourceRef.
+                type: string
+              interval:
+                description: Interval at which the HelmChart SourceRef is checked
+                  for updates. This interval is approximate and may be subject to
+                  jitter to ensure efficient use of resources.
+                pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
+                type: string
+              reconcileStrategy:
+                default: ChartVersion
+                description: ReconcileStrategy determines what enables the creation
+                  of a new artifact. Valid values are ('ChartVersion', 'Revision').
+                  See the documentation of the values for an explanation on their
+                  behavior. Defaults to ChartVersion when omitted.
+                enum:
+                - ChartVersion
+                - Revision
+                type: string
+              sourceRef:
+                description: SourceRef is the reference to the Source the chart is
+                  available at.
+                properties:
+                  apiVersion:
+                    description: APIVersion of the referent.
+                    type: string
+                  kind:
+                    description: Kind of the referent, valid values are ('HelmRepository',
+                      'GitRepository', 'Bucket').
+                    enum:
+                    - HelmRepository
+                    - GitRepository
+                    - Bucket
+                    type: string
+                  name:
+                    description: Name of the referent.
+                    type: string
+                required:
+                - kind
+                - name
+                type: object
+              suspend:
+                description: Suspend tells the controller to suspend the reconciliation
+                  of this source.
+                type: boolean
+              valuesFile:
+                description: ValuesFile is an alternative values file to use as the
+                  default chart values, expected to be a relative path in the SourceRef.
+                  Deprecated in favor of ValuesFiles, for backwards compatibility
+                  the file specified here is merged before the ValuesFiles items.
+                  Ignored when omitted.
+                type: string
+              valuesFiles:
+                description: ValuesFiles is an alternative list of values files to
+                  use as the chart values (values.yaml is not included by default),
+                  expected to be a relative path in the SourceRef. Values files are
+                  merged in the order of this list with the last file overriding the
+                  first. Ignored when omitted.
+                items:
+                  type: string
+                type: array
+              verify:
+                description: Verify contains the secret name containing the trusted
+                  public keys used to verify the signature and specifies which provider
+                  to use to check whether OCI image is authentic. This field is only
+                  supported when using HelmRepository source with spec.type 'oci'.
+                  Chart dependencies, which are not bundled in the umbrella chart
+                  artifact, are not verified.
+                properties:
+                  provider:
+                    default: cosign
+                    description: Provider specifies the technology used to sign the
+                      OCI Artifact.
+                    enum:
+                    - cosign
+                    type: string
+                  secretRef:
+                    description: SecretRef specifies the Kubernetes Secret containing
+                      the trusted public keys.
+                    properties:
+                      name:
+                        description: Name of the referent.
+                        type: string
+                    required:
+                    - name
+                    type: object
+                required:
+                - provider
+                type: object
+              version:
+                default: '*'
+                description: Version is the chart version semver expression, ignored
+                  for charts from GitRepository and Bucket sources. Defaults to latest
+                  when omitted.
+                type: string
+            required:
+            - chart
+            - interval
+            - sourceRef
+            type: object
+          status:
+            default:
+              observedGeneration: -1
+            description: HelmChartStatus records the observed state of the HelmChart.
+            properties:
+              artifact:
+                description: Artifact represents the output of the last successful
+                  reconciliation.
+                properties:
+                  digest:
+                    description: Digest is the digest of the file in the form of '<algorithm>:<checksum>'.
+                    pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$
+                    type: string
+                  lastUpdateTime:
+                    description: LastUpdateTime is the timestamp corresponding to
+                      the last update of the Artifact.
+                    format: date-time
+                    type: string
+                  metadata:
+                    additionalProperties:
+                      type: string
+                    description: Metadata holds upstream information such as OCI annotations.
+                    type: object
+                  path:
+                    description: Path is the relative file path of the Artifact. It
+                      can be used to locate the file in the root of the Artifact storage
+                      on the local file system of the controller managing the Source.
+                    type: string
+                  revision:
+                    description: Revision is a human-readable identifier traceable
+                      in the origin source system. It can be a Git commit SHA, Git
+                      tag, a Helm chart version, etc.
+                    type: string
+                  size:
+                    description: Size is the number of bytes in the file.
+                    format: int64
+                    type: integer
+                  url:
+                    description: URL is the HTTP address of the Artifact as exposed
+                      by the controller managing the Source. It can be used to retrieve
+                      the Artifact for consumption, e.g. by another controller applying
+                      the Artifact contents.
+                    type: string
+                required:
+                - lastUpdateTime
+                - path
+                - revision
+                - url
+                type: object
+              conditions:
+                description: Conditions holds the conditions for the HelmChart.
+                items:
+                  description: "Condition contains details for one aspect of the current
+                    state of this API Resource. --- This struct is intended for direct
+                    use as an array at the field path .status.conditions.  For example,
+                    \n type FooStatus struct{ // Represents the observations of a
+                    foo's current state. // Known .status.conditions.type are: \"Available\",
+                    \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
+                    // +listType=map // +listMapKey=type Conditions []metav1.Condition
+                    `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
+                    protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
+                  properties:
+                    lastTransitionTime:
+                      description: lastTransitionTime is the last time the condition
+                        transitioned from one status to another. This should be when
+                        the underlying condition changed.  If that is not known, then
+                        using the time when the API field changed is acceptable.
+                      format: date-time
+                      type: string
+                    message:
+                      description: message is a human readable message indicating
+                        details about the transition. This may be an empty string.
+                      maxLength: 32768
+                      type: string
+                    observedGeneration:
+                      description: observedGeneration represents the .metadata.generation
+                        that the condition was set based upon. For instance, if .metadata.generation
+                        is currently 12, but the .status.conditions[x].observedGeneration
+                        is 9, the condition is out of date with respect to the current
+                        state of the instance.
+                      format: int64
+                      minimum: 0
+                      type: integer
+                    reason:
+                      description: reason contains a programmatic identifier indicating
+                        the reason for the condition's last transition. Producers
+                        of specific condition types may define expected values and
+                        meanings for this field, and whether the values are considered
+                        a guaranteed API. The value should be a CamelCase string.
+                        This field may not be empty.
+                      maxLength: 1024
+                      minLength: 1
+                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+                      type: string
+                    status:
+                      description: status of the condition, one of True, False, Unknown.
+                      enum:
+                      - "True"
+                      - "False"
+                      - Unknown
+                      type: string
+                    type:
+                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
+                        --- Many .condition.type values are consistent across resources
+                        like Available, but because arbitrary conditions can be useful
+                        (see .node.status.conditions), the ability to deconflict is
+                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
+                      maxLength: 316
+                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - message
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+              lastHandledReconcileAt:
+                description: LastHandledReconcileAt holds the value of the most recent
+                  reconcile request value, so a change of the annotation value can
+                  be detected.
+                type: string
+              observedChartName:
+                description: ObservedChartName is the last observed chart name as
+                  specified by the resolved chart reference.
+                type: string
+              observedGeneration:
+                description: ObservedGeneration is the last observed generation of
+                  the HelmChart object.
+                format: int64
+                type: integer
+              observedSourceArtifactRevision:
+                description: ObservedSourceArtifactRevision is the last observed Artifact.Revision
+                  of the HelmChartSpec.SourceRef.
+                type: string
+              url:
+                description: URL is the dynamic fetch link for the latest Artifact.
+                  It is provided on a "best effort" basis, and using the precise BucketStatus.Artifact
+                  data is recommended.
+                type: string
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.12.0
+  labels:
+    app.kubernetes.io/component: source-controller
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+  name: helmrepositories.source.toolkit.fluxcd.io
+spec:
+  group: source.toolkit.fluxcd.io
+  names:
+    kind: HelmRepository
+    listKind: HelmRepositoryList
+    plural: helmrepositories
+    shortNames:
+    - helmrepo
+    singular: helmrepository
+  scope: Namespaced
+  versions:
+  - additionalPrinterColumns:
+    - jsonPath: .spec.url
+      name: URL
+      type: string
+    - jsonPath: .status.conditions[?(@.type=="Ready")].status
+      name: Ready
+      type: string
+    - jsonPath: .status.conditions[?(@.type=="Ready")].message
+      name: Status
+      type: string
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    name: v1beta1
+    schema:
+      openAPIV3Schema:
+        description: HelmRepository is the Schema for the helmrepositories API
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: HelmRepositorySpec defines the reference to a Helm repository.
+            properties:
+              accessFrom:
+                description: AccessFrom defines an Access Control List for allowing
+                  cross-namespace references to this object.
+                properties:
+                  namespaceSelectors:
+                    description: NamespaceSelectors is the list of namespace selectors
+                      to which this ACL applies. Items in this list are evaluated
+                      using a logical OR operation.
+                    items:
+                      description: NamespaceSelector selects the namespaces to which
+                        this ACL applies. An empty map of MatchLabels matches all
+                        namespaces in a cluster.
+                      properties:
+                        matchLabels:
+                          additionalProperties:
+                            type: string
+                          description: MatchLabels is a map of {key,value} pairs.
+                            A single {key,value} in the matchLabels map is equivalent
+                            to an element of matchExpressions, whose key field is
+                            "key", the operator is "In", and the values array contains
+                            only "value". The requirements are ANDed.
+                          type: object
+                      type: object
+                    type: array
+                required:
+                - namespaceSelectors
+                type: object
+              interval:
+                description: The interval at which to check the upstream for updates.
+                type: string
+              passCredentials:
+                description: PassCredentials allows the credentials from the SecretRef
+                  to be passed on to a host that does not match the host as defined
+                  in URL. This may be required if the host of the advertised chart
+                  URLs in the index differ from the defined URL. Enabling this should
+                  be done with caution, as it can potentially result in credentials
+                  getting stolen in a MITM-attack.
+                type: boolean
+              secretRef:
+                description: The name of the secret containing authentication credentials
+                  for the Helm repository. For HTTP/S basic auth the secret must contain
+                  username and password fields. For TLS the secret must contain a
+                  certFile and keyFile, and/or caFile fields.
+                properties:
+                  name:
+                    description: Name of the referent.
+                    type: string
+                required:
+                - name
+                type: object
+              suspend:
+                description: This flag tells the controller to suspend the reconciliation
+                  of this source.
+                type: boolean
+              timeout:
+                default: 60s
+                description: The timeout of index downloading, defaults to 60s.
+                type: string
+              url:
+                description: The Helm repository URL, a valid URL contains at least
+                  a protocol and host.
+                type: string
+            required:
+            - interval
+            - url
+            type: object
+          status:
+            default:
+              observedGeneration: -1
+            description: HelmRepositoryStatus defines the observed state of the HelmRepository.
+            properties:
+              artifact:
+                description: Artifact represents the output of the last successful
+                  repository sync.
+                properties:
+                  checksum:
+                    description: Checksum is the SHA256 checksum of the artifact.
+                    type: string
+                  lastUpdateTime:
+                    description: LastUpdateTime is the timestamp corresponding to
+                      the last update of this artifact.
+                    format: date-time
+                    type: string
+                  path:
+                    description: Path is the relative file path of this artifact.
+                    type: string
+                  revision:
+                    description: Revision is a human readable identifier traceable
+                      in the origin source system. It can be a Git commit SHA, Git
+                      tag, a Helm index timestamp, a Helm chart version, etc.
+                    type: string
+                  url:
+                    description: URL is the HTTP address of this artifact.
+                    type: string
+                required:
+                - path
+                - url
+                type: object
+              conditions:
+                description: Conditions holds the conditions for the HelmRepository.
+                items:
+                  description: "Condition contains details for one aspect of the current
+                    state of this API Resource. --- This struct is intended for direct
+                    use as an array at the field path .status.conditions.  For example,
+                    \n type FooStatus struct{ // Represents the observations of a
+                    foo's current state. // Known .status.conditions.type are: \"Available\",
+                    \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
+                    // +listType=map // +listMapKey=type Conditions []metav1.Condition
+                    `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
+                    protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
+                  properties:
+                    lastTransitionTime:
+                      description: lastTransitionTime is the last time the condition
+                        transitioned from one status to another. This should be when
+                        the underlying condition changed.  If that is not known, then
+                        using the time when the API field changed is acceptable.
+                      format: date-time
+                      type: string
+                    message:
+                      description: message is a human readable message indicating
+                        details about the transition. This may be an empty string.
+                      maxLength: 32768
+                      type: string
+                    observedGeneration:
+                      description: observedGeneration represents the .metadata.generation
+                        that the condition was set based upon. For instance, if .metadata.generation
+                        is currently 12, but the .status.conditions[x].observedGeneration
+                        is 9, the condition is out of date with respect to the current
+                        state of the instance.
+                      format: int64
+                      minimum: 0
+                      type: integer
+                    reason:
+                      description: reason contains a programmatic identifier indicating
+                        the reason for the condition's last transition. Producers
+                        of specific condition types may define expected values and
+                        meanings for this field, and whether the values are considered
+                        a guaranteed API. The value should be a CamelCase string.
+                        This field may not be empty.
+                      maxLength: 1024
+                      minLength: 1
+                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+                      type: string
+                    status:
+                      description: status of the condition, one of True, False, Unknown.
+                      enum:
+                      - "True"
+                      - "False"
+                      - Unknown
+                      type: string
+                    type:
+                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
+                        --- Many .condition.type values are consistent across resources
+                        like Available, but because arbitrary conditions can be useful
+                        (see .node.status.conditions), the ability to deconflict is
+                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
+                      maxLength: 316
+                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - message
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+              lastHandledReconcileAt:
+                description: LastHandledReconcileAt holds the value of the most recent
+                  reconcile request value, so a change of the annotation value can
+                  be detected.
+                type: string
+              observedGeneration:
+                description: ObservedGeneration is the last observed generation.
+                format: int64
+                type: integer
+              url:
+                description: URL is the download link for the last index fetched.
+                type: string
+            type: object
+        type: object
+    served: true
+    storage: false
+    subresources:
+      status: {}
+  - additionalPrinterColumns:
+    - jsonPath: .spec.url
+      name: URL
+      type: string
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    - jsonPath: .status.conditions[?(@.type=="Ready")].status
+      name: Ready
+      type: string
+    - jsonPath: .status.conditions[?(@.type=="Ready")].message
+      name: Status
+      type: string
+    name: v1beta2
+    schema:
+      openAPIV3Schema:
+        description: HelmRepository is the Schema for the helmrepositories API.
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: HelmRepositorySpec specifies the required configuration to
+              produce an Artifact for a Helm repository index YAML.
+            properties:
+              accessFrom:
+                description: 'AccessFrom specifies an Access Control List for allowing
+                  cross-namespace references to this object. NOTE: Not implemented,
+                  provisional as of https://github.com/fluxcd/flux2/pull/2092'
+                properties:
+                  namespaceSelectors:
+                    description: NamespaceSelectors is the list of namespace selectors
+                      to which this ACL applies. Items in this list are evaluated
+                      using a logical OR operation.
+                    items:
+                      description: NamespaceSelector selects the namespaces to which
+                        this ACL applies. An empty map of MatchLabels matches all
+                        namespaces in a cluster.
+                      properties:
+                        matchLabels:
+                          additionalProperties:
+                            type: string
+                          description: MatchLabels is a map of {key,value} pairs.
+                            A single {key,value} in the matchLabels map is equivalent
+                            to an element of matchExpressions, whose key field is
+                            "key", the operator is "In", and the values array contains
+                            only "value". The requirements are ANDed.
+                          type: object
+                      type: object
+                    type: array
+                required:
+                - namespaceSelectors
+                type: object
+              certSecretRef:
+                description: "CertSecretRef can be given the name of a Secret containing
+                  either or both of \n - a PEM-encoded client certificate (`tls.crt`)
+                  and private key (`tls.key`); - a PEM-encoded CA certificate (`ca.crt`)
+                  \n and whichever are supplied, will be used for connecting to the
+                  registry. The client cert and key are useful if you are authenticating
+                  with a certificate; the CA cert is useful if you are using a self-signed
+                  server certificate. The Secret must be of type `Opaque` or `kubernetes.io/tls`.
+                  \n It takes precedence over the values specified in the Secret referred
+                  to by `.spec.secretRef`."
+                properties:
+                  name:
+                    description: Name of the referent.
+                    type: string
+                required:
+                - name
+                type: object
+              interval:
+                description: Interval at which the HelmRepository URL is checked for
+                  updates. This interval is approximate and may be subject to jitter
+                  to ensure efficient use of resources.
+                pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
+                type: string
+              passCredentials:
+                description: PassCredentials allows the credentials from the SecretRef
+                  to be passed on to a host that does not match the host as defined
+                  in URL. This may be required if the host of the advertised chart
+                  URLs in the index differ from the defined URL. Enabling this should
+                  be done with caution, as it can potentially result in credentials
+                  getting stolen in a MITM-attack.
+                type: boolean
+              provider:
+                default: generic
+                description: Provider used for authentication, can be 'aws', 'azure',
+                  'gcp' or 'generic'. This field is optional, and only taken into
+                  account if the .spec.type field is set to 'oci'. When not specified,
+                  defaults to 'generic'.
+                enum:
+                - generic
+                - aws
+                - azure
+                - gcp
+                type: string
+              secretRef:
+                description: SecretRef specifies the Secret containing authentication
+                  credentials for the HelmRepository. For HTTP/S basic auth the secret
+                  must contain 'username' and 'password' fields. Support for TLS auth
+                  using the 'certFile' and 'keyFile', and/or 'caFile' keys is deprecated.
+                  Please use `.spec.certSecretRef` instead.
+                properties:
+                  name:
+                    description: Name of the referent.
+                    type: string
+                required:
+                - name
+                type: object
+              suspend:
+                description: Suspend tells the controller to suspend the reconciliation
+                  of this HelmRepository.
+                type: boolean
+              timeout:
+                default: 60s
+                description: Timeout is used for the index fetch operation for an
+                  HTTPS helm repository, and for remote OCI Repository operations
+                  like pulling for an OCI helm repository. Its default value is 60s.
+                pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$
+                type: string
+              type:
+                description: Type of the HelmRepository. When this field is set to  "oci",
+                  the URL field value must be prefixed with "oci://".
+                enum:
+                - default
+                - oci
+                type: string
+              url:
+                description: URL of the Helm repository, a valid URL contains at least
+                  a protocol and host.
+                type: string
+            required:
+            - interval
+            - url
+            type: object
+          status:
+            default:
+              observedGeneration: -1
+            description: HelmRepositoryStatus records the observed state of the HelmRepository.
+            properties:
+              artifact:
+                description: Artifact represents the last successful HelmRepository
+                  reconciliation.
+                properties:
+                  digest:
+                    description: Digest is the digest of the file in the form of '<algorithm>:<checksum>'.
+                    pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$
+                    type: string
+                  lastUpdateTime:
+                    description: LastUpdateTime is the timestamp corresponding to
+                      the last update of the Artifact.
+                    format: date-time
+                    type: string
+                  metadata:
+                    additionalProperties:
+                      type: string
+                    description: Metadata holds upstream information such as OCI annotations.
+                    type: object
+                  path:
+                    description: Path is the relative file path of the Artifact. It
+                      can be used to locate the file in the root of the Artifact storage
+                      on the local file system of the controller managing the Source.
+                    type: string
+                  revision:
+                    description: Revision is a human-readable identifier traceable
+                      in the origin source system. It can be a Git commit SHA, Git
+                      tag, a Helm chart version, etc.
+                    type: string
+                  size:
+                    description: Size is the number of bytes in the file.
+                    format: int64
+                    type: integer
+                  url:
+                    description: URL is the HTTP address of the Artifact as exposed
+                      by the controller managing the Source. It can be used to retrieve
+                      the Artifact for consumption, e.g. by another controller applying
+                      the Artifact contents.
+                    type: string
+                required:
+                - lastUpdateTime
+                - path
+                - revision
+                - url
+                type: object
+              conditions:
+                description: Conditions holds the conditions for the HelmRepository.
+                items:
+                  description: "Condition contains details for one aspect of the current
+                    state of this API Resource. --- This struct is intended for direct
+                    use as an array at the field path .status.conditions.  For example,
+                    \n type FooStatus struct{ // Represents the observations of a
+                    foo's current state. // Known .status.conditions.type are: \"Available\",
+                    \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
+                    // +listType=map // +listMapKey=type Conditions []metav1.Condition
+                    `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
+                    protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
+                  properties:
+                    lastTransitionTime:
+                      description: lastTransitionTime is the last time the condition
+                        transitioned from one status to another. This should be when
+                        the underlying condition changed.  If that is not known, then
+                        using the time when the API field changed is acceptable.
+                      format: date-time
+                      type: string
+                    message:
+                      description: message is a human readable message indicating
+                        details about the transition. This may be an empty string.
+                      maxLength: 32768
+                      type: string
+                    observedGeneration:
+                      description: observedGeneration represents the .metadata.generation
+                        that the condition was set based upon. For instance, if .metadata.generation
+                        is currently 12, but the .status.conditions[x].observedGeneration
+                        is 9, the condition is out of date with respect to the current
+                        state of the instance.
+                      format: int64
+                      minimum: 0
+                      type: integer
+                    reason:
+                      description: reason contains a programmatic identifier indicating
+                        the reason for the condition's last transition. Producers
+                        of specific condition types may define expected values and
+                        meanings for this field, and whether the values are considered
+                        a guaranteed API. The value should be a CamelCase string.
+                        This field may not be empty.
+                      maxLength: 1024
+                      minLength: 1
+                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+                      type: string
+                    status:
+                      description: status of the condition, one of True, False, Unknown.
+                      enum:
+                      - "True"
+                      - "False"
+                      - Unknown
+                      type: string
+                    type:
+                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
+                        --- Many .condition.type values are consistent across resources
+                        like Available, but because arbitrary conditions can be useful
+                        (see .node.status.conditions), the ability to deconflict is
+                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
+                      maxLength: 316
+                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - message
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+              lastHandledReconcileAt:
+                description: LastHandledReconcileAt holds the value of the most recent
+                  reconcile request value, so a change of the annotation value can
+                  be detected.
+                type: string
+              observedGeneration:
+                description: ObservedGeneration is the last observed generation of
+                  the HelmRepository object.
+                format: int64
+                type: integer
+              url:
+                description: URL is the dynamic fetch link for the latest Artifact.
+                  It is provided on a "best effort" basis, and using the precise HelmRepositoryStatus.Artifact
+                  data is recommended.
+                type: string
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.12.0
+  labels:
+    app.kubernetes.io/component: source-controller
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+  name: ocirepositories.source.toolkit.fluxcd.io
+spec:
+  group: source.toolkit.fluxcd.io
+  names:
+    kind: OCIRepository
+    listKind: OCIRepositoryList
+    plural: ocirepositories
+    shortNames:
+    - ocirepo
+    singular: ocirepository
+  scope: Namespaced
+  versions:
+  - additionalPrinterColumns:
+    - jsonPath: .spec.url
+      name: URL
+      type: string
+    - jsonPath: .status.conditions[?(@.type=="Ready")].status
+      name: Ready
+      type: string
+    - jsonPath: .status.conditions[?(@.type=="Ready")].message
+      name: Status
+      type: string
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    name: v1beta2
+    schema:
+      openAPIV3Schema:
+        description: OCIRepository is the Schema for the ocirepositories API
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: OCIRepositorySpec defines the desired state of OCIRepository
+            properties:
+              certSecretRef:
+                description: "CertSecretRef can be given the name of a Secret containing
+                  either or both of \n - a PEM-encoded client certificate (`tls.crt`)
+                  and private key (`tls.key`); - a PEM-encoded CA certificate (`ca.crt`)
+                  \n and whichever are supplied, will be used for connecting to the
+                  registry. The client cert and key are useful if you are authenticating
+                  with a certificate; the CA cert is useful if you are using a self-signed
+                  server certificate. The Secret must be of type `Opaque` or `kubernetes.io/tls`.
+                  \n Note: Support for the `caFile`, `certFile` and `keyFile` keys
+                  have been deprecated."
+                properties:
+                  name:
+                    description: Name of the referent.
+                    type: string
+                required:
+                - name
+                type: object
+              ignore:
+                description: Ignore overrides the set of excluded patterns in the
+                  .sourceignore format (which is the same as .gitignore). If not provided,
+                  a default will be used, consult the documentation for your version
+                  to find out what those are.
+                type: string
+              insecure:
+                description: Insecure allows connecting to a non-TLS HTTP container
+                  registry.
+                type: boolean
+              interval:
+                description: Interval at which the OCIRepository URL is checked for
+                  updates. This interval is approximate and may be subject to jitter
+                  to ensure efficient use of resources.
+                pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
+                type: string
+              layerSelector:
+                description: LayerSelector specifies which layer should be extracted
+                  from the OCI artifact. When not specified, the first layer found
+                  in the artifact is selected.
+                properties:
+                  mediaType:
+                    description: MediaType specifies the OCI media type of the layer
+                      which should be extracted from the OCI Artifact. The first layer
+                      matching this type is selected.
+                    type: string
+                  operation:
+                    description: Operation specifies how the selected layer should
+                      be processed. By default, the layer compressed content is extracted
+                      to storage. When the operation is set to 'copy', the layer compressed
+                      content is persisted to storage as it is.
+                    enum:
+                    - extract
+                    - copy
+                    type: string
+                type: object
+              provider:
+                default: generic
+                description: The provider used for authentication, can be 'aws', 'azure',
+                  'gcp' or 'generic'. When not specified, defaults to 'generic'.
+                enum:
+                - generic
+                - aws
+                - azure
+                - gcp
+                type: string
+              ref:
+                description: The OCI reference to pull and monitor for changes, defaults
+                  to the latest tag.
+                properties:
+                  digest:
+                    description: Digest is the image digest to pull, takes precedence
+                      over SemVer. The value should be in the format 'sha256:<HASH>'.
+                    type: string
+                  semver:
+                    description: SemVer is the range of tags to pull selecting the
+                      latest within the range, takes precedence over Tag.
+                    type: string
+                  tag:
+                    description: Tag is the image tag to pull, defaults to latest.
+                    type: string
+                type: object
+              secretRef:
+                description: SecretRef contains the secret name containing the registry
+                  login credentials to resolve image metadata. The secret must be
+                  of type kubernetes.io/dockerconfigjson.
+                properties:
+                  name:
+                    description: Name of the referent.
+                    type: string
+                required:
+                - name
+                type: object
+              serviceAccountName:
+                description: 'ServiceAccountName is the name of the Kubernetes ServiceAccount
+                  used to authenticate the image pull if the service account has attached
+                  pull secrets. For more information: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account'
+                type: string
+              suspend:
+                description: This flag tells the controller to suspend the reconciliation
+                  of this source.
+                type: boolean
+              timeout:
+                default: 60s
+                description: The timeout for remote OCI Repository operations like
+                  pulling, defaults to 60s.
+                pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$
+                type: string
+              url:
+                description: URL is a reference to an OCI artifact repository hosted
+                  on a remote container registry.
+                pattern: ^oci://.*$
+                type: string
+              verify:
+                description: Verify contains the secret name containing the trusted
+                  public keys used to verify the signature and specifies which provider
+                  to use to check whether OCI image is authentic.
+                properties:
+                  provider:
+                    default: cosign
+                    description: Provider specifies the technology used to sign the
+                      OCI Artifact.
+                    enum:
+                    - cosign
+                    type: string
+                  secretRef:
+                    description: SecretRef specifies the Kubernetes Secret containing
+                      the trusted public keys.
+                    properties:
+                      name:
+                        description: Name of the referent.
+                        type: string
+                    required:
+                    - name
+                    type: object
+                required:
+                - provider
+                type: object
+            required:
+            - interval
+            - url
+            type: object
+          status:
+            default:
+              observedGeneration: -1
+            description: OCIRepositoryStatus defines the observed state of OCIRepository
+            properties:
+              artifact:
+                description: Artifact represents the output of the last successful
+                  OCI Repository sync.
+                properties:
+                  digest:
+                    description: Digest is the digest of the file in the form of '<algorithm>:<checksum>'.
+                    pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$
+                    type: string
+                  lastUpdateTime:
+                    description: LastUpdateTime is the timestamp corresponding to
+                      the last update of the Artifact.
+                    format: date-time
+                    type: string
+                  metadata:
+                    additionalProperties:
+                      type: string
+                    description: Metadata holds upstream information such as OCI annotations.
+                    type: object
+                  path:
+                    description: Path is the relative file path of the Artifact. It
+                      can be used to locate the file in the root of the Artifact storage
+                      on the local file system of the controller managing the Source.
+                    type: string
+                  revision:
+                    description: Revision is a human-readable identifier traceable
+                      in the origin source system. It can be a Git commit SHA, Git
+                      tag, a Helm chart version, etc.
+                    type: string
+                  size:
+                    description: Size is the number of bytes in the file.
+                    format: int64
+                    type: integer
+                  url:
+                    description: URL is the HTTP address of the Artifact as exposed
+                      by the controller managing the Source. It can be used to retrieve
+                      the Artifact for consumption, e.g. by another controller applying
+                      the Artifact contents.
+                    type: string
+                required:
+                - lastUpdateTime
+                - path
+                - revision
+                - url
+                type: object
+              conditions:
+                description: Conditions holds the conditions for the OCIRepository.
+                items:
+                  description: "Condition contains details for one aspect of the current
+                    state of this API Resource. --- This struct is intended for direct
+                    use as an array at the field path .status.conditions.  For example,
+                    \n type FooStatus struct{ // Represents the observations of a
+                    foo's current state. // Known .status.conditions.type are: \"Available\",
+                    \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
+                    // +listType=map // +listMapKey=type Conditions []metav1.Condition
+                    `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
+                    protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
+                  properties:
+                    lastTransitionTime:
+                      description: lastTransitionTime is the last time the condition
+                        transitioned from one status to another. This should be when
+                        the underlying condition changed.  If that is not known, then
+                        using the time when the API field changed is acceptable.
+                      format: date-time
+                      type: string
+                    message:
+                      description: message is a human readable message indicating
+                        details about the transition. This may be an empty string.
+                      maxLength: 32768
+                      type: string
+                    observedGeneration:
+                      description: observedGeneration represents the .metadata.generation
+                        that the condition was set based upon. For instance, if .metadata.generation
+                        is currently 12, but the .status.conditions[x].observedGeneration
+                        is 9, the condition is out of date with respect to the current
+                        state of the instance.
+                      format: int64
+                      minimum: 0
+                      type: integer
+                    reason:
+                      description: reason contains a programmatic identifier indicating
+                        the reason for the condition's last transition. Producers
+                        of specific condition types may define expected values and
+                        meanings for this field, and whether the values are considered
+                        a guaranteed API. The value should be a CamelCase string.
+                        This field may not be empty.
+                      maxLength: 1024
+                      minLength: 1
+                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+                      type: string
+                    status:
+                      description: status of the condition, one of True, False, Unknown.
+                      enum:
+                      - "True"
+                      - "False"
+                      - Unknown
+                      type: string
+                    type:
+                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
+                        --- Many .condition.type values are consistent across resources
+                        like Available, but because arbitrary conditions can be useful
+                        (see .node.status.conditions), the ability to deconflict is
+                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
+                      maxLength: 316
+                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - message
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+              contentConfigChecksum:
+                description: "ContentConfigChecksum is a checksum of all the configurations
+                  related to the content of the source artifact: - .spec.ignore -
+                  .spec.layerSelector observed in .status.observedGeneration version
+                  of the object. This can be used to determine if the content configuration
+                  has changed and the artifact needs to be rebuilt. It has the format
+                  of `<algo>:<checksum>`, for example: `sha256:<checksum>`. \n Deprecated:
+                  Replaced with explicit fields for observed artifact content config
+                  in the status."
+                type: string
+              lastHandledReconcileAt:
+                description: LastHandledReconcileAt holds the value of the most recent
+                  reconcile request value, so a change of the annotation value can
+                  be detected.
+                type: string
+              observedGeneration:
+                description: ObservedGeneration is the last observed generation.
+                format: int64
+                type: integer
+              observedIgnore:
+                description: ObservedIgnore is the observed exclusion patterns used
+                  for constructing the source artifact.
+                type: string
+              observedLayerSelector:
+                description: ObservedLayerSelector is the observed layer selector
+                  used for constructing the source artifact.
+                properties:
+                  mediaType:
+                    description: MediaType specifies the OCI media type of the layer
+                      which should be extracted from the OCI Artifact. The first layer
+                      matching this type is selected.
+                    type: string
+                  operation:
+                    description: Operation specifies how the selected layer should
+                      be processed. By default, the layer compressed content is extracted
+                      to storage. When the operation is set to 'copy', the layer compressed
+                      content is persisted to storage as it is.
+                    enum:
+                    - extract
+                    - copy
+                    type: string
+                type: object
+              url:
+                description: URL is the download link for the artifact output of the
+                  last OCI Repository sync.
+                type: string
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  labels:
+    app.kubernetes.io/component: source-controller
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+  name: source-controller
+  namespace: flux-system
+---
+apiVersion: v1
+kind: Service
+metadata:
+  labels:
+    app.kubernetes.io/component: source-controller
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+    control-plane: controller
+  name: source-controller
+  namespace: flux-system
+spec:
+  ports:
+  - name: http
+    port: 80
+    protocol: TCP
+    targetPort: http
+  selector:
+    app: source-controller
+  type: ClusterIP
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  labels:
+    app.kubernetes.io/component: source-controller
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+    control-plane: controller
+  name: source-controller
+  namespace: flux-system
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: source-controller
+  strategy:
+    type: Recreate
+  template:
+    metadata:
+      annotations:
+        prometheus.io/port: "8080"
+        prometheus.io/scrape: "true"
+      labels:
+        app: source-controller
+    spec:
+      containers:
+      - args:
+        - --events-addr=http://notification-controller.flux-system.svc.cluster.local./
+        - --watch-all-namespaces=true
+        - --log-level=info
+        - --log-encoding=json
+        - --enable-leader-election
+        - --storage-path=/data
+        - --storage-adv-addr=source-controller.$(RUNTIME_NAMESPACE).svc.cluster.local.
+        env:
+        - name: RUNTIME_NAMESPACE
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.namespace
+        - name: TUF_ROOT
+          value: /tmp/.sigstore
+        image: ghcr.io/fluxcd/source-controller:v1.1.2
+        imagePullPolicy: IfNotPresent
+        livenessProbe:
+          httpGet:
+            path: /healthz
+            port: healthz
+        name: manager
+        ports:
+        - containerPort: 9090
+          name: http
+          protocol: TCP
+        - containerPort: 8080
+          name: http-prom
+          protocol: TCP
+        - containerPort: 9440
+          name: healthz
+          protocol: TCP
+        readinessProbe:
+          httpGet:
+            path: /
+            port: http
+        resources:
+          limits:
+            cpu: 1000m
+            memory: 1Gi
+          requests:
+            cpu: 50m
+            memory: 64Mi
+        securityContext:
+          allowPrivilegeEscalation: false
+          capabilities:
+            drop:
+            - ALL
+          readOnlyRootFilesystem: true
+          runAsNonRoot: true
+          seccompProfile:
+            type: RuntimeDefault
+        volumeMounts:
+        - mountPath: /data
+          name: data
+        - mountPath: /tmp
+          name: tmp
+      nodeSelector:
+        kubernetes.io/os: linux
+      priorityClassName: system-cluster-critical
+      securityContext:
+        fsGroup: 1337
+      serviceAccountName: source-controller
+      terminationGracePeriodSeconds: 10
+      volumes:
+      - emptyDir: {}
+        name: data
+      - emptyDir: {}
+        name: tmp
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.12.0
+  labels:
+    app.kubernetes.io/component: kustomize-controller
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+  name: kustomizations.kustomize.toolkit.fluxcd.io
+spec:
+  group: kustomize.toolkit.fluxcd.io
+  names:
+    kind: Kustomization
+    listKind: KustomizationList
+    plural: kustomizations
+    shortNames:
+    - ks
+    singular: kustomization
+  scope: Namespaced
+  versions:
+  - additionalPrinterColumns:
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    - jsonPath: .status.conditions[?(@.type=="Ready")].status
+      name: Ready
+      type: string
+    - jsonPath: .status.conditions[?(@.type=="Ready")].message
+      name: Status
+      type: string
+    name: v1
+    schema:
+      openAPIV3Schema:
+        description: Kustomization is the Schema for the kustomizations API.
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: KustomizationSpec defines the configuration to calculate
+              the desired state from a Source using Kustomize.
+            properties:
+              commonMetadata:
+                description: CommonMetadata specifies the common labels and annotations
+                  that are applied to all resources. Any existing label or annotation
+                  will be overridden if its key matches a common one.
+                properties:
+                  annotations:
+                    additionalProperties:
+                      type: string
+                    description: Annotations to be added to the object's metadata.
+                    type: object
+                  labels:
+                    additionalProperties:
+                      type: string
+                    description: Labels to be added to the object's metadata.
+                    type: object
+                type: object
+              components:
+                description: Components specifies relative paths to specifications
+                  of other Components.
+                items:
+                  type: string
+                type: array
+              decryption:
+                description: Decrypt Kubernetes secrets before applying them on the
+                  cluster.
+                properties:
+                  provider:
+                    description: Provider is the name of the decryption engine.
+                    enum:
+                    - sops
+                    type: string
+                  secretRef:
+                    description: The secret name containing the private OpenPGP keys
+                      used for decryption.
+                    properties:
+                      name:
+                        description: Name of the referent.
+                        type: string
+                    required:
+                    - name
+                    type: object
+                required:
+                - provider
+                type: object
+              dependsOn:
+                description: DependsOn may contain a meta.NamespacedObjectReference
+                  slice with references to Kustomization resources that must be ready
+                  before this Kustomization can be reconciled.
+                items:
+                  description: NamespacedObjectReference contains enough information
+                    to locate the referenced Kubernetes resource object in any namespace.
+                  properties:
+                    name:
+                      description: Name of the referent.
+                      type: string
+                    namespace:
+                      description: Namespace of the referent, when not specified it
+                        acts as LocalObjectReference.
+                      type: string
+                  required:
+                  - name
+                  type: object
+                type: array
+              force:
+                default: false
+                description: Force instructs the controller to recreate resources
+                  when patching fails due to an immutable field change.
+                type: boolean
+              healthChecks:
+                description: A list of resources to be included in the health assessment.
+                items:
+                  description: NamespacedObjectKindReference contains enough information
+                    to locate the typed referenced Kubernetes resource object in any
+                    namespace.
+                  properties:
+                    apiVersion:
+                      description: API version of the referent, if not specified the
+                        Kubernetes preferred version will be used.
+                      type: string
+                    kind:
+                      description: Kind of the referent.
+                      type: string
+                    name:
+                      description: Name of the referent.
+                      type: string
+                    namespace:
+                      description: Namespace of the referent, when not specified it
+                        acts as LocalObjectReference.
+                      type: string
+                  required:
+                  - kind
+                  - name
+                  type: object
+                type: array
+              images:
+                description: Images is a list of (image name, new name, new tag or
+                  digest) for changing image names, tags or digests. This can also
+                  be achieved with a patch, but this operator is simpler to specify.
+                items:
+                  description: Image contains an image name, a new name, a new tag
+                    or digest, which will replace the original name and tag.
+                  properties:
+                    digest:
+                      description: Digest is the value used to replace the original
+                        image tag. If digest is present NewTag value is ignored.
+                      type: string
+                    name:
+                      description: Name is a tag-less image name.
+                      type: string
+                    newName:
+                      description: NewName is the value used to replace the original
+                        name.
+                      type: string
+                    newTag:
+                      description: NewTag is the value used to replace the original
+                        tag.
+                      type: string
+                  required:
+                  - name
+                  type: object
+                type: array
+              interval:
+                description: The interval at which to reconcile the Kustomization.
+                  This interval is approximate and may be subject to jitter to ensure
+                  efficient use of resources.
+                pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
+                type: string
+              kubeConfig:
+                description: The KubeConfig for reconciling the Kustomization on a
+                  remote cluster. When used in combination with KustomizationSpec.ServiceAccountName,
+                  forces the controller to act on behalf of that Service Account at
+                  the target cluster. If the --default-service-account flag is set,
+                  its value will be used as a controller level fallback for when KustomizationSpec.ServiceAccountName
+                  is empty.
+                properties:
+                  secretRef:
+                    description: SecretRef holds the name of a secret that contains
+                      a key with the kubeconfig file as the value. If no key is set,
+                      the key will default to 'value'. It is recommended that the
+                      kubeconfig is self-contained, and the secret is regularly updated
+                      if credentials such as a cloud-access-token expire. Cloud specific
+                      `cmd-path` auth helpers will not function without adding binaries
+                      and credentials to the Pod that is responsible for reconciling
+                      Kubernetes resources.
+                    properties:
+                      key:
+                        description: Key in the Secret, when not specified an implementation-specific
+                          default key is used.
+                        type: string
+                      name:
+                        description: Name of the Secret.
+                        type: string
+                    required:
+                    - name
+                    type: object
+                required:
+                - secretRef
+                type: object
+              patches:
+                description: Strategic merge and JSON patches, defined as inline YAML
+                  objects, capable of targeting objects based on kind, label and annotation
+                  selectors.
+                items:
+                  description: Patch contains an inline StrategicMerge or JSON6902
+                    patch, and the target the patch should be applied to.
+                  properties:
+                    patch:
+                      description: Patch contains an inline StrategicMerge patch or
+                        an inline JSON6902 patch with an array of operation objects.
+                      type: string
+                    target:
+                      description: Target points to the resources that the patch document
+                        should be applied to.
+                      properties:
+                        annotationSelector:
+                          description: AnnotationSelector is a string that follows
+                            the label selection expression https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api
+                            It matches with the resource annotations.
+                          type: string
+                        group:
+                          description: Group is the API group to select resources
+                            from. Together with Version and Kind it is capable of
+                            unambiguously identifying and/or selecting resources.
+                            https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md
+                          type: string
+                        kind:
+                          description: Kind of the API Group to select resources from.
+                            Together with Group and Version it is capable of unambiguously
+                            identifying and/or selecting resources. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md
+                          type: string
+                        labelSelector:
+                          description: LabelSelector is a string that follows the
+                            label selection expression https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api
+                            It matches with the resource labels.
+                          type: string
+                        name:
+                          description: Name to match resources with.
+                          type: string
+                        namespace:
+                          description: Namespace to select resources from.
+                          type: string
+                        version:
+                          description: Version of the API Group to select resources
+                            from. Together with Group and Kind it is capable of unambiguously
+                            identifying and/or selecting resources. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md
+                          type: string
+                      type: object
+                  required:
+                  - patch
+                  type: object
+                type: array
+              path:
+                description: Path to the directory containing the kustomization.yaml
+                  file, or the set of plain YAMLs a kustomization.yaml should be generated
+                  for. Defaults to 'None', which translates to the root path of the
+                  SourceRef.
+                type: string
+              postBuild:
+                description: PostBuild describes which actions to perform on the YAML
+                  manifest generated by building the kustomize overlay.
+                properties:
+                  substitute:
+                    additionalProperties:
+                      type: string
+                    description: Substitute holds a map of key/value pairs. The variables
+                      defined in your YAML manifests that match any of the keys defined
+                      in the map will be substituted with the set value. Includes
+                      support for bash string replacement functions e.g. ${var:=default},
+                      ${var:position} and ${var/substring/replacement}.
+                    type: object
+                  substituteFrom:
+                    description: SubstituteFrom holds references to ConfigMaps and
+                      Secrets containing the variables and their values to be substituted
+                      in the YAML manifests. The ConfigMap and the Secret data keys
+                      represent the var names, and they must match the vars declared
+                      in the manifests for the substitution to happen.
+                    items:
+                      description: SubstituteReference contains a reference to a resource
+                        containing the variables name and value.
+                      properties:
+                        kind:
+                          description: Kind of the values referent, valid values are
+                            ('Secret', 'ConfigMap').
+                          enum:
+                          - Secret
+                          - ConfigMap
+                          type: string
+                        name:
+                          description: Name of the values referent. Should reside
+                            in the same namespace as the referring resource.
+                          maxLength: 253
+                          minLength: 1
+                          type: string
+                        optional:
+                          default: false
+                          description: Optional indicates whether the referenced resource
+                            must exist, or whether to tolerate its absence. If true
+                            and the referenced resource is absent, proceed as if the
+                            resource was present but empty, without any variables
+                            defined.
+                          type: boolean
+                      required:
+                      - kind
+                      - name
+                      type: object
+                    type: array
+                type: object
+              prune:
+                description: Prune enables garbage collection.
+                type: boolean
+              retryInterval:
+                description: The interval at which to retry a previously failed reconciliation.
+                  When not specified, the controller uses the KustomizationSpec.Interval
+                  value to retry failures.
+                pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
+                type: string
+              serviceAccountName:
+                description: The name of the Kubernetes service account to impersonate
+                  when reconciling this Kustomization.
+                type: string
+              sourceRef:
+                description: Reference of the source where the kustomization file
+                  is.
+                properties:
+                  apiVersion:
+                    description: API version of the referent.
+                    type: string
+                  kind:
+                    description: Kind of the referent.
+                    enum:
+                    - OCIRepository
+                    - GitRepository
+                    - Bucket
+                    type: string
+                  name:
+                    description: Name of the referent.
+                    type: string
+                  namespace:
+                    description: Namespace of the referent, defaults to the namespace
+                      of the Kubernetes resource object that contains the reference.
+                    type: string
+                required:
+                - kind
+                - name
+                type: object
+              suspend:
+                description: This flag tells the controller to suspend subsequent
+                  kustomize executions, it does not apply to already started executions.
+                  Defaults to false.
+                type: boolean
+              targetNamespace:
+                description: TargetNamespace sets or overrides the namespace in the
+                  kustomization.yaml file.
+                maxLength: 63
+                minLength: 1
+                type: string
+              timeout:
+                description: Timeout for validation, apply and health checking operations.
+                  Defaults to 'Interval' duration.
+                pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
+                type: string
+              wait:
+                description: Wait instructs the controller to check the health of
+                  all the reconciled resources. When enabled, the HealthChecks are
+                  ignored. Defaults to false.
+                type: boolean
+            required:
+            - interval
+            - prune
+            - sourceRef
+            type: object
+          status:
+            default:
+              observedGeneration: -1
+            description: KustomizationStatus defines the observed state of a kustomization.
+            properties:
+              conditions:
+                items:
+                  description: "Condition contains details for one aspect of the current
+                    state of this API Resource. --- This struct is intended for direct
+                    use as an array at the field path .status.conditions.  For example,
+                    \n type FooStatus struct{ // Represents the observations of a
+                    foo's current state. // Known .status.conditions.type are: \"Available\",
+                    \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
+                    // +listType=map // +listMapKey=type Conditions []metav1.Condition
+                    `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
+                    protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
+                  properties:
+                    lastTransitionTime:
+                      description: lastTransitionTime is the last time the condition
+                        transitioned from one status to another. This should be when
+                        the underlying condition changed.  If that is not known, then
+                        using the time when the API field changed is acceptable.
+                      format: date-time
+                      type: string
+                    message:
+                      description: message is a human readable message indicating
+                        details about the transition. This may be an empty string.
+                      maxLength: 32768
+                      type: string
+                    observedGeneration:
+                      description: observedGeneration represents the .metadata.generation
+                        that the condition was set based upon. For instance, if .metadata.generation
+                        is currently 12, but the .status.conditions[x].observedGeneration
+                        is 9, the condition is out of date with respect to the current
+                        state of the instance.
+                      format: int64
+                      minimum: 0
+                      type: integer
+                    reason:
+                      description: reason contains a programmatic identifier indicating
+                        the reason for the condition's last transition. Producers
+                        of specific condition types may define expected values and
+                        meanings for this field, and whether the values are considered
+                        a guaranteed API. The value should be a CamelCase string.
+                        This field may not be empty.
+                      maxLength: 1024
+                      minLength: 1
+                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+                      type: string
+                    status:
+                      description: status of the condition, one of True, False, Unknown.
+                      enum:
+                      - "True"
+                      - "False"
+                      - Unknown
+                      type: string
+                    type:
+                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
+                        --- Many .condition.type values are consistent across resources
+                        like Available, but because arbitrary conditions can be useful
+                        (see .node.status.conditions), the ability to deconflict is
+                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
+                      maxLength: 316
+                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - message
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+              inventory:
+                description: Inventory contains the list of Kubernetes resource object
+                  references that have been successfully applied.
+                properties:
+                  entries:
+                    description: Entries of Kubernetes resource object references.
+                    items:
+                      description: ResourceRef contains the information necessary
+                        to locate a resource within a cluster.
+                      properties:
+                        id:
+                          description: ID is the string representation of the Kubernetes
+                            resource object's metadata, in the format '<namespace>_<name>_<group>_<kind>'.
+                          type: string
+                        v:
+                          description: Version is the API version of the Kubernetes
+                            resource object's kind.
+                          type: string
+                      required:
+                      - id
+                      - v
+                      type: object
+                    type: array
+                required:
+                - entries
+                type: object
+              lastAppliedRevision:
+                description: The last successfully applied revision. Equals the Revision
+                  of the applied Artifact from the referenced Source.
+                type: string
+              lastAttemptedRevision:
+                description: LastAttemptedRevision is the revision of the last reconciliation
+                  attempt.
+                type: string
+              lastHandledReconcileAt:
+                description: LastHandledReconcileAt holds the value of the most recent
+                  reconcile request value, so a change of the annotation value can
+                  be detected.
+                type: string
+              observedGeneration:
+                description: ObservedGeneration is the last reconciled generation.
+                format: int64
+                type: integer
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+  - additionalPrinterColumns:
+    - jsonPath: .status.conditions[?(@.type=="Ready")].status
+      name: Ready
+      type: string
+    - jsonPath: .status.conditions[?(@.type=="Ready")].message
+      name: Status
+      type: string
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    deprecated: true
+    deprecationWarning: v1beta1 Kustomization is deprecated, upgrade to v1
+    name: v1beta1
+    schema:
+      openAPIV3Schema:
+        description: Kustomization is the Schema for the kustomizations API.
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: KustomizationSpec defines the desired state of a kustomization.
+            properties:
+              decryption:
+                description: Decrypt Kubernetes secrets before applying them on the
+                  cluster.
+                properties:
+                  provider:
+                    description: Provider is the name of the decryption engine.
+                    enum:
+                    - sops
+                    type: string
+                  secretRef:
+                    description: The secret name containing the private OpenPGP keys
+                      used for decryption.
+                    properties:
+                      name:
+                        description: Name of the referent.
+                        type: string
+                    required:
+                    - name
+                    type: object
+                required:
+                - provider
+                type: object
+              dependsOn:
+                description: DependsOn may contain a meta.NamespacedObjectReference
+                  slice with references to Kustomization resources that must be ready
+                  before this Kustomization can be reconciled.
+                items:
+                  description: NamespacedObjectReference contains enough information
+                    to locate the referenced Kubernetes resource object in any namespace.
+                  properties:
+                    name:
+                      description: Name of the referent.
+                      type: string
+                    namespace:
+                      description: Namespace of the referent, when not specified it
+                        acts as LocalObjectReference.
+                      type: string
+                  required:
+                  - name
+                  type: object
+                type: array
+              force:
+                default: false
+                description: Force instructs the controller to recreate resources
+                  when patching fails due to an immutable field change.
+                type: boolean
+              healthChecks:
+                description: A list of resources to be included in the health assessment.
+                items:
+                  description: NamespacedObjectKindReference contains enough information
+                    to locate the typed referenced Kubernetes resource object in any
+                    namespace.
+                  properties:
+                    apiVersion:
+                      description: API version of the referent, if not specified the
+                        Kubernetes preferred version will be used.
+                      type: string
+                    kind:
+                      description: Kind of the referent.
+                      type: string
+                    name:
+                      description: Name of the referent.
+                      type: string
+                    namespace:
+                      description: Namespace of the referent, when not specified it
+                        acts as LocalObjectReference.
+                      type: string
+                  required:
+                  - kind
+                  - name
+                  type: object
+                type: array
+              images:
+                description: Images is a list of (image name, new name, new tag or
+                  digest) for changing image names, tags or digests. This can also
+                  be achieved with a patch, but this operator is simpler to specify.
+                items:
+                  description: Image contains an image name, a new name, a new tag
+                    or digest, which will replace the original name and tag.
+                  properties:
+                    digest:
+                      description: Digest is the value used to replace the original
+                        image tag. If digest is present NewTag value is ignored.
+                      type: string
+                    name:
+                      description: Name is a tag-less image name.
+                      type: string
+                    newName:
+                      description: NewName is the value used to replace the original
+                        name.
+                      type: string
+                    newTag:
+                      description: NewTag is the value used to replace the original
+                        tag.
+                      type: string
+                  required:
+                  - name
+                  type: object
+                type: array
+              interval:
+                description: The interval at which to reconcile the Kustomization.
+                type: string
+              kubeConfig:
+                description: The KubeConfig for reconciling the Kustomization on a
+                  remote cluster. When specified, KubeConfig takes precedence over
+                  ServiceAccountName.
+                properties:
+                  secretRef:
+                    description: SecretRef holds the name to a secret that contains
+                      a 'value' key with the kubeconfig file as the value. It must
+                      be in the same namespace as the Kustomization. It is recommended
+                      that the kubeconfig is self-contained, and the secret is regularly
+                      updated if credentials such as a cloud-access-token expire.
+                      Cloud specific `cmd-path` auth helpers will not function without
+                      adding binaries and credentials to the Pod that is responsible
+                      for reconciling the Kustomization.
+                    properties:
+                      name:
+                        description: Name of the referent.
+                        type: string
+                    required:
+                    - name
+                    type: object
+                type: object
+              patches:
+                description: Strategic merge and JSON patches, defined as inline YAML
+                  objects, capable of targeting objects based on kind, label and annotation
+                  selectors.
+                items:
+                  description: Patch contains an inline StrategicMerge or JSON6902
+                    patch, and the target the patch should be applied to.
+                  properties:
+                    patch:
+                      description: Patch contains an inline StrategicMerge patch or
+                        an inline JSON6902 patch with an array of operation objects.
+                      type: string
+                    target:
+                      description: Target points to the resources that the patch document
+                        should be applied to.
+                      properties:
+                        annotationSelector:
+                          description: AnnotationSelector is a string that follows
+                            the label selection expression https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api
+                            It matches with the resource annotations.
+                          type: string
+                        group:
+                          description: Group is the API group to select resources
+                            from. Together with Version and Kind it is capable of
+                            unambiguously identifying and/or selecting resources.
+                            https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md
+                          type: string
+                        kind:
+                          description: Kind of the API Group to select resources from.
+                            Together with Group and Version it is capable of unambiguously
+                            identifying and/or selecting resources. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md
+                          type: string
+                        labelSelector:
+                          description: LabelSelector is a string that follows the
+                            label selection expression https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api
+                            It matches with the resource labels.
+                          type: string
+                        name:
+                          description: Name to match resources with.
+                          type: string
+                        namespace:
+                          description: Namespace to select resources from.
+                          type: string
+                        version:
+                          description: Version of the API Group to select resources
+                            from. Together with Group and Kind it is capable of unambiguously
+                            identifying and/or selecting resources. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md
+                          type: string
+                      type: object
+                  required:
+                  - patch
+                  type: object
+                type: array
+              patchesJson6902:
+                description: JSON 6902 patches, defined as inline YAML objects.
+                items:
+                  description: JSON6902Patch contains a JSON6902 patch and the target
+                    the patch should be applied to.
+                  properties:
+                    patch:
+                      description: Patch contains the JSON6902 patch document with
+                        an array of operation objects.
+                      items:
+                        description: JSON6902 is a JSON6902 operation object. https://datatracker.ietf.org/doc/html/rfc6902#section-4
+                        properties:
+                          from:
+                            description: From contains a JSON-pointer value that references
+                              a location within the target document where the operation
+                              is performed. The meaning of the value depends on the
+                              value of Op, and is NOT taken into account by all operations.
+                            type: string
+                          op:
+                            description: Op indicates the operation to perform. Its
+                              value MUST be one of "add", "remove", "replace", "move",
+                              "copy", or "test". https://datatracker.ietf.org/doc/html/rfc6902#section-4
+                            enum:
+                            - test
+                            - remove
+                            - add
+                            - replace
+                            - move
+                            - copy
+                            type: string
+                          path:
+                            description: Path contains the JSON-pointer value that
+                              references a location within the target document where
+                              the operation is performed. The meaning of the value
+                              depends on the value of Op.
+                            type: string
+                          value:
+                            description: Value contains a valid JSON structure. The
+                              meaning of the value depends on the value of Op, and
+                              is NOT taken into account by all operations.
+                            x-kubernetes-preserve-unknown-fields: true
+                        required:
+                        - op
+                        - path
+                        type: object
+                      type: array
+                    target:
+                      description: Target points to the resources that the patch document
+                        should be applied to.
+                      properties:
+                        annotationSelector:
+                          description: AnnotationSelector is a string that follows
+                            the label selection expression https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api
+                            It matches with the resource annotations.
+                          type: string
+                        group:
+                          description: Group is the API group to select resources
+                            from. Together with Version and Kind it is capable of
+                            unambiguously identifying and/or selecting resources.
+                            https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md
+                          type: string
+                        kind:
+                          description: Kind of the API Group to select resources from.
+                            Together with Group and Version it is capable of unambiguously
+                            identifying and/or selecting resources. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md
+                          type: string
+                        labelSelector:
+                          description: LabelSelector is a string that follows the
+                            label selection expression https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api
+                            It matches with the resource labels.
+                          type: string
+                        name:
+                          description: Name to match resources with.
+                          type: string
+                        namespace:
+                          description: Namespace to select resources from.
+                          type: string
+                        version:
+                          description: Version of the API Group to select resources
+                            from. Together with Group and Kind it is capable of unambiguously
+                            identifying and/or selecting resources. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md
+                          type: string
+                      type: object
+                  required:
+                  - patch
+                  - target
+                  type: object
+                type: array
+              patchesStrategicMerge:
+                description: Strategic merge patches, defined as inline YAML objects.
+                items:
+                  x-kubernetes-preserve-unknown-fields: true
+                type: array
+              path:
+                description: Path to the directory containing the kustomization.yaml
+                  file, or the set of plain YAMLs a kustomization.yaml should be generated
+                  for. Defaults to 'None', which translates to the root path of the
+                  SourceRef.
+                type: string
+              postBuild:
+                description: PostBuild describes which actions to perform on the YAML
+                  manifest generated by building the kustomize overlay.
+                properties:
+                  substitute:
+                    additionalProperties:
+                      type: string
+                    description: Substitute holds a map of key/value pairs. The variables
+                      defined in your YAML manifests that match any of the keys defined
+                      in the map will be substituted with the set value. Includes
+                      support for bash string replacement functions e.g. ${var:=default},
+                      ${var:position} and ${var/substring/replacement}.
+                    type: object
+                  substituteFrom:
+                    description: SubstituteFrom holds references to ConfigMaps and
+                      Secrets containing the variables and their values to be substituted
+                      in the YAML manifests. The ConfigMap and the Secret data keys
+                      represent the var names and they must match the vars declared
+                      in the manifests for the substitution to happen.
+                    items:
+                      description: SubstituteReference contains a reference to a resource
+                        containing the variables name and value.
+                      properties:
+                        kind:
+                          description: Kind of the values referent, valid values are
+                            ('Secret', 'ConfigMap').
+                          enum:
+                          - Secret
+                          - ConfigMap
+                          type: string
+                        name:
+                          description: Name of the values referent. Should reside
+                            in the same namespace as the referring resource.
+                          maxLength: 253
+                          minLength: 1
+                          type: string
+                      required:
+                      - kind
+                      - name
+                      type: object
+                    type: array
+                type: object
+              prune:
+                description: Prune enables garbage collection.
+                type: boolean
+              retryInterval:
+                description: The interval at which to retry a previously failed reconciliation.
+                  When not specified, the controller uses the KustomizationSpec.Interval
+                  value to retry failures.
+                type: string
+              serviceAccountName:
+                description: The name of the Kubernetes service account to impersonate
+                  when reconciling this Kustomization.
+                type: string
+              sourceRef:
+                description: Reference of the source where the kustomization file
+                  is.
+                properties:
+                  apiVersion:
+                    description: API version of the referent
+                    type: string
+                  kind:
+                    description: Kind of the referent
+                    enum:
+                    - GitRepository
+                    - Bucket
+                    type: string
+                  name:
+                    description: Name of the referent
+                    type: string
+                  namespace:
+                    description: Namespace of the referent, defaults to the Kustomization
+                      namespace
+                    type: string
+                required:
+                - kind
+                - name
+                type: object
+              suspend:
+                description: This flag tells the controller to suspend subsequent
+                  kustomize executions, it does not apply to already started executions.
+                  Defaults to false.
+                type: boolean
+              targetNamespace:
+                description: TargetNamespace sets or overrides the namespace in the
+                  kustomization.yaml file.
+                maxLength: 63
+                minLength: 1
+                type: string
+              timeout:
+                description: Timeout for validation, apply and health checking operations.
+                  Defaults to 'Interval' duration.
+                type: string
+              validation:
+                description: Validate the Kubernetes objects before applying them
+                  on the cluster. The validation strategy can be 'client' (local dry-run),
+                  'server' (APIServer dry-run) or 'none'. When 'Force' is 'true',
+                  validation will fallback to 'client' if set to 'server' because
+                  server-side validation is not supported in this scenario.
+                enum:
+                - none
+                - client
+                - server
+                type: string
+            required:
+            - interval
+            - prune
+            - sourceRef
+            type: object
+          status:
+            default:
+              observedGeneration: -1
+            description: KustomizationStatus defines the observed state of a kustomization.
+            properties:
+              conditions:
+                items:
+                  description: "Condition contains details for one aspect of the current
+                    state of this API Resource. --- This struct is intended for direct
+                    use as an array at the field path .status.conditions.  For example,
+                    \n type FooStatus struct{ // Represents the observations of a
+                    foo's current state. // Known .status.conditions.type are: \"Available\",
+                    \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
+                    // +listType=map // +listMapKey=type Conditions []metav1.Condition
+                    `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
+                    protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
+                  properties:
+                    lastTransitionTime:
+                      description: lastTransitionTime is the last time the condition
+                        transitioned from one status to another. This should be when
+                        the underlying condition changed.  If that is not known, then
+                        using the time when the API field changed is acceptable.
+                      format: date-time
+                      type: string
+                    message:
+                      description: message is a human readable message indicating
+                        details about the transition. This may be an empty string.
+                      maxLength: 32768
+                      type: string
+                    observedGeneration:
+                      description: observedGeneration represents the .metadata.generation
+                        that the condition was set based upon. For instance, if .metadata.generation
+                        is currently 12, but the .status.conditions[x].observedGeneration
+                        is 9, the condition is out of date with respect to the current
+                        state of the instance.
+                      format: int64
+                      minimum: 0
+                      type: integer
+                    reason:
+                      description: reason contains a programmatic identifier indicating
+                        the reason for the condition's last transition. Producers
+                        of specific condition types may define expected values and
+                        meanings for this field, and whether the values are considered
+                        a guaranteed API. The value should be a CamelCase string.
+                        This field may not be empty.
+                      maxLength: 1024
+                      minLength: 1
+                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+                      type: string
+                    status:
+                      description: status of the condition, one of True, False, Unknown.
+                      enum:
+                      - "True"
+                      - "False"
+                      - Unknown
+                      type: string
+                    type:
+                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
+                        --- Many .condition.type values are consistent across resources
+                        like Available, but because arbitrary conditions can be useful
+                        (see .node.status.conditions), the ability to deconflict is
+                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
+                      maxLength: 316
+                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - message
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+              lastAppliedRevision:
+                description: The last successfully applied revision. The revision
+                  format for Git sources is <branch|tag>/<commit-sha>.
+                type: string
+              lastAttemptedRevision:
+                description: LastAttemptedRevision is the revision of the last reconciliation
+                  attempt.
+                type: string
+              lastHandledReconcileAt:
+                description: LastHandledReconcileAt holds the value of the most recent
+                  reconcile request value, so a change of the annotation value can
+                  be detected.
+                type: string
+              observedGeneration:
+                description: ObservedGeneration is the last reconciled generation.
+                format: int64
+                type: integer
+              snapshot:
+                description: The last successfully applied revision metadata.
+                properties:
+                  checksum:
+                    description: The manifests sha1 checksum.
+                    type: string
+                  entries:
+                    description: A list of Kubernetes kinds grouped by namespace.
+                    items:
+                      description: Snapshot holds the metadata of namespaced Kubernetes
+                        objects
+                      properties:
+                        kinds:
+                          additionalProperties:
+                            type: string
+                          description: The list of Kubernetes kinds.
+                          type: object
+                        namespace:
+                          description: The namespace of this entry.
+                          type: string
+                      required:
+                      - kinds
+                      type: object
+                    type: array
+                required:
+                - checksum
+                - entries
+                type: object
+            type: object
+        type: object
+    served: true
+    storage: false
+    subresources:
+      status: {}
+  - additionalPrinterColumns:
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    - jsonPath: .status.conditions[?(@.type=="Ready")].status
+      name: Ready
+      type: string
+    - jsonPath: .status.conditions[?(@.type=="Ready")].message
+      name: Status
+      type: string
+    deprecated: true
+    deprecationWarning: v1beta2 Kustomization is deprecated, upgrade to v1
+    name: v1beta2
+    schema:
+      openAPIV3Schema:
+        description: Kustomization is the Schema for the kustomizations API.
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: KustomizationSpec defines the configuration to calculate
+              the desired state from a Source using Kustomize.
+            properties:
+              commonMetadata:
+                description: CommonMetadata specifies the common labels and annotations
+                  that are applied to all resources. Any existing label or annotation
+                  will be overridden if its key matches a common one.
+                properties:
+                  annotations:
+                    additionalProperties:
+                      type: string
+                    description: Annotations to be added to the object's metadata.
+                    type: object
+                  labels:
+                    additionalProperties:
+                      type: string
+                    description: Labels to be added to the object's metadata.
+                    type: object
+                type: object
+              components:
+                description: Components specifies relative paths to specifications
+                  of other Components.
+                items:
+                  type: string
+                type: array
+              decryption:
+                description: Decrypt Kubernetes secrets before applying them on the
+                  cluster.
+                properties:
+                  provider:
+                    description: Provider is the name of the decryption engine.
+                    enum:
+                    - sops
+                    type: string
+                  secretRef:
+                    description: The secret name containing the private OpenPGP keys
+                      used for decryption.
+                    properties:
+                      name:
+                        description: Name of the referent.
+                        type: string
+                    required:
+                    - name
+                    type: object
+                required:
+                - provider
+                type: object
+              dependsOn:
+                description: DependsOn may contain a meta.NamespacedObjectReference
+                  slice with references to Kustomization resources that must be ready
+                  before this Kustomization can be reconciled.
+                items:
+                  description: NamespacedObjectReference contains enough information
+                    to locate the referenced Kubernetes resource object in any namespace.
+                  properties:
+                    name:
+                      description: Name of the referent.
+                      type: string
+                    namespace:
+                      description: Namespace of the referent, when not specified it
+                        acts as LocalObjectReference.
+                      type: string
+                  required:
+                  - name
+                  type: object
+                type: array
+              force:
+                default: false
+                description: Force instructs the controller to recreate resources
+                  when patching fails due to an immutable field change.
+                type: boolean
+              healthChecks:
+                description: A list of resources to be included in the health assessment.
+                items:
+                  description: NamespacedObjectKindReference contains enough information
+                    to locate the typed referenced Kubernetes resource object in any
+                    namespace.
+                  properties:
+                    apiVersion:
+                      description: API version of the referent, if not specified the
+                        Kubernetes preferred version will be used.
+                      type: string
+                    kind:
+                      description: Kind of the referent.
+                      type: string
+                    name:
+                      description: Name of the referent.
+                      type: string
+                    namespace:
+                      description: Namespace of the referent, when not specified it
+                        acts as LocalObjectReference.
+                      type: string
+                  required:
+                  - kind
+                  - name
+                  type: object
+                type: array
+              images:
+                description: Images is a list of (image name, new name, new tag or
+                  digest) for changing image names, tags or digests. This can also
+                  be achieved with a patch, but this operator is simpler to specify.
+                items:
+                  description: Image contains an image name, a new name, a new tag
+                    or digest, which will replace the original name and tag.
+                  properties:
+                    digest:
+                      description: Digest is the value used to replace the original
+                        image tag. If digest is present NewTag value is ignored.
+                      type: string
+                    name:
+                      description: Name is a tag-less image name.
+                      type: string
+                    newName:
+                      description: NewName is the value used to replace the original
+                        name.
+                      type: string
+                    newTag:
+                      description: NewTag is the value used to replace the original
+                        tag.
+                      type: string
+                  required:
+                  - name
+                  type: object
+                type: array
+              interval:
+                description: The interval at which to reconcile the Kustomization.
+                pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
+                type: string
+              kubeConfig:
+                description: The KubeConfig for reconciling the Kustomization on a
+                  remote cluster. When used in combination with KustomizationSpec.ServiceAccountName,
+                  forces the controller to act on behalf of that Service Account at
+                  the target cluster. If the --default-service-account flag is set,
+                  its value will be used as a controller level fallback for when KustomizationSpec.ServiceAccountName
+                  is empty.
+                properties:
+                  secretRef:
+                    description: SecretRef holds the name of a secret that contains
+                      a key with the kubeconfig file as the value. If no key is set,
+                      the key will default to 'value'. It is recommended that the
+                      kubeconfig is self-contained, and the secret is regularly updated
+                      if credentials such as a cloud-access-token expire. Cloud specific
+                      `cmd-path` auth helpers will not function without adding binaries
+                      and credentials to the Pod that is responsible for reconciling
+                      Kubernetes resources.
+                    properties:
+                      key:
+                        description: Key in the Secret, when not specified an implementation-specific
+                          default key is used.
+                        type: string
+                      name:
+                        description: Name of the Secret.
+                        type: string
+                    required:
+                    - name
+                    type: object
+                required:
+                - secretRef
+                type: object
+              patches:
+                description: Strategic merge and JSON patches, defined as inline YAML
+                  objects, capable of targeting objects based on kind, label and annotation
+                  selectors.
+                items:
+                  description: Patch contains an inline StrategicMerge or JSON6902
+                    patch, and the target the patch should be applied to.
+                  properties:
+                    patch:
+                      description: Patch contains an inline StrategicMerge patch or
+                        an inline JSON6902 patch with an array of operation objects.
+                      type: string
+                    target:
+                      description: Target points to the resources that the patch document
+                        should be applied to.
+                      properties:
+                        annotationSelector:
+                          description: AnnotationSelector is a string that follows
+                            the label selection expression https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api
+                            It matches with the resource annotations.
+                          type: string
+                        group:
+                          description: Group is the API group to select resources
+                            from. Together with Version and Kind it is capable of
+                            unambiguously identifying and/or selecting resources.
+                            https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md
+                          type: string
+                        kind:
+                          description: Kind of the API Group to select resources from.
+                            Together with Group and Version it is capable of unambiguously
+                            identifying and/or selecting resources. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md
+                          type: string
+                        labelSelector:
+                          description: LabelSelector is a string that follows the
+                            label selection expression https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api
+                            It matches with the resource labels.
+                          type: string
+                        name:
+                          description: Name to match resources with.
+                          type: string
+                        namespace:
+                          description: Namespace to select resources from.
+                          type: string
+                        version:
+                          description: Version of the API Group to select resources
+                            from. Together with Group and Kind it is capable of unambiguously
+                            identifying and/or selecting resources. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md
+                          type: string
+                      type: object
+                  required:
+                  - patch
+                  type: object
+                type: array
+              patchesJson6902:
+                description: 'JSON 6902 patches, defined as inline YAML objects. Deprecated:
+                  Use Patches instead.'
+                items:
+                  description: JSON6902Patch contains a JSON6902 patch and the target
+                    the patch should be applied to.
+                  properties:
+                    patch:
+                      description: Patch contains the JSON6902 patch document with
+                        an array of operation objects.
+                      items:
+                        description: JSON6902 is a JSON6902 operation object. https://datatracker.ietf.org/doc/html/rfc6902#section-4
+                        properties:
+                          from:
+                            description: From contains a JSON-pointer value that references
+                              a location within the target document where the operation
+                              is performed. The meaning of the value depends on the
+                              value of Op, and is NOT taken into account by all operations.
+                            type: string
+                          op:
+                            description: Op indicates the operation to perform. Its
+                              value MUST be one of "add", "remove", "replace", "move",
+                              "copy", or "test". https://datatracker.ietf.org/doc/html/rfc6902#section-4
+                            enum:
+                            - test
+                            - remove
+                            - add
+                            - replace
+                            - move
+                            - copy
+                            type: string
+                          path:
+                            description: Path contains the JSON-pointer value that
+                              references a location within the target document where
+                              the operation is performed. The meaning of the value
+                              depends on the value of Op.
+                            type: string
+                          value:
+                            description: Value contains a valid JSON structure. The
+                              meaning of the value depends on the value of Op, and
+                              is NOT taken into account by all operations.
+                            x-kubernetes-preserve-unknown-fields: true
+                        required:
+                        - op
+                        - path
+                        type: object
+                      type: array
+                    target:
+                      description: Target points to the resources that the patch document
+                        should be applied to.
+                      properties:
+                        annotationSelector:
+                          description: AnnotationSelector is a string that follows
+                            the label selection expression https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api
+                            It matches with the resource annotations.
+                          type: string
+                        group:
+                          description: Group is the API group to select resources
+                            from. Together with Version and Kind it is capable of
+                            unambiguously identifying and/or selecting resources.
+                            https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md
+                          type: string
+                        kind:
+                          description: Kind of the API Group to select resources from.
+                            Together with Group and Version it is capable of unambiguously
+                            identifying and/or selecting resources. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md
+                          type: string
+                        labelSelector:
+                          description: LabelSelector is a string that follows the
+                            label selection expression https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api
+                            It matches with the resource labels.
+                          type: string
+                        name:
+                          description: Name to match resources with.
+                          type: string
+                        namespace:
+                          description: Namespace to select resources from.
+                          type: string
+                        version:
+                          description: Version of the API Group to select resources
+                            from. Together with Group and Kind it is capable of unambiguously
+                            identifying and/or selecting resources. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md
+                          type: string
+                      type: object
+                  required:
+                  - patch
+                  - target
+                  type: object
+                type: array
+              patchesStrategicMerge:
+                description: 'Strategic merge patches, defined as inline YAML objects.
+                  Deprecated: Use Patches instead.'
+                items:
+                  x-kubernetes-preserve-unknown-fields: true
+                type: array
+              path:
+                description: Path to the directory containing the kustomization.yaml
+                  file, or the set of plain YAMLs a kustomization.yaml should be generated
+                  for. Defaults to 'None', which translates to the root path of the
+                  SourceRef.
+                type: string
+              postBuild:
+                description: PostBuild describes which actions to perform on the YAML
+                  manifest generated by building the kustomize overlay.
+                properties:
+                  substitute:
+                    additionalProperties:
+                      type: string
+                    description: Substitute holds a map of key/value pairs. The variables
+                      defined in your YAML manifests that match any of the keys defined
+                      in the map will be substituted with the set value. Includes
+                      support for bash string replacement functions e.g. ${var:=default},
+                      ${var:position} and ${var/substring/replacement}.
+                    type: object
+                  substituteFrom:
+                    description: SubstituteFrom holds references to ConfigMaps and
+                      Secrets containing the variables and their values to be substituted
+                      in the YAML manifests. The ConfigMap and the Secret data keys
+                      represent the var names and they must match the vars declared
+                      in the manifests for the substitution to happen.
+                    items:
+                      description: SubstituteReference contains a reference to a resource
+                        containing the variables name and value.
+                      properties:
+                        kind:
+                          description: Kind of the values referent, valid values are
+                            ('Secret', 'ConfigMap').
+                          enum:
+                          - Secret
+                          - ConfigMap
+                          type: string
+                        name:
+                          description: Name of the values referent. Should reside
+                            in the same namespace as the referring resource.
+                          maxLength: 253
+                          minLength: 1
+                          type: string
+                        optional:
+                          default: false
+                          description: Optional indicates whether the referenced resource
+                            must exist, or whether to tolerate its absence. If true
+                            and the referenced resource is absent, proceed as if the
+                            resource was present but empty, without any variables
+                            defined.
+                          type: boolean
+                      required:
+                      - kind
+                      - name
+                      type: object
+                    type: array
+                type: object
+              prune:
+                description: Prune enables garbage collection.
+                type: boolean
+              retryInterval:
+                description: The interval at which to retry a previously failed reconciliation.
+                  When not specified, the controller uses the KustomizationSpec.Interval
+                  value to retry failures.
+                pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
+                type: string
+              serviceAccountName:
+                description: The name of the Kubernetes service account to impersonate
+                  when reconciling this Kustomization.
+                type: string
+              sourceRef:
+                description: Reference of the source where the kustomization file
+                  is.
+                properties:
+                  apiVersion:
+                    description: API version of the referent.
+                    type: string
+                  kind:
+                    description: Kind of the referent.
+                    enum:
+                    - OCIRepository
+                    - GitRepository
+                    - Bucket
+                    type: string
+                  name:
+                    description: Name of the referent.
+                    type: string
+                  namespace:
+                    description: Namespace of the referent, defaults to the namespace
+                      of the Kubernetes resource object that contains the reference.
+                    type: string
+                required:
+                - kind
+                - name
+                type: object
+              suspend:
+                description: This flag tells the controller to suspend subsequent
+                  kustomize executions, it does not apply to already started executions.
+                  Defaults to false.
+                type: boolean
+              targetNamespace:
+                description: TargetNamespace sets or overrides the namespace in the
+                  kustomization.yaml file.
+                maxLength: 63
+                minLength: 1
+                type: string
+              timeout:
+                description: Timeout for validation, apply and health checking operations.
+                  Defaults to 'Interval' duration.
+                pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
+                type: string
+              validation:
+                description: 'Deprecated: Not used in v1beta2.'
+                enum:
+                - none
+                - client
+                - server
+                type: string
+              wait:
+                description: Wait instructs the controller to check the health of
+                  all the reconciled resources. When enabled, the HealthChecks are
+                  ignored. Defaults to false.
+                type: boolean
+            required:
+            - interval
+            - prune
+            - sourceRef
+            type: object
+          status:
+            default:
+              observedGeneration: -1
+            description: KustomizationStatus defines the observed state of a kustomization.
+            properties:
+              conditions:
+                items:
+                  description: "Condition contains details for one aspect of the current
+                    state of this API Resource. --- This struct is intended for direct
+                    use as an array at the field path .status.conditions.  For example,
+                    \n type FooStatus struct{ // Represents the observations of a
+                    foo's current state. // Known .status.conditions.type are: \"Available\",
+                    \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
+                    // +listType=map // +listMapKey=type Conditions []metav1.Condition
+                    `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
+                    protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
+                  properties:
+                    lastTransitionTime:
+                      description: lastTransitionTime is the last time the condition
+                        transitioned from one status to another. This should be when
+                        the underlying condition changed.  If that is not known, then
+                        using the time when the API field changed is acceptable.
+                      format: date-time
+                      type: string
+                    message:
+                      description: message is a human readable message indicating
+                        details about the transition. This may be an empty string.
+                      maxLength: 32768
+                      type: string
+                    observedGeneration:
+                      description: observedGeneration represents the .metadata.generation
+                        that the condition was set based upon. For instance, if .metadata.generation
+                        is currently 12, but the .status.conditions[x].observedGeneration
+                        is 9, the condition is out of date with respect to the current
+                        state of the instance.
+                      format: int64
+                      minimum: 0
+                      type: integer
+                    reason:
+                      description: reason contains a programmatic identifier indicating
+                        the reason for the condition's last transition. Producers
+                        of specific condition types may define expected values and
+                        meanings for this field, and whether the values are considered
+                        a guaranteed API. The value should be a CamelCase string.
+                        This field may not be empty.
+                      maxLength: 1024
+                      minLength: 1
+                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+                      type: string
+                    status:
+                      description: status of the condition, one of True, False, Unknown.
+                      enum:
+                      - "True"
+                      - "False"
+                      - Unknown
+                      type: string
+                    type:
+                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
+                        --- Many .condition.type values are consistent across resources
+                        like Available, but because arbitrary conditions can be useful
+                        (see .node.status.conditions), the ability to deconflict is
+                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
+                      maxLength: 316
+                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - message
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+              inventory:
+                description: Inventory contains the list of Kubernetes resource object
+                  references that have been successfully applied.
+                properties:
+                  entries:
+                    description: Entries of Kubernetes resource object references.
+                    items:
+                      description: ResourceRef contains the information necessary
+                        to locate a resource within a cluster.
+                      properties:
+                        id:
+                          description: ID is the string representation of the Kubernetes
+                            resource object's metadata, in the format '<namespace>_<name>_<group>_<kind>'.
+                          type: string
+                        v:
+                          description: Version is the API version of the Kubernetes
+                            resource object's kind.
+                          type: string
+                      required:
+                      - id
+                      - v
+                      type: object
+                    type: array
+                required:
+                - entries
+                type: object
+              lastAppliedRevision:
+                description: The last successfully applied revision. Equals the Revision
+                  of the applied Artifact from the referenced Source.
+                type: string
+              lastAttemptedRevision:
+                description: LastAttemptedRevision is the revision of the last reconciliation
+                  attempt.
+                type: string
+              lastHandledReconcileAt:
+                description: LastHandledReconcileAt holds the value of the most recent
+                  reconcile request value, so a change of the annotation value can
+                  be detected.
+                type: string
+              observedGeneration:
+                description: ObservedGeneration is the last reconciled generation.
+                format: int64
+                type: integer
+            type: object
+        type: object
+    served: true
+    storage: false
+    subresources:
+      status: {}
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  labels:
+    app.kubernetes.io/component: kustomize-controller
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+  name: kustomize-controller
+  namespace: flux-system
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  labels:
+    app.kubernetes.io/component: kustomize-controller
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+    control-plane: controller
+  name: kustomize-controller
+  namespace: flux-system
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: kustomize-controller
+  template:
+    metadata:
+      annotations:
+        prometheus.io/port: "8080"
+        prometheus.io/scrape: "true"
+      labels:
+        app: kustomize-controller
+    spec:
+      containers:
+      - args:
+        - --events-addr=http://notification-controller.flux-system.svc.cluster.local./
+        - --watch-all-namespaces=true
+        - --log-level=info
+        - --log-encoding=json
+        - --enable-leader-election
+        env:
+        - name: RUNTIME_NAMESPACE
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.namespace
+        image: ghcr.io/fluxcd/kustomize-controller:v1.1.1
+        imagePullPolicy: IfNotPresent
+        livenessProbe:
+          httpGet:
+            path: /healthz
+            port: healthz
+        name: manager
+        ports:
+        - containerPort: 8080
+          name: http-prom
+          protocol: TCP
+        - containerPort: 9440
+          name: healthz
+          protocol: TCP
+        readinessProbe:
+          httpGet:
+            path: /readyz
+            port: healthz
+        resources:
+          limits:
+            cpu: 1000m
+            memory: 1Gi
+          requests:
+            cpu: 100m
+            memory: 64Mi
+        securityContext:
+          allowPrivilegeEscalation: false
+          capabilities:
+            drop:
+            - ALL
+          readOnlyRootFilesystem: true
+          runAsNonRoot: true
+          seccompProfile:
+            type: RuntimeDefault
+        volumeMounts:
+        - mountPath: /tmp
+          name: temp
+      nodeSelector:
+        kubernetes.io/os: linux
+      priorityClassName: system-cluster-critical
+      securityContext:
+        fsGroup: 1337
+      serviceAccountName: kustomize-controller
+      terminationGracePeriodSeconds: 60
+      volumes:
+      - emptyDir: {}
+        name: temp
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.12.0
+  labels:
+    app.kubernetes.io/component: helm-controller
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+  name: helmreleases.helm.toolkit.fluxcd.io
+spec:
+  group: helm.toolkit.fluxcd.io
+  names:
+    kind: HelmRelease
+    listKind: HelmReleaseList
+    plural: helmreleases
+    shortNames:
+    - hr
+    singular: helmrelease
+  scope: Namespaced
+  versions:
+  - additionalPrinterColumns:
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    - jsonPath: .status.conditions[?(@.type=="Ready")].status
+      name: Ready
+      type: string
+    - jsonPath: .status.conditions[?(@.type=="Ready")].message
+      name: Status
+      type: string
+    name: v2beta1
+    schema:
+      openAPIV3Schema:
+        description: HelmRelease is the Schema for the helmreleases API
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: HelmReleaseSpec defines the desired state of a Helm release.
+            properties:
+              chart:
+                description: Chart defines the template of the v1beta2.HelmChart that
+                  should be created for this HelmRelease.
+                properties:
+                  metadata:
+                    description: ObjectMeta holds the template for metadata like labels
+                      and annotations.
+                    properties:
+                      annotations:
+                        additionalProperties:
+                          type: string
+                        description: 'Annotations is an unstructured key value map
+                          stored with a resource that may be set by external tools
+                          to store and retrieve arbitrary metadata. They are not queryable
+                          and should be preserved when modifying objects. More info:
+                          https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/'
+                        type: object
+                      labels:
+                        additionalProperties:
+                          type: string
+                        description: 'Map of string keys and values that can be used
+                          to organize and categorize (scope and select) objects. More
+                          info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/'
+                        type: object
+                    type: object
+                  spec:
+                    description: Spec holds the template for the v1beta2.HelmChartSpec
+                      for this HelmRelease.
+                    properties:
+                      chart:
+                        description: The name or path the Helm chart is available
+                          at in the SourceRef.
+                        type: string
+                      interval:
+                        description: Interval at which to check the v1beta2.Source
+                          for updates. Defaults to 'HelmReleaseSpec.Interval'.
+                        pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
+                        type: string
+                      reconcileStrategy:
+                        default: ChartVersion
+                        description: Determines what enables the creation of a new
+                          artifact. Valid values are ('ChartVersion', 'Revision').
+                          See the documentation of the values for an explanation on
+                          their behavior. Defaults to ChartVersion when omitted.
+                        enum:
+                        - ChartVersion
+                        - Revision
+                        type: string
+                      sourceRef:
+                        description: The name and namespace of the v1beta2.Source
+                          the chart is available at.
+                        properties:
+                          apiVersion:
+                            description: APIVersion of the referent.
+                            type: string
+                          kind:
+                            description: Kind of the referent.
+                            enum:
+                            - HelmRepository
+                            - GitRepository
+                            - Bucket
+                            type: string
+                          name:
+                            description: Name of the referent.
+                            maxLength: 253
+                            minLength: 1
+                            type: string
+                          namespace:
+                            description: Namespace of the referent.
+                            maxLength: 63
+                            minLength: 1
+                            type: string
+                        required:
+                        - name
+                        type: object
+                      valuesFile:
+                        description: Alternative values file to use as the default
+                          chart values, expected to be a relative path in the SourceRef.
+                          Deprecated in favor of ValuesFiles, for backwards compatibility
+                          the file defined here is merged before the ValuesFiles items.
+                          Ignored when omitted.
+                        type: string
+                      valuesFiles:
+                        description: Alternative list of values files to use as the
+                          chart values (values.yaml is not included by default), expected
+                          to be a relative path in the SourceRef. Values files are
+                          merged in the order of this list with the last file overriding
+                          the first. Ignored when omitted.
+                        items:
+                          type: string
+                        type: array
+                      verify:
+                        description: Verify contains the secret name containing the
+                          trusted public keys used to verify the signature and specifies
+                          which provider to use to check whether OCI image is authentic.
+                          This field is only supported for OCI sources. Chart dependencies,
+                          which are not bundled in the umbrella chart artifact, are
+                          not verified.
+                        properties:
+                          provider:
+                            default: cosign
+                            description: Provider specifies the technology used to
+                              sign the OCI Helm chart.
+                            enum:
+                            - cosign
+                            type: string
+                          secretRef:
+                            description: SecretRef specifies the Kubernetes Secret
+                              containing the trusted public keys.
+                            properties:
+                              name:
+                                description: Name of the referent.
+                                type: string
+                            required:
+                            - name
+                            type: object
+                        required:
+                        - provider
+                        type: object
+                      version:
+                        default: '*'
+                        description: Version semver expression, ignored for charts
+                          from v1beta2.GitRepository and v1beta2.Bucket sources. Defaults
+                          to latest when omitted.
+                        type: string
+                    required:
+                    - chart
+                    - sourceRef
+                    type: object
+                required:
+                - spec
+                type: object
+              dependsOn:
+                description: DependsOn may contain a meta.NamespacedObjectReference
+                  slice with references to HelmRelease resources that must be ready
+                  before this HelmRelease can be reconciled.
+                items:
+                  description: NamespacedObjectReference contains enough information
+                    to locate the referenced Kubernetes resource object in any namespace.
+                  properties:
+                    name:
+                      description: Name of the referent.
+                      type: string
+                    namespace:
+                      description: Namespace of the referent, when not specified it
+                        acts as LocalObjectReference.
+                      type: string
+                  required:
+                  - name
+                  type: object
+                type: array
+              install:
+                description: Install holds the configuration for Helm install actions
+                  for this HelmRelease.
+                properties:
+                  crds:
+                    description: "CRDs upgrade CRDs from the Helm Chart's crds directory
+                      according to the CRD upgrade policy provided here. Valid values
+                      are `Skip`, `Create` or `CreateReplace`. Default is `Create`
+                      and if omitted CRDs are installed but not updated. \n Skip:
+                      do neither install nor replace (update) any CRDs. \n Create:
+                      new CRDs are created, existing CRDs are neither updated nor
+                      deleted. \n CreateReplace: new CRDs are created, existing CRDs
+                      are updated (replaced) but not deleted. \n By default, CRDs
+                      are applied (installed) during Helm install action. With this
+                      option users can opt-in to CRD replace existing CRDs on Helm
+                      install actions, which is not (yet) natively supported by Helm.
+                      https://helm.sh/docs/chart_best_practices/custom_resource_definitions."
+                    enum:
+                    - Skip
+                    - Create
+                    - CreateReplace
+                    type: string
+                  createNamespace:
+                    description: CreateNamespace tells the Helm install action to
+                      create the HelmReleaseSpec.TargetNamespace if it does not exist
+                      yet. On uninstall, the namespace will not be garbage collected.
+                    type: boolean
+                  disableHooks:
+                    description: DisableHooks prevents hooks from running during the
+                      Helm install action.
+                    type: boolean
+                  disableOpenAPIValidation:
+                    description: DisableOpenAPIValidation prevents the Helm install
+                      action from validating rendered templates against the Kubernetes
+                      OpenAPI Schema.
+                    type: boolean
+                  disableWait:
+                    description: DisableWait disables the waiting for resources to
+                      be ready after a Helm install has been performed.
+                    type: boolean
+                  disableWaitForJobs:
+                    description: DisableWaitForJobs disables waiting for jobs to complete
+                      after a Helm install has been performed.
+                    type: boolean
+                  remediation:
+                    description: Remediation holds the remediation configuration for
+                      when the Helm install action for the HelmRelease fails. The
+                      default is to not perform any action.
+                    properties:
+                      ignoreTestFailures:
+                        description: IgnoreTestFailures tells the controller to skip
+                          remediation when the Helm tests are run after an install
+                          action but fail. Defaults to 'Test.IgnoreFailures'.
+                        type: boolean
+                      remediateLastFailure:
+                        description: RemediateLastFailure tells the controller to
+                          remediate the last failure, when no retries remain. Defaults
+                          to 'false'.
+                        type: boolean
+                      retries:
+                        description: Retries is the number of retries that should
+                          be attempted on failures before bailing. Remediation, using
+                          an uninstall, is performed between each attempt. Defaults
+                          to '0', a negative integer equals to unlimited retries.
+                        type: integer
+                    type: object
+                  replace:
+                    description: Replace tells the Helm install action to re-use the
+                      'ReleaseName', but only if that name is a deleted release which
+                      remains in the history.
+                    type: boolean
+                  skipCRDs:
+                    description: "SkipCRDs tells the Helm install action to not install
+                      any CRDs. By default, CRDs are installed if not already present.
+                      \n Deprecated use CRD policy (`crds`) attribute with value `Skip`
+                      instead."
+                    type: boolean
+                  timeout:
+                    description: Timeout is the time to wait for any individual Kubernetes
+                      operation (like Jobs for hooks) during the performance of a
+                      Helm install action. Defaults to 'HelmReleaseSpec.Timeout'.
+                    pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
+                    type: string
+                type: object
+              interval:
+                description: Interval at which to reconcile the Helm release. This
+                  interval is approximate and may be subject to jitter to ensure efficient
+                  use of resources.
+                pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
+                type: string
+              kubeConfig:
+                description: KubeConfig for reconciling the HelmRelease on a remote
+                  cluster. When used in combination with HelmReleaseSpec.ServiceAccountName,
+                  forces the controller to act on behalf of that Service Account at
+                  the target cluster. If the --default-service-account flag is set,
+                  its value will be used as a controller level fallback for when HelmReleaseSpec.ServiceAccountName
+                  is empty.
+                properties:
+                  secretRef:
+                    description: SecretRef holds the name of a secret that contains
+                      a key with the kubeconfig file as the value. If no key is set,
+                      the key will default to 'value'. It is recommended that the
+                      kubeconfig is self-contained, and the secret is regularly updated
+                      if credentials such as a cloud-access-token expire. Cloud specific
+                      `cmd-path` auth helpers will not function without adding binaries
+                      and credentials to the Pod that is responsible for reconciling
+                      Kubernetes resources.
+                    properties:
+                      key:
+                        description: Key in the Secret, when not specified an implementation-specific
+                          default key is used.
+                        type: string
+                      name:
+                        description: Name of the Secret.
+                        type: string
+                    required:
+                    - name
+                    type: object
+                required:
+                - secretRef
+                type: object
+              maxHistory:
+                description: MaxHistory is the number of revisions saved by Helm for
+                  this HelmRelease. Use '0' for an unlimited number of revisions;
+                  defaults to '10'.
+                type: integer
+              persistentClient:
+                description: "PersistentClient tells the controller to use a persistent
+                  Kubernetes client for this release. When enabled, the client will
+                  be reused for the duration of the reconciliation, instead of being
+                  created and destroyed for each (step of a) Helm action. \n This
+                  can improve performance, but may cause issues with some Helm charts
+                  that for example do create Custom Resource Definitions during installation
+                  outside Helm's CRD lifecycle hooks, which are then not observed
+                  to be available by e.g. post-install hooks. \n If not set, it defaults
+                  to true."
+                type: boolean
+              postRenderers:
+                description: PostRenderers holds an array of Helm PostRenderers, which
+                  will be applied in order of their definition.
+                items:
+                  description: PostRenderer contains a Helm PostRenderer specification.
+                  properties:
+                    kustomize:
+                      description: Kustomization to apply as PostRenderer.
+                      properties:
+                        images:
+                          description: Images is a list of (image name, new name,
+                            new tag or digest) for changing image names, tags or digests.
+                            This can also be achieved with a patch, but this operator
+                            is simpler to specify.
+                          items:
+                            description: Image contains an image name, a new name,
+                              a new tag or digest, which will replace the original
+                              name and tag.
+                            properties:
+                              digest:
+                                description: Digest is the value used to replace the
+                                  original image tag. If digest is present NewTag
+                                  value is ignored.
+                                type: string
+                              name:
+                                description: Name is a tag-less image name.
+                                type: string
+                              newName:
+                                description: NewName is the value used to replace
+                                  the original name.
+                                type: string
+                              newTag:
+                                description: NewTag is the value used to replace the
+                                  original tag.
+                                type: string
+                            required:
+                            - name
+                            type: object
+                          type: array
+                        patches:
+                          description: Strategic merge and JSON patches, defined as
+                            inline YAML objects, capable of targeting objects based
+                            on kind, label and annotation selectors.
+                          items:
+                            description: Patch contains an inline StrategicMerge or
+                              JSON6902 patch, and the target the patch should be applied
+                              to.
+                            properties:
+                              patch:
+                                description: Patch contains an inline StrategicMerge
+                                  patch or an inline JSON6902 patch with an array
+                                  of operation objects.
+                                type: string
+                              target:
+                                description: Target points to the resources that the
+                                  patch document should be applied to.
+                                properties:
+                                  annotationSelector:
+                                    description: AnnotationSelector is a string that
+                                      follows the label selection expression https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api
+                                      It matches with the resource annotations.
+                                    type: string
+                                  group:
+                                    description: Group is the API group to select
+                                      resources from. Together with Version and Kind
+                                      it is capable of unambiguously identifying and/or
+                                      selecting resources. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md
+                                    type: string
+                                  kind:
+                                    description: Kind of the API Group to select resources
+                                      from. Together with Group and Version it is
+                                      capable of unambiguously identifying and/or
+                                      selecting resources. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md
+                                    type: string
+                                  labelSelector:
+                                    description: LabelSelector is a string that follows
+                                      the label selection expression https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api
+                                      It matches with the resource labels.
+                                    type: string
+                                  name:
+                                    description: Name to match resources with.
+                                    type: string
+                                  namespace:
+                                    description: Namespace to select resources from.
+                                    type: string
+                                  version:
+                                    description: Version of the API Group to select
+                                      resources from. Together with Group and Kind
+                                      it is capable of unambiguously identifying and/or
+                                      selecting resources. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md
+                                    type: string
+                                type: object
+                            required:
+                            - patch
+                            type: object
+                          type: array
+                        patchesJson6902:
+                          description: JSON 6902 patches, defined as inline YAML objects.
+                          items:
+                            description: JSON6902Patch contains a JSON6902 patch and
+                              the target the patch should be applied to.
+                            properties:
+                              patch:
+                                description: Patch contains the JSON6902 patch document
+                                  with an array of operation objects.
+                                items:
+                                  description: JSON6902 is a JSON6902 operation object.
+                                    https://datatracker.ietf.org/doc/html/rfc6902#section-4
+                                  properties:
+                                    from:
+                                      description: From contains a JSON-pointer value
+                                        that references a location within the target
+                                        document where the operation is performed.
+                                        The meaning of the value depends on the value
+                                        of Op, and is NOT taken into account by all
+                                        operations.
+                                      type: string
+                                    op:
+                                      description: Op indicates the operation to perform.
+                                        Its value MUST be one of "add", "remove",
+                                        "replace", "move", "copy", or "test". https://datatracker.ietf.org/doc/html/rfc6902#section-4
+                                      enum:
+                                      - test
+                                      - remove
+                                      - add
+                                      - replace
+                                      - move
+                                      - copy
+                                      type: string
+                                    path:
+                                      description: Path contains the JSON-pointer
+                                        value that references a location within the
+                                        target document where the operation is performed.
+                                        The meaning of the value depends on the value
+                                        of Op.
+                                      type: string
+                                    value:
+                                      description: Value contains a valid JSON structure.
+                                        The meaning of the value depends on the value
+                                        of Op, and is NOT taken into account by all
+                                        operations.
+                                      x-kubernetes-preserve-unknown-fields: true
+                                  required:
+                                  - op
+                                  - path
+                                  type: object
+                                type: array
+                              target:
+                                description: Target points to the resources that the
+                                  patch document should be applied to.
+                                properties:
+                                  annotationSelector:
+                                    description: AnnotationSelector is a string that
+                                      follows the label selection expression https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api
+                                      It matches with the resource annotations.
+                                    type: string
+                                  group:
+                                    description: Group is the API group to select
+                                      resources from. Together with Version and Kind
+                                      it is capable of unambiguously identifying and/or
+                                      selecting resources. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md
+                                    type: string
+                                  kind:
+                                    description: Kind of the API Group to select resources
+                                      from. Together with Group and Version it is
+                                      capable of unambiguously identifying and/or
+                                      selecting resources. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md
+                                    type: string
+                                  labelSelector:
+                                    description: LabelSelector is a string that follows
+                                      the label selection expression https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api
+                                      It matches with the resource labels.
+                                    type: string
+                                  name:
+                                    description: Name to match resources with.
+                                    type: string
+                                  namespace:
+                                    description: Namespace to select resources from.
+                                    type: string
+                                  version:
+                                    description: Version of the API Group to select
+                                      resources from. Together with Group and Kind
+                                      it is capable of unambiguously identifying and/or
+                                      selecting resources. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md
+                                    type: string
+                                type: object
+                            required:
+                            - patch
+                            - target
+                            type: object
+                          type: array
+                        patchesStrategicMerge:
+                          description: Strategic merge patches, defined as inline
+                            YAML objects.
+                          items:
+                            x-kubernetes-preserve-unknown-fields: true
+                          type: array
+                      type: object
+                  type: object
+                type: array
+              releaseName:
+                description: ReleaseName used for the Helm release. Defaults to a
+                  composition of '[TargetNamespace-]Name'.
+                maxLength: 53
+                minLength: 1
+                type: string
+              rollback:
+                description: Rollback holds the configuration for Helm rollback actions
+                  for this HelmRelease.
+                properties:
+                  cleanupOnFail:
+                    description: CleanupOnFail allows deletion of new resources created
+                      during the Helm rollback action when it fails.
+                    type: boolean
+                  disableHooks:
+                    description: DisableHooks prevents hooks from running during the
+                      Helm rollback action.
+                    type: boolean
+                  disableWait:
+                    description: DisableWait disables the waiting for resources to
+                      be ready after a Helm rollback has been performed.
+                    type: boolean
+                  disableWaitForJobs:
+                    description: DisableWaitForJobs disables waiting for jobs to complete
+                      after a Helm rollback has been performed.
+                    type: boolean
+                  force:
+                    description: Force forces resource updates through a replacement
+                      strategy.
+                    type: boolean
+                  recreate:
+                    description: Recreate performs pod restarts for the resource if
+                      applicable.
+                    type: boolean
+                  timeout:
+                    description: Timeout is the time to wait for any individual Kubernetes
+                      operation (like Jobs for hooks) during the performance of a
+                      Helm rollback action. Defaults to 'HelmReleaseSpec.Timeout'.
+                    pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
+                    type: string
+                type: object
+              serviceAccountName:
+                description: The name of the Kubernetes service account to impersonate
+                  when reconciling this HelmRelease.
+                type: string
+              storageNamespace:
+                description: StorageNamespace used for the Helm storage. Defaults
+                  to the namespace of the HelmRelease.
+                maxLength: 63
+                minLength: 1
+                type: string
+              suspend:
+                description: Suspend tells the controller to suspend reconciliation
+                  for this HelmRelease, it does not apply to already started reconciliations.
+                  Defaults to false.
+                type: boolean
+              targetNamespace:
+                description: TargetNamespace to target when performing operations
+                  for the HelmRelease. Defaults to the namespace of the HelmRelease.
+                maxLength: 63
+                minLength: 1
+                type: string
+              test:
+                description: Test holds the configuration for Helm test actions for
+                  this HelmRelease.
+                properties:
+                  enable:
+                    description: Enable enables Helm test actions for this HelmRelease
+                      after an Helm install or upgrade action has been performed.
+                    type: boolean
+                  ignoreFailures:
+                    description: IgnoreFailures tells the controller to skip remediation
+                      when the Helm tests are run but fail. Can be overwritten for
+                      tests run after install or upgrade actions in 'Install.IgnoreTestFailures'
+                      and 'Upgrade.IgnoreTestFailures'.
+                    type: boolean
+                  timeout:
+                    description: Timeout is the time to wait for any individual Kubernetes
+                      operation during the performance of a Helm test action. Defaults
+                      to 'HelmReleaseSpec.Timeout'.
+                    pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
+                    type: string
+                type: object
+              timeout:
+                description: Timeout is the time to wait for any individual Kubernetes
+                  operation (like Jobs for hooks) during the performance of a Helm
+                  action. Defaults to '5m0s'.
+                pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
+                type: string
+              uninstall:
+                description: Uninstall holds the configuration for Helm uninstall
+                  actions for this HelmRelease.
+                properties:
+                  deletionPropagation:
+                    default: background
+                    description: DeletionPropagation specifies the deletion propagation
+                      policy when a Helm uninstall is performed.
+                    enum:
+                    - background
+                    - foreground
+                    - orphan
+                    type: string
+                  disableHooks:
+                    description: DisableHooks prevents hooks from running during the
+                      Helm rollback action.
+                    type: boolean
+                  disableWait:
+                    description: DisableWait disables waiting for all the resources
+                      to be deleted after a Helm uninstall is performed.
+                    type: boolean
+                  keepHistory:
+                    description: KeepHistory tells Helm to remove all associated resources
+                      and mark the release as deleted, but retain the release history.
+                    type: boolean
+                  timeout:
+                    description: Timeout is the time to wait for any individual Kubernetes
+                      operation (like Jobs for hooks) during the performance of a
+                      Helm uninstall action. Defaults to 'HelmReleaseSpec.Timeout'.
+                    pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
+                    type: string
+                type: object
+              upgrade:
+                description: Upgrade holds the configuration for Helm upgrade actions
+                  for this HelmRelease.
+                properties:
+                  cleanupOnFail:
+                    description: CleanupOnFail allows deletion of new resources created
+                      during the Helm upgrade action when it fails.
+                    type: boolean
+                  crds:
+                    description: "CRDs upgrade CRDs from the Helm Chart's crds directory
+                      according to the CRD upgrade policy provided here. Valid values
+                      are `Skip`, `Create` or `CreateReplace`. Default is `Skip` and
+                      if omitted CRDs are neither installed nor upgraded. \n Skip:
+                      do neither install nor replace (update) any CRDs. \n Create:
+                      new CRDs are created, existing CRDs are neither updated nor
+                      deleted. \n CreateReplace: new CRDs are created, existing CRDs
+                      are updated (replaced) but not deleted. \n By default, CRDs
+                      are not applied during Helm upgrade action. With this option
+                      users can opt-in to CRD upgrade, which is not (yet) natively
+                      supported by Helm. https://helm.sh/docs/chart_best_practices/custom_resource_definitions."
+                    enum:
+                    - Skip
+                    - Create
+                    - CreateReplace
+                    type: string
+                  disableHooks:
+                    description: DisableHooks prevents hooks from running during the
+                      Helm upgrade action.
+                    type: boolean
+                  disableOpenAPIValidation:
+                    description: DisableOpenAPIValidation prevents the Helm upgrade
+                      action from validating rendered templates against the Kubernetes
+                      OpenAPI Schema.
+                    type: boolean
+                  disableWait:
+                    description: DisableWait disables the waiting for resources to
+                      be ready after a Helm upgrade has been performed.
+                    type: boolean
+                  disableWaitForJobs:
+                    description: DisableWaitForJobs disables waiting for jobs to complete
+                      after a Helm upgrade has been performed.
+                    type: boolean
+                  force:
+                    description: Force forces resource updates through a replacement
+                      strategy.
+                    type: boolean
+                  preserveValues:
+                    description: PreserveValues will make Helm reuse the last release's
+                      values and merge in overrides from 'Values'. Setting this flag
+                      makes the HelmRelease non-declarative.
+                    type: boolean
+                  remediation:
+                    description: Remediation holds the remediation configuration for
+                      when the Helm upgrade action for the HelmRelease fails. The
+                      default is to not perform any action.
+                    properties:
+                      ignoreTestFailures:
+                        description: IgnoreTestFailures tells the controller to skip
+                          remediation when the Helm tests are run after an upgrade
+                          action but fail. Defaults to 'Test.IgnoreFailures'.
+                        type: boolean
+                      remediateLastFailure:
+                        description: RemediateLastFailure tells the controller to
+                          remediate the last failure, when no retries remain. Defaults
+                          to 'false' unless 'Retries' is greater than 0.
+                        type: boolean
+                      retries:
+                        description: Retries is the number of retries that should
+                          be attempted on failures before bailing. Remediation, using
+                          'Strategy', is performed between each attempt. Defaults
+                          to '0', a negative integer equals to unlimited retries.
+                        type: integer
+                      strategy:
+                        description: Strategy to use for failure remediation. Defaults
+                          to 'rollback'.
+                        enum:
+                        - rollback
+                        - uninstall
+                        type: string
+                    type: object
+                  timeout:
+                    description: Timeout is the time to wait for any individual Kubernetes
+                      operation (like Jobs for hooks) during the performance of a
+                      Helm upgrade action. Defaults to 'HelmReleaseSpec.Timeout'.
+                    pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
+                    type: string
+                type: object
+              values:
+                description: Values holds the values for this Helm release.
+                x-kubernetes-preserve-unknown-fields: true
+              valuesFrom:
+                description: ValuesFrom holds references to resources containing Helm
+                  values for this HelmRelease, and information about how they should
+                  be merged.
+                items:
+                  description: ValuesReference contains a reference to a resource
+                    containing Helm values, and optionally the key they can be found
+                    at.
+                  properties:
+                    kind:
+                      description: Kind of the values referent, valid values are ('Secret',
+                        'ConfigMap').
+                      enum:
+                      - Secret
+                      - ConfigMap
+                      type: string
+                    name:
+                      description: Name of the values referent. Should reside in the
+                        same namespace as the referring resource.
+                      maxLength: 253
+                      minLength: 1
+                      type: string
+                    optional:
+                      description: Optional marks this ValuesReference as optional.
+                        When set, a not found error for the values reference is ignored,
+                        but any ValuesKey, TargetPath or transient error will still
+                        result in a reconciliation failure.
+                      type: boolean
+                    targetPath:
+                      description: TargetPath is the YAML dot notation path the value
+                        should be merged at. When set, the ValuesKey is expected to
+                        be a single flat value. Defaults to 'None', which results
+                        in the values getting merged at the root.
+                      maxLength: 250
+                      pattern: ^([a-zA-Z0-9_\-.\\\/]|\[[0-9]{1,5}\])+$
+                      type: string
+                    valuesKey:
+                      description: ValuesKey is the data key where the values.yaml
+                        or a specific value can be found at. Defaults to 'values.yaml'.
+                        When set, must be a valid Data Key, consisting of alphanumeric
+                        characters, '-', '_' or '.'.
+                      maxLength: 253
+                      pattern: ^[\-._a-zA-Z0-9]+$
+                      type: string
+                  required:
+                  - kind
+                  - name
+                  type: object
+                type: array
+            required:
+            - chart
+            - interval
+            type: object
+          status:
+            default:
+              observedGeneration: -1
+            description: HelmReleaseStatus defines the observed state of a HelmRelease.
+            properties:
+              conditions:
+                description: Conditions holds the conditions for the HelmRelease.
+                items:
+                  description: "Condition contains details for one aspect of the current
+                    state of this API Resource. --- This struct is intended for direct
+                    use as an array at the field path .status.conditions.  For example,
+                    \n type FooStatus struct{ // Represents the observations of a
+                    foo's current state. // Known .status.conditions.type are: \"Available\",
+                    \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
+                    // +listType=map // +listMapKey=type Conditions []metav1.Condition
+                    `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
+                    protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
+                  properties:
+                    lastTransitionTime:
+                      description: lastTransitionTime is the last time the condition
+                        transitioned from one status to another. This should be when
+                        the underlying condition changed.  If that is not known, then
+                        using the time when the API field changed is acceptable.
+                      format: date-time
+                      type: string
+                    message:
+                      description: message is a human readable message indicating
+                        details about the transition. This may be an empty string.
+                      maxLength: 32768
+                      type: string
+                    observedGeneration:
+                      description: observedGeneration represents the .metadata.generation
+                        that the condition was set based upon. For instance, if .metadata.generation
+                        is currently 12, but the .status.conditions[x].observedGeneration
+                        is 9, the condition is out of date with respect to the current
+                        state of the instance.
+                      format: int64
+                      minimum: 0
+                      type: integer
+                    reason:
+                      description: reason contains a programmatic identifier indicating
+                        the reason for the condition's last transition. Producers
+                        of specific condition types may define expected values and
+                        meanings for this field, and whether the values are considered
+                        a guaranteed API. The value should be a CamelCase string.
+                        This field may not be empty.
+                      maxLength: 1024
+                      minLength: 1
+                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+                      type: string
+                    status:
+                      description: status of the condition, one of True, False, Unknown.
+                      enum:
+                      - "True"
+                      - "False"
+                      - Unknown
+                      type: string
+                    type:
+                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
+                        --- Many .condition.type values are consistent across resources
+                        like Available, but because arbitrary conditions can be useful
+                        (see .node.status.conditions), the ability to deconflict is
+                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
+                      maxLength: 316
+                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - message
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+              failures:
+                description: Failures is the reconciliation failure count against
+                  the latest desired state. It is reset after a successful reconciliation.
+                format: int64
+                type: integer
+              helmChart:
+                description: HelmChart is the namespaced name of the HelmChart resource
+                  created by the controller for the HelmRelease.
+                type: string
+              installFailures:
+                description: InstallFailures is the install failure count against
+                  the latest desired state. It is reset after a successful reconciliation.
+                format: int64
+                type: integer
+              lastAppliedRevision:
+                description: LastAppliedRevision is the revision of the last successfully
+                  applied source.
+                type: string
+              lastAttemptedRevision:
+                description: LastAttemptedRevision is the revision of the last reconciliation
+                  attempt.
+                type: string
+              lastAttemptedValuesChecksum:
+                description: LastAttemptedValuesChecksum is the SHA1 checksum of the
+                  values of the last reconciliation attempt.
+                type: string
+              lastHandledReconcileAt:
+                description: LastHandledReconcileAt holds the value of the most recent
+                  reconcile request value, so a change of the annotation value can
+                  be detected.
+                type: string
+              lastReleaseRevision:
+                description: LastReleaseRevision is the revision of the last successful
+                  Helm release.
+                type: integer
+              observedGeneration:
+                description: ObservedGeneration is the last observed generation.
+                format: int64
+                type: integer
+              upgradeFailures:
+                description: UpgradeFailures is the upgrade failure count against
+                  the latest desired state. It is reset after a successful reconciliation.
+                format: int64
+                type: integer
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  labels:
+    app.kubernetes.io/component: helm-controller
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+  name: helm-controller
+  namespace: flux-system
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  labels:
+    app.kubernetes.io/component: helm-controller
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+    control-plane: controller
+  name: helm-controller
+  namespace: flux-system
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: helm-controller
+  template:
+    metadata:
+      annotations:
+        prometheus.io/port: "8080"
+        prometheus.io/scrape: "true"
+      labels:
+        app: helm-controller
+    spec:
+      containers:
+      - args:
+        - --events-addr=http://notification-controller.flux-system.svc.cluster.local./
+        - --watch-all-namespaces=true
+        - --log-level=info
+        - --log-encoding=json
+        - --enable-leader-election
+        env:
+        - name: RUNTIME_NAMESPACE
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.namespace
+        image: ghcr.io/fluxcd/helm-controller:v0.36.2
+        imagePullPolicy: IfNotPresent
+        livenessProbe:
+          httpGet:
+            path: /healthz
+            port: healthz
+        name: manager
+        ports:
+        - containerPort: 8080
+          name: http-prom
+          protocol: TCP
+        - containerPort: 9440
+          name: healthz
+          protocol: TCP
+        readinessProbe:
+          httpGet:
+            path: /readyz
+            port: healthz
+        resources:
+          limits:
+            cpu: 1000m
+            memory: 1Gi
+          requests:
+            cpu: 100m
+            memory: 64Mi
+        securityContext:
+          allowPrivilegeEscalation: false
+          capabilities:
+            drop:
+            - ALL
+          readOnlyRootFilesystem: true
+          runAsNonRoot: true
+          seccompProfile:
+            type: RuntimeDefault
+        volumeMounts:
+        - mountPath: /tmp
+          name: temp
+      nodeSelector:
+        kubernetes.io/os: linux
+      priorityClassName: system-cluster-critical
+      securityContext:
+        fsGroup: 1337
+      serviceAccountName: helm-controller
+      terminationGracePeriodSeconds: 600
+      volumes:
+      - emptyDir: {}
+        name: temp
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.12.0
+  labels:
+    app.kubernetes.io/component: notification-controller
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+  name: alerts.notification.toolkit.fluxcd.io
+spec:
+  group: notification.toolkit.fluxcd.io
+  names:
+    kind: Alert
+    listKind: AlertList
+    plural: alerts
+    singular: alert
+  scope: Namespaced
+  versions:
+  - additionalPrinterColumns:
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    - jsonPath: .status.conditions[?(@.type=="Ready")].status
+      name: Ready
+      type: string
+    - jsonPath: .status.conditions[?(@.type=="Ready")].message
+      name: Status
+      type: string
+    name: v1beta1
+    schema:
+      openAPIV3Schema:
+        description: Alert is the Schema for the alerts API
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: AlertSpec defines an alerting rule for events involving a
+              list of objects
+            properties:
+              eventSeverity:
+                default: info
+                description: Filter events based on severity, defaults to ('info').
+                  If set to 'info' no events will be filtered.
+                enum:
+                - info
+                - error
+                type: string
+              eventSources:
+                description: Filter events based on the involved objects.
+                items:
+                  description: CrossNamespaceObjectReference contains enough information
+                    to let you locate the typed referenced object at cluster level
+                  properties:
+                    apiVersion:
+                      description: API version of the referent
+                      type: string
+                    kind:
+                      description: Kind of the referent
+                      enum:
+                      - Bucket
+                      - GitRepository
+                      - Kustomization
+                      - HelmRelease
+                      - HelmChart
+                      - HelmRepository
+                      - ImageRepository
+                      - ImagePolicy
+                      - ImageUpdateAutomation
+                      - OCIRepository
+                      type: string
+                    matchLabels:
+                      additionalProperties:
+                        type: string
+                      description: MatchLabels is a map of {key,value} pairs. A single
+                        {key,value} in the matchLabels map is equivalent to an element
+                        of matchExpressions, whose key field is "key", the operator
+                        is "In", and the values array contains only "value". The requirements
+                        are ANDed.
+                      type: object
+                    name:
+                      description: Name of the referent
+                      maxLength: 53
+                      minLength: 1
+                      type: string
+                    namespace:
+                      description: Namespace of the referent
+                      maxLength: 53
+                      minLength: 1
+                      type: string
+                  required:
+                  - name
+                  type: object
+                type: array
+              exclusionList:
+                description: A list of Golang regular expressions to be used for excluding
+                  messages.
+                items:
+                  type: string
+                type: array
+              providerRef:
+                description: Send events using this provider.
+                properties:
+                  name:
+                    description: Name of the referent.
+                    type: string
+                required:
+                - name
+                type: object
+              summary:
+                description: Short description of the impact and affected cluster.
+                type: string
+              suspend:
+                description: This flag tells the controller to suspend subsequent
+                  events dispatching. Defaults to false.
+                type: boolean
+            required:
+            - eventSources
+            - providerRef
+            type: object
+          status:
+            default:
+              observedGeneration: -1
+            description: AlertStatus defines the observed state of Alert
+            properties:
+              conditions:
+                items:
+                  description: "Condition contains details for one aspect of the current
+                    state of this API Resource. --- This struct is intended for direct
+                    use as an array at the field path .status.conditions.  For example,
+                    \n type FooStatus struct{ // Represents the observations of a
+                    foo's current state. // Known .status.conditions.type are: \"Available\",
+                    \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
+                    // +listType=map // +listMapKey=type Conditions []metav1.Condition
+                    `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
+                    protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
+                  properties:
+                    lastTransitionTime:
+                      description: lastTransitionTime is the last time the condition
+                        transitioned from one status to another. This should be when
+                        the underlying condition changed.  If that is not known, then
+                        using the time when the API field changed is acceptable.
+                      format: date-time
+                      type: string
+                    message:
+                      description: message is a human readable message indicating
+                        details about the transition. This may be an empty string.
+                      maxLength: 32768
+                      type: string
+                    observedGeneration:
+                      description: observedGeneration represents the .metadata.generation
+                        that the condition was set based upon. For instance, if .metadata.generation
+                        is currently 12, but the .status.conditions[x].observedGeneration
+                        is 9, the condition is out of date with respect to the current
+                        state of the instance.
+                      format: int64
+                      minimum: 0
+                      type: integer
+                    reason:
+                      description: reason contains a programmatic identifier indicating
+                        the reason for the condition's last transition. Producers
+                        of specific condition types may define expected values and
+                        meanings for this field, and whether the values are considered
+                        a guaranteed API. The value should be a CamelCase string.
+                        This field may not be empty.
+                      maxLength: 1024
+                      minLength: 1
+                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+                      type: string
+                    status:
+                      description: status of the condition, one of True, False, Unknown.
+                      enum:
+                      - "True"
+                      - "False"
+                      - Unknown
+                      type: string
+                    type:
+                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
+                        --- Many .condition.type values are consistent across resources
+                        like Available, but because arbitrary conditions can be useful
+                        (see .node.status.conditions), the ability to deconflict is
+                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
+                      maxLength: 316
+                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - message
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+              observedGeneration:
+                description: ObservedGeneration is the last observed generation.
+                format: int64
+                type: integer
+            type: object
+        type: object
+    served: true
+    storage: false
+    subresources:
+      status: {}
+  - additionalPrinterColumns:
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    - jsonPath: .status.conditions[?(@.type=="Ready")].status
+      name: Ready
+      type: string
+    - jsonPath: .status.conditions[?(@.type=="Ready")].message
+      name: Status
+      type: string
+    name: v1beta2
+    schema:
+      openAPIV3Schema:
+        description: Alert is the Schema for the alerts API
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: AlertSpec defines an alerting rule for events involving a
+              list of objects.
+            properties:
+              eventMetadata:
+                additionalProperties:
+                  type: string
+                description: EventMetadata is an optional field for adding metadata
+                  to events dispatched by the controller. This can be used for enhancing
+                  the context of the event. If a field would override one already
+                  present on the original event as generated by the emitter, then
+                  the override doesn't happen, i.e. the original value is preserved,
+                  and an info log is printed.
+                type: object
+              eventSeverity:
+                default: info
+                description: EventSeverity specifies how to filter events based on
+                  severity. If set to 'info' no events will be filtered.
+                enum:
+                - info
+                - error
+                type: string
+              eventSources:
+                description: EventSources specifies how to filter events based on
+                  the involved object kind, name and namespace.
+                items:
+                  description: CrossNamespaceObjectReference contains enough information
+                    to let you locate the typed referenced object at cluster level
+                  properties:
+                    apiVersion:
+                      description: API version of the referent
+                      type: string
+                    kind:
+                      description: Kind of the referent
+                      enum:
+                      - Bucket
+                      - GitRepository
+                      - Kustomization
+                      - HelmRelease
+                      - HelmChart
+                      - HelmRepository
+                      - ImageRepository
+                      - ImagePolicy
+                      - ImageUpdateAutomation
+                      - OCIRepository
+                      type: string
+                    matchLabels:
+                      additionalProperties:
+                        type: string
+                      description: MatchLabels is a map of {key,value} pairs. A single
+                        {key,value} in the matchLabels map is equivalent to an element
+                        of matchExpressions, whose key field is "key", the operator
+                        is "In", and the values array contains only "value". The requirements
+                        are ANDed. MatchLabels requires the name to be set to `*`.
+                      type: object
+                    name:
+                      description: Name of the referent If multiple resources are
+                        targeted `*` may be set.
+                      maxLength: 53
+                      minLength: 1
+                      type: string
+                    namespace:
+                      description: Namespace of the referent
+                      maxLength: 53
+                      minLength: 1
+                      type: string
+                  required:
+                  - kind
+                  - name
+                  type: object
+                type: array
+              exclusionList:
+                description: ExclusionList specifies a list of Golang regular expressions
+                  to be used for excluding messages.
+                items:
+                  type: string
+                type: array
+              inclusionList:
+                description: InclusionList specifies a list of Golang regular expressions
+                  to be used for including messages.
+                items:
+                  type: string
+                type: array
+              providerRef:
+                description: ProviderRef specifies which Provider this Alert should
+                  use.
+                properties:
+                  name:
+                    description: Name of the referent.
+                    type: string
+                required:
+                - name
+                type: object
+              summary:
+                description: Summary holds a short description of the impact and affected
+                  cluster.
+                maxLength: 255
+                type: string
+              suspend:
+                description: Suspend tells the controller to suspend subsequent events
+                  handling for this Alert.
+                type: boolean
+            required:
+            - eventSources
+            - providerRef
+            type: object
+          status:
+            default:
+              observedGeneration: -1
+            description: AlertStatus defines the observed state of the Alert.
+            properties:
+              conditions:
+                description: Conditions holds the conditions for the Alert.
+                items:
+                  description: "Condition contains details for one aspect of the current
+                    state of this API Resource. --- This struct is intended for direct
+                    use as an array at the field path .status.conditions.  For example,
+                    \n type FooStatus struct{ // Represents the observations of a
+                    foo's current state. // Known .status.conditions.type are: \"Available\",
+                    \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
+                    // +listType=map // +listMapKey=type Conditions []metav1.Condition
+                    `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
+                    protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
+                  properties:
+                    lastTransitionTime:
+                      description: lastTransitionTime is the last time the condition
+                        transitioned from one status to another. This should be when
+                        the underlying condition changed.  If that is not known, then
+                        using the time when the API field changed is acceptable.
+                      format: date-time
+                      type: string
+                    message:
+                      description: message is a human readable message indicating
+                        details about the transition. This may be an empty string.
+                      maxLength: 32768
+                      type: string
+                    observedGeneration:
+                      description: observedGeneration represents the .metadata.generation
+                        that the condition was set based upon. For instance, if .metadata.generation
+                        is currently 12, but the .status.conditions[x].observedGeneration
+                        is 9, the condition is out of date with respect to the current
+                        state of the instance.
+                      format: int64
+                      minimum: 0
+                      type: integer
+                    reason:
+                      description: reason contains a programmatic identifier indicating
+                        the reason for the condition's last transition. Producers
+                        of specific condition types may define expected values and
+                        meanings for this field, and whether the values are considered
+                        a guaranteed API. The value should be a CamelCase string.
+                        This field may not be empty.
+                      maxLength: 1024
+                      minLength: 1
+                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+                      type: string
+                    status:
+                      description: status of the condition, one of True, False, Unknown.
+                      enum:
+                      - "True"
+                      - "False"
+                      - Unknown
+                      type: string
+                    type:
+                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
+                        --- Many .condition.type values are consistent across resources
+                        like Available, but because arbitrary conditions can be useful
+                        (see .node.status.conditions), the ability to deconflict is
+                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
+                      maxLength: 316
+                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - message
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+              lastHandledReconcileAt:
+                description: LastHandledReconcileAt holds the value of the most recent
+                  reconcile request value, so a change of the annotation value can
+                  be detected.
+                type: string
+              observedGeneration:
+                description: ObservedGeneration is the last observed generation.
+                format: int64
+                type: integer
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.12.0
+  labels:
+    app.kubernetes.io/component: notification-controller
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+  name: providers.notification.toolkit.fluxcd.io
+spec:
+  group: notification.toolkit.fluxcd.io
+  names:
+    kind: Provider
+    listKind: ProviderList
+    plural: providers
+    singular: provider
+  scope: Namespaced
+  versions:
+  - additionalPrinterColumns:
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    - jsonPath: .status.conditions[?(@.type=="Ready")].status
+      name: Ready
+      type: string
+    - jsonPath: .status.conditions[?(@.type=="Ready")].message
+      name: Status
+      type: string
+    name: v1beta1
+    schema:
+      openAPIV3Schema:
+        description: Provider is the Schema for the providers API
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: ProviderSpec defines the desired state of Provider
+            properties:
+              address:
+                description: HTTP/S webhook address of this provider
+                pattern: ^(http|https)://
+                type: string
+              certSecretRef:
+                description: CertSecretRef can be given the name of a secret containing
+                  a PEM-encoded CA certificate (`caFile`)
+                properties:
+                  name:
+                    description: Name of the referent.
+                    type: string
+                required:
+                - name
+                type: object
+              channel:
+                description: Alert channel for this provider
+                type: string
+              proxy:
+                description: HTTP/S address of the proxy
+                pattern: ^(http|https)://
+                type: string
+              secretRef:
+                description: Secret reference containing the provider webhook URL
+                  using "address" as data key
+                properties:
+                  name:
+                    description: Name of the referent.
+                    type: string
+                required:
+                - name
+                type: object
+              suspend:
+                description: This flag tells the controller to suspend subsequent
+                  events handling. Defaults to false.
+                type: boolean
+              timeout:
+                description: Timeout for sending alerts to the provider.
+                pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$
+                type: string
+              type:
+                description: Type of provider
+                enum:
+                - slack
+                - discord
+                - msteams
+                - rocket
+                - generic
+                - generic-hmac
+                - github
+                - gitlab
+                - bitbucket
+                - azuredevops
+                - googlechat
+                - webex
+                - sentry
+                - azureeventhub
+                - telegram
+                - lark
+                - matrix
+                - opsgenie
+                - alertmanager
+                - grafana
+                - githubdispatch
+                type: string
+              username:
+                description: Bot username for this provider
+                type: string
+            required:
+            - type
+            type: object
+          status:
+            default:
+              observedGeneration: -1
+            description: ProviderStatus defines the observed state of Provider
+            properties:
+              conditions:
+                items:
+                  description: "Condition contains details for one aspect of the current
+                    state of this API Resource. --- This struct is intended for direct
+                    use as an array at the field path .status.conditions.  For example,
+                    \n type FooStatus struct{ // Represents the observations of a
+                    foo's current state. // Known .status.conditions.type are: \"Available\",
+                    \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
+                    // +listType=map // +listMapKey=type Conditions []metav1.Condition
+                    `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
+                    protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
+                  properties:
+                    lastTransitionTime:
+                      description: lastTransitionTime is the last time the condition
+                        transitioned from one status to another. This should be when
+                        the underlying condition changed.  If that is not known, then
+                        using the time when the API field changed is acceptable.
+                      format: date-time
+                      type: string
+                    message:
+                      description: message is a human readable message indicating
+                        details about the transition. This may be an empty string.
+                      maxLength: 32768
+                      type: string
+                    observedGeneration:
+                      description: observedGeneration represents the .metadata.generation
+                        that the condition was set based upon. For instance, if .metadata.generation
+                        is currently 12, but the .status.conditions[x].observedGeneration
+                        is 9, the condition is out of date with respect to the current
+                        state of the instance.
+                      format: int64
+                      minimum: 0
+                      type: integer
+                    reason:
+                      description: reason contains a programmatic identifier indicating
+                        the reason for the condition's last transition. Producers
+                        of specific condition types may define expected values and
+                        meanings for this field, and whether the values are considered
+                        a guaranteed API. The value should be a CamelCase string.
+                        This field may not be empty.
+                      maxLength: 1024
+                      minLength: 1
+                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+                      type: string
+                    status:
+                      description: status of the condition, one of True, False, Unknown.
+                      enum:
+                      - "True"
+                      - "False"
+                      - Unknown
+                      type: string
+                    type:
+                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
+                        --- Many .condition.type values are consistent across resources
+                        like Available, but because arbitrary conditions can be useful
+                        (see .node.status.conditions), the ability to deconflict is
+                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
+                      maxLength: 316
+                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - message
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+              observedGeneration:
+                description: ObservedGeneration is the last reconciled generation.
+                format: int64
+                type: integer
+            type: object
+        type: object
+    served: true
+    storage: false
+    subresources:
+      status: {}
+  - additionalPrinterColumns:
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    - jsonPath: .status.conditions[?(@.type=="Ready")].status
+      name: Ready
+      type: string
+    - jsonPath: .status.conditions[?(@.type=="Ready")].message
+      name: Status
+      type: string
+    name: v1beta2
+    schema:
+      openAPIV3Schema:
+        description: Provider is the Schema for the providers API.
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: ProviderSpec defines the desired state of the Provider.
+            properties:
+              address:
+                description: Address specifies the endpoint, in a generic sense, to
+                  where alerts are sent. What kind of endpoint depends on the specific
+                  Provider type being used. For the generic Provider, for example,
+                  this is an HTTP/S address. For other Provider types this could be
+                  a project ID or a namespace.
+                maxLength: 2048
+                type: string
+              certSecretRef:
+                description: "CertSecretRef specifies the Secret containing a PEM-encoded
+                  CA certificate (in the `ca.crt` key). \n Note: Support for the `caFile`
+                  key has been deprecated."
+                properties:
+                  name:
+                    description: Name of the referent.
+                    type: string
+                required:
+                - name
+                type: object
+              channel:
+                description: Channel specifies the destination channel where events
+                  should be posted.
+                maxLength: 2048
+                type: string
+              interval:
+                description: Interval at which to reconcile the Provider with its
+                  Secret references.
+                pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
+                type: string
+              proxy:
+                description: Proxy the HTTP/S address of the proxy server.
+                maxLength: 2048
+                pattern: ^(http|https)://.*$
+                type: string
+              secretRef:
+                description: SecretRef specifies the Secret containing the authentication
+                  credentials for this Provider.
+                properties:
+                  name:
+                    description: Name of the referent.
+                    type: string
+                required:
+                - name
+                type: object
+              suspend:
+                description: Suspend tells the controller to suspend subsequent events
+                  handling for this Provider.
+                type: boolean
+              timeout:
+                description: Timeout for sending alerts to the Provider.
+                pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$
+                type: string
+              type:
+                description: Type specifies which Provider implementation to use.
+                enum:
+                - slack
+                - discord
+                - msteams
+                - rocket
+                - generic
+                - generic-hmac
+                - github
+                - gitlab
+                - gitea
+                - bitbucket
+                - azuredevops
+                - googlechat
+                - googlepubsub
+                - webex
+                - sentry
+                - azureeventhub
+                - telegram
+                - lark
+                - matrix
+                - opsgenie
+                - alertmanager
+                - grafana
+                - githubdispatch
+                - pagerduty
+                - datadog
+                type: string
+              username:
+                description: Username specifies the name under which events are posted.
+                maxLength: 2048
+                type: string
+            required:
+            - type
+            type: object
+          status:
+            default:
+              observedGeneration: -1
+            description: ProviderStatus defines the observed state of the Provider.
+            properties:
+              conditions:
+                description: Conditions holds the conditions for the Provider.
+                items:
+                  description: "Condition contains details for one aspect of the current
+                    state of this API Resource. --- This struct is intended for direct
+                    use as an array at the field path .status.conditions.  For example,
+                    \n type FooStatus struct{ // Represents the observations of a
+                    foo's current state. // Known .status.conditions.type are: \"Available\",
+                    \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
+                    // +listType=map // +listMapKey=type Conditions []metav1.Condition
+                    `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
+                    protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
+                  properties:
+                    lastTransitionTime:
+                      description: lastTransitionTime is the last time the condition
+                        transitioned from one status to another. This should be when
+                        the underlying condition changed.  If that is not known, then
+                        using the time when the API field changed is acceptable.
+                      format: date-time
+                      type: string
+                    message:
+                      description: message is a human readable message indicating
+                        details about the transition. This may be an empty string.
+                      maxLength: 32768
+                      type: string
+                    observedGeneration:
+                      description: observedGeneration represents the .metadata.generation
+                        that the condition was set based upon. For instance, if .metadata.generation
+                        is currently 12, but the .status.conditions[x].observedGeneration
+                        is 9, the condition is out of date with respect to the current
+                        state of the instance.
+                      format: int64
+                      minimum: 0
+                      type: integer
+                    reason:
+                      description: reason contains a programmatic identifier indicating
+                        the reason for the condition's last transition. Producers
+                        of specific condition types may define expected values and
+                        meanings for this field, and whether the values are considered
+                        a guaranteed API. The value should be a CamelCase string.
+                        This field may not be empty.
+                      maxLength: 1024
+                      minLength: 1
+                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+                      type: string
+                    status:
+                      description: status of the condition, one of True, False, Unknown.
+                      enum:
+                      - "True"
+                      - "False"
+                      - Unknown
+                      type: string
+                    type:
+                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
+                        --- Many .condition.type values are consistent across resources
+                        like Available, but because arbitrary conditions can be useful
+                        (see .node.status.conditions), the ability to deconflict is
+                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
+                      maxLength: 316
+                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - message
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+              lastHandledReconcileAt:
+                description: LastHandledReconcileAt holds the value of the most recent
+                  reconcile request value, so a change of the annotation value can
+                  be detected.
+                type: string
+              observedGeneration:
+                description: ObservedGeneration is the last reconciled generation.
+                format: int64
+                type: integer
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.12.0
+  labels:
+    app.kubernetes.io/component: notification-controller
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+  name: receivers.notification.toolkit.fluxcd.io
+spec:
+  group: notification.toolkit.fluxcd.io
+  names:
+    kind: Receiver
+    listKind: ReceiverList
+    plural: receivers
+    singular: receiver
+  scope: Namespaced
+  versions:
+  - additionalPrinterColumns:
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    - jsonPath: .status.conditions[?(@.type=="Ready")].status
+      name: Ready
+      type: string
+    - jsonPath: .status.conditions[?(@.type=="Ready")].message
+      name: Status
+      type: string
+    name: v1
+    schema:
+      openAPIV3Schema:
+        description: Receiver is the Schema for the receivers API.
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: ReceiverSpec defines the desired state of the Receiver.
+            properties:
+              events:
+                description: Events specifies the list of event types to handle, e.g.
+                  'push' for GitHub or 'Push Hook' for GitLab.
+                items:
+                  type: string
+                type: array
+              interval:
+                default: 10m
+                description: Interval at which to reconcile the Receiver with its
+                  Secret references.
+                pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
+                type: string
+              resources:
+                description: A list of resources to be notified about changes.
+                items:
+                  description: CrossNamespaceObjectReference contains enough information
+                    to let you locate the typed referenced object at cluster level
+                  properties:
+                    apiVersion:
+                      description: API version of the referent
+                      type: string
+                    kind:
+                      description: Kind of the referent
+                      enum:
+                      - Bucket
+                      - GitRepository
+                      - Kustomization
+                      - HelmRelease
+                      - HelmChart
+                      - HelmRepository
+                      - ImageRepository
+                      - ImagePolicy
+                      - ImageUpdateAutomation
+                      - OCIRepository
+                      type: string
+                    matchLabels:
+                      additionalProperties:
+                        type: string
+                      description: MatchLabels is a map of {key,value} pairs. A single
+                        {key,value} in the matchLabels map is equivalent to an element
+                        of matchExpressions, whose key field is "key", the operator
+                        is "In", and the values array contains only "value". The requirements
+                        are ANDed. MatchLabels requires the name to be set to `*`.
+                      type: object
+                    name:
+                      description: Name of the referent If multiple resources are
+                        targeted `*` may be set.
+                      maxLength: 53
+                      minLength: 1
+                      type: string
+                    namespace:
+                      description: Namespace of the referent
+                      maxLength: 53
+                      minLength: 1
+                      type: string
+                  required:
+                  - kind
+                  - name
+                  type: object
+                type: array
+              secretRef:
+                description: SecretRef specifies the Secret containing the token used
+                  to validate the payload authenticity.
+                properties:
+                  name:
+                    description: Name of the referent.
+                    type: string
+                required:
+                - name
+                type: object
+              suspend:
+                description: Suspend tells the controller to suspend subsequent events
+                  handling for this receiver.
+                type: boolean
+              type:
+                description: Type of webhook sender, used to determine the validation
+                  procedure and payload deserialization.
+                enum:
+                - generic
+                - generic-hmac
+                - github
+                - gitlab
+                - bitbucket
+                - harbor
+                - dockerhub
+                - quay
+                - gcr
+                - nexus
+                - acr
+                type: string
+            required:
+            - resources
+            - secretRef
+            - type
+            type: object
+          status:
+            default:
+              observedGeneration: -1
+            description: ReceiverStatus defines the observed state of the Receiver.
+            properties:
+              conditions:
+                description: Conditions holds the conditions for the Receiver.
+                items:
+                  description: "Condition contains details for one aspect of the current
+                    state of this API Resource. --- This struct is intended for direct
+                    use as an array at the field path .status.conditions.  For example,
+                    \n type FooStatus struct{ // Represents the observations of a
+                    foo's current state. // Known .status.conditions.type are: \"Available\",
+                    \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
+                    // +listType=map // +listMapKey=type Conditions []metav1.Condition
+                    `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
+                    protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
+                  properties:
+                    lastTransitionTime:
+                      description: lastTransitionTime is the last time the condition
+                        transitioned from one status to another. This should be when
+                        the underlying condition changed.  If that is not known, then
+                        using the time when the API field changed is acceptable.
+                      format: date-time
+                      type: string
+                    message:
+                      description: message is a human readable message indicating
+                        details about the transition. This may be an empty string.
+                      maxLength: 32768
+                      type: string
+                    observedGeneration:
+                      description: observedGeneration represents the .metadata.generation
+                        that the condition was set based upon. For instance, if .metadata.generation
+                        is currently 12, but the .status.conditions[x].observedGeneration
+                        is 9, the condition is out of date with respect to the current
+                        state of the instance.
+                      format: int64
+                      minimum: 0
+                      type: integer
+                    reason:
+                      description: reason contains a programmatic identifier indicating
+                        the reason for the condition's last transition. Producers
+                        of specific condition types may define expected values and
+                        meanings for this field, and whether the values are considered
+                        a guaranteed API. The value should be a CamelCase string.
+                        This field may not be empty.
+                      maxLength: 1024
+                      minLength: 1
+                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+                      type: string
+                    status:
+                      description: status of the condition, one of True, False, Unknown.
+                      enum:
+                      - "True"
+                      - "False"
+                      - Unknown
+                      type: string
+                    type:
+                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
+                        --- Many .condition.type values are consistent across resources
+                        like Available, but because arbitrary conditions can be useful
+                        (see .node.status.conditions), the ability to deconflict is
+                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
+                      maxLength: 316
+                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - message
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+              lastHandledReconcileAt:
+                description: LastHandledReconcileAt holds the value of the most recent
+                  reconcile request value, so a change of the annotation value can
+                  be detected.
+                type: string
+              observedGeneration:
+                description: ObservedGeneration is the last observed generation of
+                  the Receiver object.
+                format: int64
+                type: integer
+              webhookPath:
+                description: WebhookPath is the generated incoming webhook address
+                  in the format of '/hook/sha256sum(token+name+namespace)'.
+                type: string
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+  - additionalPrinterColumns:
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    - jsonPath: .status.conditions[?(@.type=="Ready")].status
+      name: Ready
+      type: string
+    - jsonPath: .status.conditions[?(@.type=="Ready")].message
+      name: Status
+      type: string
+    deprecated: true
+    deprecationWarning: v1beta1 Receiver is deprecated, upgrade to v1
+    name: v1beta1
+    schema:
+      openAPIV3Schema:
+        description: Receiver is the Schema for the receivers API
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: ReceiverSpec defines the desired state of Receiver
+            properties:
+              events:
+                description: A list of events to handle, e.g. 'push' for GitHub or
+                  'Push Hook' for GitLab.
+                items:
+                  type: string
+                type: array
+              resources:
+                description: A list of resources to be notified about changes.
+                items:
+                  description: CrossNamespaceObjectReference contains enough information
+                    to let you locate the typed referenced object at cluster level
+                  properties:
+                    apiVersion:
+                      description: API version of the referent
+                      type: string
+                    kind:
+                      description: Kind of the referent
+                      enum:
+                      - Bucket
+                      - GitRepository
+                      - Kustomization
+                      - HelmRelease
+                      - HelmChart
+                      - HelmRepository
+                      - ImageRepository
+                      - ImagePolicy
+                      - ImageUpdateAutomation
+                      - OCIRepository
+                      type: string
+                    matchLabels:
+                      additionalProperties:
+                        type: string
+                      description: MatchLabels is a map of {key,value} pairs. A single
+                        {key,value} in the matchLabels map is equivalent to an element
+                        of matchExpressions, whose key field is "key", the operator
+                        is "In", and the values array contains only "value". The requirements
+                        are ANDed.
+                      type: object
+                    name:
+                      description: Name of the referent
+                      maxLength: 53
+                      minLength: 1
+                      type: string
+                    namespace:
+                      description: Namespace of the referent
+                      maxLength: 53
+                      minLength: 1
+                      type: string
+                  required:
+                  - name
+                  type: object
+                type: array
+              secretRef:
+                description: Secret reference containing the token used to validate
+                  the payload authenticity
+                properties:
+                  name:
+                    description: Name of the referent.
+                    type: string
+                required:
+                - name
+                type: object
+              suspend:
+                description: This flag tells the controller to suspend subsequent
+                  events handling. Defaults to false.
+                type: boolean
+              type:
+                description: Type of webhook sender, used to determine the validation
+                  procedure and payload deserialization.
+                enum:
+                - generic
+                - generic-hmac
+                - github
+                - gitlab
+                - bitbucket
+                - harbor
+                - dockerhub
+                - quay
+                - gcr
+                - nexus
+                - acr
+                type: string
+            required:
+            - resources
+            - type
+            type: object
+          status:
+            default:
+              observedGeneration: -1
+            description: ReceiverStatus defines the observed state of Receiver
+            properties:
+              conditions:
+                items:
+                  description: "Condition contains details for one aspect of the current
+                    state of this API Resource. --- This struct is intended for direct
+                    use as an array at the field path .status.conditions.  For example,
+                    \n type FooStatus struct{ // Represents the observations of a
+                    foo's current state. // Known .status.conditions.type are: \"Available\",
+                    \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
+                    // +listType=map // +listMapKey=type Conditions []metav1.Condition
+                    `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
+                    protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
+                  properties:
+                    lastTransitionTime:
+                      description: lastTransitionTime is the last time the condition
+                        transitioned from one status to another. This should be when
+                        the underlying condition changed.  If that is not known, then
+                        using the time when the API field changed is acceptable.
+                      format: date-time
+                      type: string
+                    message:
+                      description: message is a human readable message indicating
+                        details about the transition. This may be an empty string.
+                      maxLength: 32768
+                      type: string
+                    observedGeneration:
+                      description: observedGeneration represents the .metadata.generation
+                        that the condition was set based upon. For instance, if .metadata.generation
+                        is currently 12, but the .status.conditions[x].observedGeneration
+                        is 9, the condition is out of date with respect to the current
+                        state of the instance.
+                      format: int64
+                      minimum: 0
+                      type: integer
+                    reason:
+                      description: reason contains a programmatic identifier indicating
+                        the reason for the condition's last transition. Producers
+                        of specific condition types may define expected values and
+                        meanings for this field, and whether the values are considered
+                        a guaranteed API. The value should be a CamelCase string.
+                        This field may not be empty.
+                      maxLength: 1024
+                      minLength: 1
+                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+                      type: string
+                    status:
+                      description: status of the condition, one of True, False, Unknown.
+                      enum:
+                      - "True"
+                      - "False"
+                      - Unknown
+                      type: string
+                    type:
+                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
+                        --- Many .condition.type values are consistent across resources
+                        like Available, but because arbitrary conditions can be useful
+                        (see .node.status.conditions), the ability to deconflict is
+                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
+                      maxLength: 316
+                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - message
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+              observedGeneration:
+                description: ObservedGeneration is the last observed generation.
+                format: int64
+                type: integer
+              url:
+                description: Generated webhook URL in the format of '/hook/sha256sum(token+name+namespace)'.
+                type: string
+            type: object
+        type: object
+    served: true
+    storage: false
+    subresources:
+      status: {}
+  - additionalPrinterColumns:
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    - jsonPath: .status.conditions[?(@.type=="Ready")].status
+      name: Ready
+      type: string
+    - jsonPath: .status.conditions[?(@.type=="Ready")].message
+      name: Status
+      type: string
+    deprecated: true
+    deprecationWarning: v1beta2 Receiver is deprecated, upgrade to v1
+    name: v1beta2
+    schema:
+      openAPIV3Schema:
+        description: Receiver is the Schema for the receivers API.
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: ReceiverSpec defines the desired state of the Receiver.
+            properties:
+              events:
+                description: Events specifies the list of event types to handle, e.g.
+                  'push' for GitHub or 'Push Hook' for GitLab.
+                items:
+                  type: string
+                type: array
+              interval:
+                description: Interval at which to reconcile the Receiver with its
+                  Secret references.
+                pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
+                type: string
+              resources:
+                description: A list of resources to be notified about changes.
+                items:
+                  description: CrossNamespaceObjectReference contains enough information
+                    to let you locate the typed referenced object at cluster level
+                  properties:
+                    apiVersion:
+                      description: API version of the referent
+                      type: string
+                    kind:
+                      description: Kind of the referent
+                      enum:
+                      - Bucket
+                      - GitRepository
+                      - Kustomization
+                      - HelmRelease
+                      - HelmChart
+                      - HelmRepository
+                      - ImageRepository
+                      - ImagePolicy
+                      - ImageUpdateAutomation
+                      - OCIRepository
+                      type: string
+                    matchLabels:
+                      additionalProperties:
+                        type: string
+                      description: MatchLabels is a map of {key,value} pairs. A single
+                        {key,value} in the matchLabels map is equivalent to an element
+                        of matchExpressions, whose key field is "key", the operator
+                        is "In", and the values array contains only "value". The requirements
+                        are ANDed. MatchLabels requires the name to be set to `*`.
+                      type: object
+                    name:
+                      description: Name of the referent If multiple resources are
+                        targeted `*` may be set.
+                      maxLength: 53
+                      minLength: 1
+                      type: string
+                    namespace:
+                      description: Namespace of the referent
+                      maxLength: 53
+                      minLength: 1
+                      type: string
+                  required:
+                  - kind
+                  - name
+                  type: object
+                type: array
+              secretRef:
+                description: SecretRef specifies the Secret containing the token used
+                  to validate the payload authenticity.
+                properties:
+                  name:
+                    description: Name of the referent.
+                    type: string
+                required:
+                - name
+                type: object
+              suspend:
+                description: Suspend tells the controller to suspend subsequent events
+                  handling for this receiver.
+                type: boolean
+              type:
+                description: Type of webhook sender, used to determine the validation
+                  procedure and payload deserialization.
+                enum:
+                - generic
+                - generic-hmac
+                - github
+                - gitlab
+                - bitbucket
+                - harbor
+                - dockerhub
+                - quay
+                - gcr
+                - nexus
+                - acr
+                type: string
+            required:
+            - resources
+            - type
+            type: object
+          status:
+            default:
+              observedGeneration: -1
+            description: ReceiverStatus defines the observed state of the Receiver.
+            properties:
+              conditions:
+                description: Conditions holds the conditions for the Receiver.
+                items:
+                  description: "Condition contains details for one aspect of the current
+                    state of this API Resource. --- This struct is intended for direct
+                    use as an array at the field path .status.conditions.  For example,
+                    \n type FooStatus struct{ // Represents the observations of a
+                    foo's current state. // Known .status.conditions.type are: \"Available\",
+                    \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
+                    // +listType=map // +listMapKey=type Conditions []metav1.Condition
+                    `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
+                    protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
+                  properties:
+                    lastTransitionTime:
+                      description: lastTransitionTime is the last time the condition
+                        transitioned from one status to another. This should be when
+                        the underlying condition changed.  If that is not known, then
+                        using the time when the API field changed is acceptable.
+                      format: date-time
+                      type: string
+                    message:
+                      description: message is a human readable message indicating
+                        details about the transition. This may be an empty string.
+                      maxLength: 32768
+                      type: string
+                    observedGeneration:
+                      description: observedGeneration represents the .metadata.generation
+                        that the condition was set based upon. For instance, if .metadata.generation
+                        is currently 12, but the .status.conditions[x].observedGeneration
+                        is 9, the condition is out of date with respect to the current
+                        state of the instance.
+                      format: int64
+                      minimum: 0
+                      type: integer
+                    reason:
+                      description: reason contains a programmatic identifier indicating
+                        the reason for the condition's last transition. Producers
+                        of specific condition types may define expected values and
+                        meanings for this field, and whether the values are considered
+                        a guaranteed API. The value should be a CamelCase string.
+                        This field may not be empty.
+                      maxLength: 1024
+                      minLength: 1
+                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+                      type: string
+                    status:
+                      description: status of the condition, one of True, False, Unknown.
+                      enum:
+                      - "True"
+                      - "False"
+                      - Unknown
+                      type: string
+                    type:
+                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
+                        --- Many .condition.type values are consistent across resources
+                        like Available, but because arbitrary conditions can be useful
+                        (see .node.status.conditions), the ability to deconflict is
+                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
+                      maxLength: 316
+                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - message
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+              lastHandledReconcileAt:
+                description: LastHandledReconcileAt holds the value of the most recent
+                  reconcile request value, so a change of the annotation value can
+                  be detected.
+                type: string
+              observedGeneration:
+                description: ObservedGeneration is the last observed generation of
+                  the Receiver object.
+                format: int64
+                type: integer
+              url:
+                description: 'URL is the generated incoming webhook address in the
+                  format of ''/hook/sha256sum(token+name+namespace)''. Deprecated:
+                  Replaced by WebhookPath.'
+                type: string
+              webhookPath:
+                description: WebhookPath is the generated incoming webhook address
+                  in the format of '/hook/sha256sum(token+name+namespace)'.
+                type: string
+            type: object
+        type: object
+    served: true
+    storage: false
+    subresources:
+      status: {}
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  labels:
+    app.kubernetes.io/component: notification-controller
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+  name: notification-controller
+  namespace: flux-system
+---
+apiVersion: v1
+kind: Service
+metadata:
+  labels:
+    app.kubernetes.io/component: notification-controller
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+    control-plane: controller
+  name: notification-controller
+  namespace: flux-system
+spec:
+  ports:
+  - name: http
+    port: 80
+    protocol: TCP
+    targetPort: http
+  selector:
+    app: notification-controller
+  type: ClusterIP
+---
+apiVersion: v1
+kind: Service
+metadata:
+  labels:
+    app.kubernetes.io/component: notification-controller
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+    control-plane: controller
+  name: webhook-receiver
+  namespace: flux-system
+spec:
+  ports:
+  - name: http
+    port: 80
+    protocol: TCP
+    targetPort: http-webhook
+  selector:
+    app: notification-controller
+  type: ClusterIP
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  labels:
+    app.kubernetes.io/component: notification-controller
+    app.kubernetes.io/instance: flux-system
+    app.kubernetes.io/part-of: flux
+    app.kubernetes.io/version: v2.1.2
+    control-plane: controller
+  name: notification-controller
+  namespace: flux-system
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: notification-controller
+  template:
+    metadata:
+      annotations:
+        prometheus.io/port: "8080"
+        prometheus.io/scrape: "true"
+      labels:
+        app: notification-controller
+    spec:
+      containers:
+      - args:
+        - --watch-all-namespaces=true
+        - --log-level=info
+        - --log-encoding=json
+        - --enable-leader-election
+        env:
+        - name: RUNTIME_NAMESPACE
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.namespace
+        image: ghcr.io/fluxcd/notification-controller:v1.1.0
+        imagePullPolicy: IfNotPresent
+        livenessProbe:
+          httpGet:
+            path: /healthz
+            port: healthz
+        name: manager
+        ports:
+        - containerPort: 9090
+          name: http
+          protocol: TCP
+        - containerPort: 9292
+          name: http-webhook
+          protocol: TCP
+        - containerPort: 8080
+          name: http-prom
+          protocol: TCP
+        - containerPort: 9440
+          name: healthz
+          protocol: TCP
+        readinessProbe:
+          httpGet:
+            path: /readyz
+            port: healthz
+        resources:
+          limits:
+            cpu: 1000m
+            memory: 1Gi
+          requests:
+            cpu: 100m
+            memory: 64Mi
+        securityContext:
+          allowPrivilegeEscalation: false
+          capabilities:
+            drop:
+            - ALL
+          readOnlyRootFilesystem: true
+          runAsNonRoot: true
+          seccompProfile:
+            type: RuntimeDefault
+        volumeMounts:
+        - mountPath: /tmp
+          name: temp
+      nodeSelector:
+        kubernetes.io/os: linux
+      securityContext:
+        fsGroup: 1337
+      serviceAccountName: notification-controller
+      terminationGracePeriodSeconds: 10
+      volumes:
+      - emptyDir: {}
+        name: temp
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/flux-system/gotk-sync.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/flux-system/gotk-sync.yaml
new file mode 100644 (file)
index 0000000..4346fee
--- /dev/null
@@ -0,0 +1,44 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+# This manifest was generated by flux. DO NOT EDIT.
+---
+apiVersion: source.toolkit.fluxcd.io/v1
+kind: GitRepository
+metadata:
+  name: flux-system
+  namespace: flux-system
+spec:
+  interval: 1m0s
+  ref:
+    branch: main
+  secretRef:
+    name: flux-system
+  url: ${FLEET_REPO_URL}
+---
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: flux-system
+  namespace: flux-system
+spec:
+  interval: 10m0s
+  path: ./clusters/${CLUSTER_KUSTOMIZATION_NAME}
+  prune: true
+  sourceRef:
+    kind: GitRepository
+    name: flux-system
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/flux-system/kustomization.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/flux-system/kustomization.yaml
new file mode 100644 (file)
index 0000000..705b72e
--- /dev/null
@@ -0,0 +1,22 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
+resources:
+- gotk-components.yaml
+- gotk-sync.yaml
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/infra-configs.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/infra-configs.yaml
new file mode 100644 (file)
index 0000000..d2879eb
--- /dev/null
@@ -0,0 +1,49 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: infra-configs
+  namespace: flux-system
+  labels:
+    osm_profile_type: infra-configs
+spec:
+  dependsOn:
+    - name: infra-controllers
+  interval: 1h
+  retryInterval: 1m
+  timeout: 5m
+  sourceRef:
+    kind: GitRepository
+    name: fleet-repo
+  path: ${INFRA_CONFIGS_PATH}
+  prune: true
+  # Decryption configuration starts here
+  decryption:
+    provider: sops
+    secretRef:
+      name: sops-age
+  # patches:
+  #   - patch: |
+  #       - op: replace
+  #         path: /spec/acme/server
+  #         value: https://acme-v02.api.letsencrypt.org/directory
+  #     target:
+  #       kind: ClusterIssuer
+  #       name: letsencrypt
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/infra-controllers.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/infra-controllers.yaml
new file mode 100644 (file)
index 0000000..671afc8
--- /dev/null
@@ -0,0 +1,40 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: infra-controllers
+  namespace: flux-system
+  labels:
+    osm_profile_type: infra-controllers
+spec:
+  interval: 1h
+  retryInterval: 1m
+  timeout: 5m
+  sourceRef:
+    kind: GitRepository
+    name: fleet-repo
+  path: ${INFRA_CONTROLLERS_PATH}
+  prune: true
+  wait: true
+  # Decryption configuration starts here
+  decryption:
+    provider: sops
+    secretRef:
+      name: sops-age
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/kustomization.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/kustomization.yaml
new file mode 100644 (file)
index 0000000..6e3c9af
--- /dev/null
@@ -0,0 +1,36 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
+resources:
+  # Repos
+  - fleet-repo.yaml
+  - sw-catalogs-repo.yaml
+
+  # Base cluster structure (CRDs, operators and their configs)
+  - infra-controllers.yaml
+  - infra-configs.yaml
+
+  # Managed resources
+  - managed-resources.yaml
+
+  # Managed apps
+  - apps.yaml
+
+  # Adds also the `flux-system` folder to preserve bootstrap structure
+  - flux-system
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/managed-resources.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/managed-resources.yaml
new file mode 100644 (file)
index 0000000..2d59cc9
--- /dev/null
@@ -0,0 +1,52 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# Namespace
+# apiVersion: v1
+# kind: Namespace
+# metadata:
+#   name: managed-resources
+
+---
+# Managed resources
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: managed-resources
+  namespace: flux-system
+  labels:
+    osm_profile_type: managed-resources
+spec:
+  # interval: 10m0s
+  interval: 7m0s
+  dependsOn:
+    - name: infra-configs
+  sourceRef:
+    kind: GitRepository
+    name: fleet-repo
+  path: ${MANAGED_RESOURCES_PATH}
+  prune: true
+  wait: true
+  # timeout: 5m0s
+  timeout: 7m0s
+  retryInterval: 2m0s
+  # Decryption configuration starts here
+  decryption:
+    provider: sops
+    secretRef:
+      name: sops-age
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/sw-catalogs-repo.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/cluster-base/templates/sw-catalogs-repo.yaml
new file mode 100644 (file)
index 0000000..75bc138
--- /dev/null
@@ -0,0 +1,30 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: source.toolkit.fluxcd.io/v1
+kind: GitRepository
+metadata:
+  name: sw-catalogs
+  namespace: flux-system
+spec:
+  interval: 1m0s
+  ref:
+    branch: main
+  secretRef:
+    name: sw-catalogs
+  url: ${SW_CATALOGS_REPO_URL}
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/empty-kustomization/manifests/configmap/reference-cm.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/empty-kustomization/manifests/configmap/reference-cm.yaml
new file mode 100644 (file)
index 0000000..f038bd0
--- /dev/null
@@ -0,0 +1,25 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# Template for creating remote ConfigMaps
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: ${configmap_name}
+  namespace: ${configmap_namespace}
+data: {}
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/empty-kustomization/templates/kustomization-placeholder.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/flux-remote-bootstrap/empty-kustomization/templates/kustomization-placeholder.yaml
new file mode 100644 (file)
index 0000000..9742d3f
--- /dev/null
@@ -0,0 +1,50 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+# Creates required remote namespaces
+apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
+kind: Kustomization
+metadata:
+  name: ${CLUSTER_KUSTOMIZATION_NAME}
+  namespace: managed-resources
+  labels:
+    cluster: ${CLUSTER_KUSTOMIZATION_NAME}
+spec:
+  interval: 1m
+  timeout: 5m
+  prune: true
+  # force: true
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
+  path: ./cloud-resources/flux-remote-bootstrap/empty-kustomization/manifests/configmap
+  patches:
+    - patch: |-
+        apiVersion: v1
+        kind: ConfigMap
+        metadata:
+          name: ${configmap_name}
+          namespace: ${configmap_namespace}
+        data:
+          kubeconfig: ${kubeconfig_secret_name}
+  # Inputs:
+  postBuild:
+    substitute:
+      configmap_name: imported-${CLUSTER_KUSTOMIZATION_NAME}
+      configmap_namespace: managed-resources
+      kubeconfig_secret_name: kubeconfig-${CLUSTER_KUSTOMIZATION_NAME}
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/gke/manifests/gke.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/gke/manifests/gke.yaml
new file mode 100644 (file)
index 0000000..1677801
--- /dev/null
@@ -0,0 +1,91 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: container.gcp.upbound.io/v1beta1
+kind: NodePool
+metadata:
+  annotations:
+    meta.upbound.io/example-id: container/v1beta1/nodepool
+  labels:
+    testing.upbound.io/example-name: ${cluster_name}
+  name: nodepool-${cluster_resource_name}
+spec:
+  forProvider:
+    # Force K8s version
+    # version: '1.27'
+    clusterSelector:
+      matchLabels:
+        testing.upbound.io/example-name: ${cluster_name}
+    nodeConfig:
+    - machineType: ${vm_size}
+      oauthScopes:
+      - https://www.googleapis.com/auth/cloud-platform
+      preemptible: ${preemptible_nodes}
+      serviceAccountSelector:
+        matchLabels:
+          testing.upbound.io/example-name: ${cluster_name}
+    nodeCount: 1
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
+
+---
+apiVersion: container.gcp.upbound.io/v1beta1
+kind: Cluster
+metadata:
+  annotations:
+    meta.upbound.io/example-id: container/v1beta1/cluster
+  labels:
+    testing.upbound.io/example-name: ${cluster_name}
+  name: ${cluster_resource_name}
+spec:
+  forProvider:
+    initialNodeCount: 1
+    location: ${cluster_location}
+    # Force K8s version
+    minMasterVersion: '1.27'
+    removeDefaultNodePool: true
+    # To enable client authentication in GKE:
+    # See: <https://cloud.google.com/config-connector/docs/reference/resource-docs/container/containercluster>
+    masterAuth:
+    - clientCertificateConfig:
+      - issueClientCertificate: true
+  publishConnectionDetailsTo:
+    name: kubeconfig-${cluster_resource_name}
+  writeConnectionSecretToRef:
+    name: kubeconfig-${cluster_resource_name}
+    namespace: managed-resources
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
+
+---
+apiVersion: cloudplatform.gcp.upbound.io/v1beta1
+kind: ServiceAccount
+metadata:
+  annotations:
+    meta.upbound.io/example-id: container/v1beta1/nodepool
+  labels:
+    testing.upbound.io/example-name: ${cluster_name}
+  name: ${cluster_resource_name}
+spec:
+  forProvider:
+    displayName: Service Account for Cluster ${cluster_name}
+  # Use in case you wanted to use different credentials (i.e., ProviderConfig different than default)
+  providerConfigRef:
+    name: ${providerconfig_name}
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/gke/templates/gke01.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/cloud-resources/gke/templates/gke01.yaml
new file mode 100644 (file)
index 0000000..9eccda6
--- /dev/null
@@ -0,0 +1,99 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# TEMPLATE_PARAMETERS:
+# ===================
+#
+# CLUSTER_KUSTOMIZATION_NAME: Name of the cluster in the management cluster (e.g., for `Kustomization`s).
+# - Alternatively, it can be patched at:
+#   .metadata.name
+#   .metadata.labels.cluster
+#   .spec.commonMetadata.labels.cluster
+#
+# PARAMETERS TO PATCH:
+# ===================
+#
+# .spec.postBuild.substitute.providerconfig_name: Name of the GCP ProviderConfig to use to create the GKE cluster.
+# .spec.postBuild.substitute.cluster_name: Name of the cluster in the target cloud. It may differ from `CLUSTER_KUSTOMIZATION_NAME` since naming restrictions are often different from K8s resource naming restrictions (e.g., hyphens vs. underscores).
+# .spec.postBuild.substitute.k8s_version: Kubernetes version.
+# .spec.postBuild.substitute.node_count: Number of worker nodes.
+# .spec.postBuild.substitute.vm_size: Flavor of worker node VMs.
+# .spec.postBuild.substitute.cluster_location: Target cluster region.
+# .spec.postBuild.substitute.preemptible_nodes: (default: "false")
+
+# Cluster resource
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: ${CLUSTER_KUSTOMIZATION_NAME}
+  namespace: managed-resources
+  labels:
+    cluster: ${CLUSTER_KUSTOMIZATION_NAME}
+spec:
+  commonMetadata:
+    labels:
+      cluster: ${CLUSTER_KUSTOMIZATION_NAME}
+  interval: 1h
+  retryInterval: 1m
+  timeout: 5m
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
+  path: ./cloud-resources/gke/manifests
+  prune: true
+  # force: true
+  wait: true
+  patches:
+    - patch: |-
+        apiVersion: container.gcp.upbound.io/v1beta1
+        kind: NodePool
+        metadata:
+          name: nodepool-${cluster_resource_name}
+        spec:
+          forProvider:
+            version: "${k8s_version}"
+            nodeConfig:
+            - machineType: ${vm_size}
+              oauthScopes:
+              - https://www.googleapis.com/auth/cloud-platform
+              preemptible: ${preemptible_nodes}
+              serviceAccountSelector:
+                matchLabels:
+                  testing.upbound.io/example-name: ${cluster_name}
+            nodeCount: ${node_count}
+    - patch: |-
+        apiVersion: container.gcp.upbound.io/v1beta1
+        kind: Cluster
+        metadata:
+          name: ${cluster_resource_name}
+        spec:
+          forProvider:
+            minMasterVersion: "${k8s_version}"
+  # Input parameters
+  postBuild:
+    substitute:
+      providerconfig_name: default
+      cluster_resource_name: ${CLUSTER_KUSTOMIZATION_NAME}
+      cluster_name: mygkecluster01
+      k8s_version: "'1.28'"
+      node_count: "1"
+      vm_size: e2-medium
+      cluster_location: europe-southwest1-a
+      # GKE only
+      preemptible_nodes: "false"
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/crossplane/providers/aws/templates/crossplane-providerconfig-aws.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/crossplane/providers/aws/templates/crossplane-providerconfig-aws.yaml
new file mode 100644 (file)
index 0000000..f4fa5b3
--- /dev/null
@@ -0,0 +1,37 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# PARAMETERS TO PATCH:
+# ===================
+#
+# .metadata.name: (default: "default") Name of the `ProviderConfig` for the cloud credentials.
+# .spec.credentials.secretRef.name: (default: "aws-creds") Name of the secret where the credentials are stored.
+
+# Default configuration for AWS provider for Crossplane
+apiVersion: aws.upbound.io/v1beta1
+kind: ProviderConfig
+metadata:
+  name: default
+spec:
+  credentials:
+    source: Secret
+    secretRef:
+      namespace: crossplane-system
+      name: aws-creds
+      key: creds
+      
\ No newline at end of file
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/crossplane/providers/azure/templates/crossplane-providerconfig-azure.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/crossplane/providers/azure/templates/crossplane-providerconfig-azure.yaml
new file mode 100644 (file)
index 0000000..d557657
--- /dev/null
@@ -0,0 +1,36 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# PARAMETERS TO PATCH:
+# ===================
+#
+# .metadata.name: (default: "default") Name of the `ProviderConfig` for the cloud credentials.
+# .spec.credentials.secretRef.name: (default: "azure-creds") Name of the secret where the credentials are stored.
+
+# Default configuration for Azure provider for Crossplane
+apiVersion: azure.upbound.io/v1beta1
+kind: ProviderConfig
+metadata:
+  name: default
+spec:
+  credentials:
+    source: Secret
+    secretRef:
+      namespace: crossplane-system
+      name: azure-creds
+      key: creds
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/crossplane/providers/gcp/templates/crossplane-providerconfig-gcp.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/crossplane/providers/gcp/templates/crossplane-providerconfig-gcp.yaml
new file mode 100644 (file)
index 0000000..849753b
--- /dev/null
@@ -0,0 +1,37 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# PARAMETERS TO PATCH:
+# ===================
+#
+# .metadata.name: (default: "default") Name of the `ProviderConfig` for the cloud credentials.
+# .spec.credentials.secretRef.name: (default: "gcp-creds") Name of the secret where the credentials are stored.
+
+# Default configuration for GCP provider for Crossplane
+apiVersion: gcp.upbound.io/v1beta1
+kind: ProviderConfig
+metadata:
+  name: default
+spec:
+  projectID: ${GCP_PROJECT}
+  credentials:
+    source: Secret
+    secretRef:
+      namespace: crossplane-system
+      name: gcp-creds
+      key: creds
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/kubernetes-dashboard/templates/cluster-role-binding-dashboard.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/kubernetes-dashboard/templates/cluster-role-binding-dashboard.yaml
new file mode 100644 (file)
index 0000000..9bb21ab
--- /dev/null
@@ -0,0 +1,29 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: admin-user
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: cluster-admin
+subjects:
+- kind: ServiceAccount
+  name: admin-user
+  namespace: kubernetes-dashboard
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/kubernetes-dashboard/templates/sa-dashboard.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/kubernetes-dashboard/templates/sa-dashboard.yaml
new file mode 100644 (file)
index 0000000..51325a1
--- /dev/null
@@ -0,0 +1,22 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: admin-user
+  namespace: kubernetes-dashboard
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/kubernetes-dashboard/templates/secret-token-dashboard.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/kubernetes-dashboard/templates/secret-token-dashboard.yaml
new file mode 100644 (file)
index 0000000..d7c170c
--- /dev/null
@@ -0,0 +1,25 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: v1
+kind: Secret
+metadata:
+  name: admin-user
+  namespace: kubernetes-dashboard
+  annotations:
+    kubernetes.io/service-account.name: "admin-user"
+type: kubernetes.io/service-account-token
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/sa-and-role.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/sa-and-role.yaml
new file mode 100644 (file)
index 0000000..6170b65
--- /dev/null
@@ -0,0 +1,87 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: argo
+  namespace: osm-workflows
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: argo-role
+  namespace: osm-workflows
+rules:
+- apiGroups:
+  - coordination.k8s.io
+  resources:
+  - leases
+  verbs:
+  - create
+  - get
+  - update
+- apiGroups:
+  - ""
+  resources:
+  - pods
+  - secrets
+  - configmaps
+  - persistentvolumeclaims
+  - persistentvolumeclaims/finalizers
+  verbs:
+  - create
+  - update
+  - delete
+  - get
+  - patch
+- apiGroups:
+  - argoproj.io
+  resources:
+  - workflowtaskresults
+  verbs:
+  - create
+  - patch
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: argo-binding
+  namespace: osm-workflows
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: argo-role
+subjects:
+- kind: ServiceAccount
+  name: argo
+  namespace: osm-workflows
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: default-binding
+  namespace: osm-workflows
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: argo-role
+subjects:
+- kind: ServiceAccount
+  name: default
+  namespace: osm-workflows
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/building-blocks/clone-transform-push-wft.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/building-blocks/clone-transform-push-wft.yaml
new file mode 100644 (file)
index 0000000..537753a
--- /dev/null
@@ -0,0 +1,133 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: clone-transform-push-wft
+  namespace: osm-workflows
+
+spec:
+  arguments:
+    parameters:
+    # Fleet repo
+    - name: git_fleet_url
+    - name: fleet_destination_folder
+    - name: git_fleet_cred_secret
+    # SW-Catalogs repo
+    - name: git_sw_catalogs_url
+    - name: sw_catalogs_destination_folder
+    - name: git_sw_catalogs_cred_secret
+    # Transformation template
+    - name: templateref_name
+      # value: debugging-wft
+    - name: templateref_template
+      # value: ls-command
+
+  entrypoint: main
+
+  templates:
+
+  # Main template
+  - name: main
+    inputs:
+      parameters:
+      - name: git_fleet_url
+      - name: fleet_destination_folder
+      - name: git_fleet_cred_secret
+      - name: git_sw_catalogs_url
+      - name: sw_catalogs_destination_folder
+      - name: git_sw_catalogs_cred_secret
+      - name: templateref_name
+      - name: templateref_template
+    steps:
+    - - name: generate-volume-repos
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+    - - name: clone-fleet
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-volume-repos.outputs.parameters.pvc-name}}'
+    - - name: clone-sw-catalogs
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: repo_url
+            value: "{{inputs.parameters.git_sw_catalogs_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.sw_catalogs_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_sw_catalogs_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-volume-repos.outputs.parameters.pvc-name}}'
+    - - name: transform
+        templateRef:
+          name: "{{inputs.parameters.templateref_name}}"
+          template: "{{inputs.parameters.templateref_template}}"
+        arguments:
+          parameters:
+          - name: folder
+            value: "/repos"
+          - name: volume_name
+            value: '{{steps.generate-volume-repos.outputs.parameters.pvc-name}}'
+          - name: mount_path
+            value: "/repos"
+    # - - name: list-repo-files
+    #     template: ls-command
+    #     arguments:
+    #       parameters:
+    #       - name: folder
+    #         value: "/repos"
+    #       - name: volume_name
+    #         value: '{{steps.generate-volume-repos.outputs.parameters.pvc-name}}'
+    #       - name: mount_path
+    #         value: "/repos"
+    - - name: push-to-fleet
+        templateRef:
+          name: git-wft
+          template: git-commit-merge-push
+        arguments:
+          parameters:
+          - name: repo_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-volume-repos.outputs.parameters.pvc-name}}'
+          - name: commit_message
+            value: "My test commit message"
+          - name: main_branch
+            value: main
+          - name: contrib_branch
+            value: osm_contrib
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/building-blocks/cloud-accounts-wft.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/building-blocks/cloud-accounts-wft.yaml
new file mode 100644 (file)
index 0000000..18c739d
--- /dev/null
@@ -0,0 +1,267 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: cloud-accounts-wft
+  namespace: osm-workflows
+spec:
+  templates:
+
+  # Create a `ProviderConfig` for CrossPlane
+  - name: create-crossplane-providerconfig
+    inputs:
+      parameters:
+      # Volumes with cloned repos
+      - name: fleet_volume_name
+      - name: fleet_mount_path
+        value: "/fleet"
+      - name: sw_catalogs_volume_name
+      - name: sw_catalogs_mount_path
+        value: "/sw-catalogs"
+
+      # Specific parameters
+      - name: providerconfig_name
+      ## As of today, one among `azure`, `aws` or `gcp`
+      - name: provider_type
+      ## Final secret to reference from the `ProviderConfig`
+      - name: cred_secret_name
+      ## Temporary secret with secret contents for the workflow
+      ## - If `temp_cred_secret_name` is empty, assumes that the final secret already exists
+      - name: temp_cred_secret_name
+        value: ""
+      - name: temp_cred_secret_key
+        value: "creds"
+      - name: age_public_key_mgmt
+      - name: osm_project_name
+        value: "osm_admin"
+      ## Specific parameters - GCP only
+      - name: target_gcp_project
+        value: ""
+      # Debug?
+      - name: debug
+        value: "false"
+
+      # Other parameters - Do not touch
+      - name: cred_secret_key
+        value: "creds"
+      - name: mgmt_cluster_name
+        value: "_management"
+      - name: cred_secret_ns
+        value: "crossplane-system"
+      - name: base_templates_path
+        value: "infra-configs/crossplane/providers"
+      - name: cloned_fleet_folder_name
+        value: "fleet-osm"
+      - name: cloned_sw_catalogs_folder_name
+        value: "sw-catalogs-osm"
+
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      env:
+      - name: CRED_SECRET_CONTENT
+        valueFrom:
+          secretKeyRef:
+            name: "{{inputs.parameters.temp_cred_secret_name}}"
+            key: "{{inputs.parameters.temp_cred_secret_key}}"
+          default: ""
+      - name: DEBUG
+        value: "{{inputs.parameters.debug}}"
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+      - create_crossplane_providerconfig
+      - "{{inputs.parameters.providerconfig_name}}"
+      - "{{inputs.parameters.provider_type}}"
+      - "{{inputs.parameters.cred_secret_name}}"
+      - "{{inputs.parameters.cred_secret_key}}"
+      - "{{inputs.parameters.cred_secret_ns}}"
+      - ''
+      - "{{inputs.parameters.age_public_key_mgmt}}"
+      - "{{inputs.parameters.fleet_mount_path}}/{{inputs.parameters.cloned_fleet_folder_name}}"
+      - "{{inputs.parameters.sw_catalogs_mount_path}}/{{inputs.parameters.cloned_sw_catalogs_folder_name}}"
+      - "{{inputs.parameters.target_gcp_project}}"
+      - "{{inputs.parameters.base_templates_path}}"
+      - "{{inputs.parameters.osm_project_name}}"
+      - "{{inputs.parameters.mgmt_cluster_name}}"
+      volumeMounts:
+      - name: fleet-repo-volume
+        mountPath: '{{inputs.parameters.fleet_mount_path}}'
+      - name: sw-catalogs-repo-volume
+        mountPath: '{{inputs.parameters.sw_catalogs_mount_path}}'
+    volumes:
+      - name: fleet-repo-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.fleet_volume_name}}'
+      - name: sw-catalogs-repo-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.sw_catalogs_volume_name}}'
+    securityContext:
+      fsGroup: 10000
+    #   runAsUser: 10000
+    #   runAsGroup: 10000
+
+
+  # Update a `ProviderConfig` for CrossPlane
+  - name: update-crossplane-providerconfig
+    inputs:
+      parameters:
+      # Volumes with cloned repos
+      - name: fleet_volume_name
+      - name: fleet_mount_path
+        value: "/fleet"
+      - name: sw_catalogs_volume_name
+      - name: sw_catalogs_mount_path
+        value: "/sw-catalogs"
+
+      # Specific parameters
+      - name: providerconfig_name
+      ## As of today, one among `azure`, `aws` or `gcp`
+      - name: provider_type
+      ## Final secret to reference from the `ProviderConfig`
+      - name: cred_secret_name
+      ## Temporary secret with secret contents for the workflow
+      ## - If `temp_cred_secret_name` is empty, assumes that the final secret already exists
+      - name: temp_cred_secret_name
+        value: ""
+      - name: temp_cred_secret_key
+        value: "creds"
+      - name: age_public_key_mgmt
+      - name: osm_project_name
+        value: "osm_admin"
+      ## Specific parameters - GCP only
+      - name: target_gcp_project
+        value: ""
+      # Debug?
+      - name: debug
+        value: "false"
+
+      # Other parameters - Do not touch
+      - name: cred_secret_key
+        value: "creds"
+      - name: mgmt_cluster_name
+        value: "_management"
+      - name: cred_secret_ns
+        value: "crossplane-system"
+      - name: base_templates_path
+        value: "infra-configs/crossplane/providers"
+      - name: cloned_fleet_folder_name
+        value: "fleet-osm"
+      - name: cloned_sw_catalogs_folder_name
+        value: "sw-catalogs-osm"
+
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      env:
+      - name: CRED_SECRET_CONTENT
+        valueFrom:
+          secretKeyRef:
+            name: "{{inputs.parameters.temp_cred_secret_name}}"
+            key: "{{inputs.parameters.temp_cred_secret_key}}"
+          default: ""
+      - name: DEBUG
+        value: "{{inputs.parameters.debug}}"
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+      - update_crossplane_providerconfig
+      - "{{inputs.parameters.providerconfig_name}}"
+      - "{{inputs.parameters.provider_type}}"
+      - "{{inputs.parameters.cred_secret_name}}"
+      - "{{inputs.parameters.cred_secret_key}}"
+      - "{{inputs.parameters.cred_secret_ns}}"
+      - ''
+      - "{{inputs.parameters.age_public_key_mgmt}}"
+      - "{{inputs.parameters.fleet_mount_path}}/{{inputs.parameters.cloned_fleet_folder_name}}"
+      - "{{inputs.parameters.sw_catalogs_mount_path}}/{{inputs.parameters.cloned_sw_catalogs_folder_name}}"
+      - "{{inputs.parameters.target_gcp_project}}"
+      - "{{inputs.parameters.base_templates_path}}"
+      - "{{inputs.parameters.osm_project_name}}"
+      - "{{inputs.parameters.mgmt_cluster_name}}"
+      volumeMounts:
+      - name: fleet-repo-volume
+        mountPath: '{{inputs.parameters.fleet_mount_path}}'
+      - name: sw-catalogs-repo-volume
+        mountPath: '{{inputs.parameters.sw_catalogs_mount_path}}'
+    volumes:
+      - name: fleet-repo-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.fleet_volume_name}}'
+      - name: sw-catalogs-repo-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.sw_catalogs_volume_name}}'
+    securityContext:
+      fsGroup: 10000
+    #   runAsUser: 10000
+    #   runAsGroup: 10000
+
+
+
+  # Delete a `ProviderConfig` for CrossPlane
+  - name: delete-crossplane-providerconfig
+    inputs:
+      parameters:
+      # Volumes with cloned repos
+      - name: fleet_volume_name
+      - name: fleet_mount_path
+        value: "/fleet"
+      - name: sw_catalogs_volume_name
+      - name: sw_catalogs_mount_path
+        value: "/sw-catalogs"
+
+      # Specific parameters
+      - name: providerconfig_name
+      ## As of today, one among `azure`, `aws` or `gcp`
+      - name: provider_type
+      - name: osm_project_name
+        value: "osm_admin"
+      # Debug?
+      - name: debug
+        value: "false"
+
+      # Other parameters - Do not touch
+      - name: mgmt_cluster_name
+        value: "_management"
+      - name: cloned_fleet_folder_name
+        value: "fleet-osm"
+
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      env:
+      - name: DEBUG
+        value: "{{inputs.parameters.debug}}"
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+      - delete_crossplane_providerconfig
+      - "{{inputs.parameters.providerconfig_name}}"
+      - "{{inputs.parameters.provider_type}}"
+      - "{{inputs.parameters.fleet_mount_path}}/{{inputs.parameters.cloned_fleet_folder_name}}"
+      - "{{inputs.parameters.osm_project_name}}"
+      - "{{inputs.parameters.mgmt_cluster_name}}"
+      volumeMounts:
+      - name: fleet-repo-volume
+        mountPath: '{{inputs.parameters.fleet_mount_path}}'
+    volumes:
+      - name: fleet-repo-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.fleet_volume_name}}'
+    securityContext:
+      fsGroup: 10000
+    #   runAsUser: 10000
+    #   runAsGroup: 10000
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/building-blocks/cluster-management-wft.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/building-blocks/cluster-management-wft.yaml
new file mode 100644 (file)
index 0000000..f70c676
--- /dev/null
@@ -0,0 +1,480 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: cluster-management-wft
+  namespace: osm-workflows
+spec:
+  templates:
+
+  # Create a PaaS cluster using CrossPlane (any cloud)
+  - name: create-crossplane-cluster
+    inputs:
+      parameters:
+      # Volumes with cloned repos
+      - name: fleet_volume_name
+      - name: fleet_mount_path
+        value: "/fleet"
+      - name: sw_catalogs_volume_name
+      - name: sw_catalogs_mount_path
+        value: "/sw-catalogs"
+
+      # Specific parameters
+      - name: cluster_kustomization_name
+      - name: cluster_name
+      ## As of today, one among `aks`, `eks` or `gke`:
+      - name: cluster_type
+      - name: providerconfig_name
+      - name: vm_size
+      - name: node_count
+      - name: cluster_location
+      - name: k8s_version
+      - name: public_key_mgmt
+      - name: public_key_new_cluster
+      - name: secret_name_private_age_key_for_new_cluster
+      - name: key_name_in_secret
+        value: "agekey"
+      - name: fleet_repo_url
+      - name: sw_catalogs_repo_url
+      - name: mgmt_project_name
+        value: "osm_admin"
+      ## Do we want to skip OSM's bootstrap?
+      - name: skip_bootstrap
+        value: "false"
+      ## AKS only (otherwise, empty)
+      - name: rg_name
+        values: ""
+      ## GKE only (otherwise, empty)
+      - name: preemptible_nodes
+        values: "false"
+      # Other parameters - Recommended to keep defaults
+      - name: mgmt_cluster_name
+        value: "_management"
+      - name: base_templates_path
+        value: "cloud-resources"
+      - name: cloned_fleet_folder_name
+        value: "fleet-osm"
+      - name: cloned_sw_catalogs_folder_name
+        value: "sw-catalogs-osm"
+      # Debug?
+      - name: debug
+        value: "false"
+
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      env:
+      - name: PRIVATE_KEY_NEW_CLUSTER
+        valueFrom:
+          secretKeyRef:
+            name: "{{inputs.parameters.secret_name_private_age_key_for_new_cluster}}"
+            key: "{{inputs.parameters.key_name_in_secret}}"
+      - name: DEBUG
+        value: "{{inputs.parameters.debug}}"
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+      - create_crossplane_cluster
+      - "{{inputs.parameters.cluster_kustomization_name}}"
+      - "{{inputs.parameters.cluster_name}}"
+      - "{{inputs.parameters.cluster_type}}"
+      - "{{inputs.parameters.providerconfig_name}}"
+      - "{{inputs.parameters.vm_size}}"
+      - "{{inputs.parameters.node_count}}"
+      - "{{inputs.parameters.cluster_location}}"
+      - "{{inputs.parameters.k8s_version}}"
+      - "{{inputs.parameters.public_key_mgmt}}"
+      - "{{inputs.parameters.public_key_new_cluster}}"
+      - ''
+      - "{{inputs.parameters.rg_name}}"
+      - "{{inputs.parameters.preemptible_nodes}}"
+      - "{{inputs.parameters.fleet_mount_path}}/{{inputs.parameters.cloned_fleet_folder_name}}"
+      - "{{inputs.parameters.fleet_repo_url}}"
+      - "{{inputs.parameters.sw_catalogs_mount_path}}/{{inputs.parameters.cloned_sw_catalogs_folder_name}}"
+      - "{{inputs.parameters.sw_catalogs_repo_url}}"
+      - "{{inputs.parameters.skip_bootstrap}}"
+      - "{{inputs.parameters.mgmt_project_name}}"
+      - "{{inputs.parameters.mgmt_cluster_name}}"
+      - "{{inputs.parameters.base_templates_path}}"
+
+      volumeMounts:
+      - name: fleet-repo-volume
+        mountPath: '{{inputs.parameters.fleet_mount_path}}'
+      - name: sw-catalogs-repo-volume
+        mountPath: '{{inputs.parameters.sw_catalogs_mount_path}}'
+    volumes:
+      - name: fleet-repo-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.fleet_volume_name}}'
+      - name: sw-catalogs-repo-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.sw_catalogs_volume_name}}'
+    securityContext:
+      runAsUser: 10000
+    #   runAsGroup: 10000
+    #   fsGroup: 10000
+
+
+  # Update a PaaS cluster created using CrossPlane (any cloud)
+  - name: update-crossplane-cluster
+    inputs:
+      parameters:
+      # Volumes with cloned repos
+      - name: fleet_volume_name
+      - name: fleet_mount_path
+        value: "/fleet"
+      - name: sw_catalogs_volume_name
+      - name: sw_catalogs_mount_path
+        value: "/sw-catalogs"
+
+      # Specific parameters
+      - name: cluster_kustomization_name
+      - name: cluster_name
+      ## As of today, one among `aks`, `eks` or `gke`:
+      - name: cluster_type
+      - name: providerconfig_name
+      - name: vm_size
+      - name: node_count
+      - name: cluster_location
+      - name: k8s_version
+      - name: public_key_mgmt
+      - name: public_key_new_cluster
+      - name: secret_name_private_age_key_for_new_cluster
+      - name: key_name_in_secret
+        value: "agekey"
+      - name: fleet_repo_url
+      - name: sw_catalogs_repo_url
+      - name: mgmt_project_name
+        value: "osm_admin"
+      ## AKS only (otherwise, empty)
+      - name: rg_name
+        values: ""
+      ## GKE only (otherwise, empty)
+      - name: preemptible_nodes
+        values: "false"
+      # Other parameters - Recommended to keep defaults
+      - name: mgmt_cluster_name
+        value: "_management"
+      - name: base_templates_path
+        value: "cloud-resources"
+      - name: cloned_fleet_folder_name
+        value: "fleet-osm"
+      - name: cloned_sw_catalogs_folder_name
+        value: "sw-catalogs-osm"
+      # Debug?
+      - name: debug
+        value: "false"
+
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      env:
+      - name: PRIVATE_KEY_NEW_CLUSTER
+        valueFrom:
+          secretKeyRef:
+            name: "{{inputs.parameters.secret_name_private_age_key_for_new_cluster}}"
+            key: "{{inputs.parameters.key_name_in_secret}}"
+      - name: DEBUG
+        value: "{{inputs.parameters.debug}}"
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+      - update_crossplane_cluster
+      - "{{inputs.parameters.cluster_kustomization_name}}"
+      - "{{inputs.parameters.cluster_name}}"
+      - "{{inputs.parameters.cluster_type}}"
+      - "{{inputs.parameters.providerconfig_name}}"
+      - "{{inputs.parameters.vm_size}}"
+      - "{{inputs.parameters.node_count}}"
+      - "{{inputs.parameters.cluster_location}}"
+      - "{{inputs.parameters.k8s_version}}"
+      - "{{inputs.parameters.public_key_mgmt}}"
+      - "{{inputs.parameters.public_key_new_cluster}}"
+      - ''
+      - "{{inputs.parameters.rg_name}}"
+      - "{{inputs.parameters.preemptible_nodes}}"
+      - "{{inputs.parameters.fleet_mount_path}}/{{inputs.parameters.cloned_fleet_folder_name}}"
+      - "{{inputs.parameters.fleet_repo_url}}"
+      - "{{inputs.parameters.sw_catalogs_mount_path}}/{{inputs.parameters.cloned_sw_catalogs_folder_name}}"
+      - "{{inputs.parameters.sw_catalogs_repo_url}}"
+      ## Note that during upgrades, OSM's bootstrap is avoided:
+      - "true"
+      - "{{inputs.parameters.mgmt_project_name}}"
+      - "{{inputs.parameters.mgmt_cluster_name}}"
+      - "{{inputs.parameters.base_templates_path}}"
+
+      volumeMounts:
+      - name: fleet-repo-volume
+        mountPath: '{{inputs.parameters.fleet_mount_path}}'
+      - name: sw-catalogs-repo-volume
+        mountPath: '{{inputs.parameters.sw_catalogs_mount_path}}'
+    volumes:
+      - name: fleet-repo-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.fleet_volume_name}}'
+      - name: sw-catalogs-repo-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.sw_catalogs_volume_name}}'
+    securityContext:
+      runAsUser: 10000
+    #   runAsGroup: 10000
+    #   fsGroup: 10000
+
+
+  # TODO: Deprecated - To be removed
+  # Create a PaaS cluster in Azure
+  - name: create-cluster-aks
+    inputs:
+      parameters:
+      # Volumes with cloned repos
+      - name: fleet_volume_name
+      - name: fleet_mount_path
+        value: "/fleet"
+      - name: sw_catalogs_volume_name
+      - name: sw_catalogs_mount_path
+        value: "/sw-catalogs"
+
+      # Specific parameters
+      - name: cluster_name
+      - name: vm_size
+      - name: node_count
+      - name: cluster_location
+      - name: rg_name
+      - name: k8s_version
+      - name: providerconfig_name
+      - name: cluster_kustomization_name
+      - name: mgmt_project_name
+        value: "osm_admin"
+
+      # Other parameters - Recommended to keep defaults
+      - name: fleet_repo_dir
+        value: "/fleet/fleet-osm/"
+      - name: sw_catalogs_repo_dir
+        value: "/sw-catalogs/sw-catalogs-osm/"
+      - name: target_folder
+        value: "{{inputs.parameters.fleet_repo_dir}}/{{inputs.parameters.mgmt_project_name}}/managed-resources/_management"
+      - name: manifest_filename
+        value: "{{inputs.parameters.cluster_name}}.yaml"
+      - name: templates
+        value: "{{inputs.parameters.sw_catalogs_repo_dir}}/cloud-resources/aks/templates/"
+      - name: template_manifest_filename
+        value: "aks01.yaml"
+    volumes:
+      - name: fleet-repo-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.fleet_volume_name}}'
+      - name: sw-catalogs-repo-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.sw_catalogs_volume_name}}'
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      # securityContext:
+      #   runAsUser: 10000
+      #   runAsGroup: 10000
+      #   fsGroup: 10000
+      volumeMounts:
+      - name: fleet-repo-volume
+        mountPath: '{{inputs.parameters.fleet_mount_path}}'
+      - name: sw-catalogs-repo-volume
+        mountPath: '{{inputs.parameters.sw_catalogs_mount_path}}'
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+      - create_cluster_aks
+      - "{{inputs.parameters.cluster_name}}"
+      - "{{inputs.parameters.vm_size}}"
+      - "{{inputs.parameters.node_count}}"
+      - "{{inputs.parameters.cluster_location}}"
+      - "{{inputs.parameters.rg_name}}"
+      - "{{inputs.parameters.k8s_version}}"
+      - "{{inputs.parameters.providerconfig_name}}"
+      - "{{inputs.parameters.cluster_kustomization_name}}"
+      - "{{inputs.parameters.target_folder}}"
+      - "{{inputs.parameters.manifest_filename}}"
+      - "{{inputs.parameters.templates}}"
+      - "{{inputs.parameters.template_manifest_filename}}"
+
+
+  # Bootstrap remote cluster running in **ANY cloud**
+  - name: bootstrap-remote-cluster
+    inputs:
+      parameters:
+      # Volumes with cloned repos
+      - name: fleet_volume_name
+      - name: fleet_mount_path
+        value: "/fleet"
+      - name: sw_catalogs_volume_name
+      - name: sw_catalogs_mount_path
+        value: "/sw-catalogs"
+
+      # Specific parameters
+      - name: cluster_name
+      - name: cluster_kustomization_name
+      - name: public_key_mgmt
+      - name: public_key_new_cluster
+      - name: secret_name_private_age_key_for_new_cluster
+      - name: key_name_in_secret
+        value: "agekey"
+      - name: fleet_repo_url
+      - name: sw_catalogs_repo_url
+
+      # Other parameters - Recommended to keep defaults
+      - name: mgmt_project_name
+        value: "osm_admin"
+      - name: imported_cluster
+        value: "false"
+      - name: fleet_repo_dir
+        value: "/fleet/fleet-osm/"
+      - name: sw_catalogs_repo_dir
+        value: "/sw-catalogs/sw-catalogs-osm/"
+
+      # Debug/dry run?
+      - name: debug
+        value: "false"
+
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      env:
+      - name: PRIVATE_KEY_NEW_CLUSTER
+        valueFrom:
+          secretKeyRef:
+            name: "{{inputs.parameters.secret_name_private_age_key_for_new_cluster}}"
+            key: "{{inputs.parameters.key_name_in_secret}}"
+      - name: DEBUG
+        value: "{{inputs.parameters.debug}}"
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+      - create_bootstrap_for_remote_cluster
+      - "{{inputs.parameters.cluster_name}}"
+      - "{{inputs.parameters.cluster_kustomization_name}}"
+      - "{{inputs.parameters.fleet_repo_dir}}"
+      - "{{inputs.parameters.sw_catalogs_repo_dir}}"
+      - "{{inputs.parameters.fleet_repo_url}}"
+      - "{{inputs.parameters.sw_catalogs_repo_url}}"
+      - "{{inputs.parameters.mgmt_project_name}}"
+      - "{{inputs.parameters.public_key_mgmt}}"
+      - "{{inputs.parameters.public_key_new_cluster}}"
+      - ''
+      - "{{inputs.parameters.imported_cluster}}"
+      volumeMounts:
+      - name: fleet-repo-volume
+        mountPath: '{{inputs.parameters.fleet_mount_path}}'
+      - name: sw-catalogs-repo-volume
+        mountPath: '{{inputs.parameters.sw_catalogs_mount_path}}'
+    volumes:
+      - name: fleet-repo-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.fleet_volume_name}}'
+      - name: sw-catalogs-repo-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.sw_catalogs_volume_name}}'
+    securityContext:
+      runAsUser: 10000
+    #   runAsGroup: 10000
+    #   fsGroup: 10000
+
+
+  # Disconnect Flux in remote cluster running in **ANY cloud**
+  - name: disconnect-flux-remote-cluster
+    inputs:
+      parameters:
+      # Volumes with cloned repos
+      - name: fleet_volume_name
+      - name: fleet_mount_path
+        value: "/fleet"
+
+      # Specific parameters
+      - name: cluster_kustomization_name
+      - name: mgmt_project_name
+        value: "osm_admin"
+
+      # Other parameters - Recommended to keep defaults
+      - name: fleet_repo_dir
+        value: "/fleet/fleet-osm/"
+
+      # Debug/dry run?
+      - name: debug
+        value: "false"
+
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      env:
+      - name: DEBUG
+        value: "{{inputs.parameters.debug}}"
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+      - disconnect_flux_remote_cluster
+      - "{{inputs.parameters.cluster_kustomization_name}}"
+      - "{{inputs.parameters.fleet_repo_dir}}"
+      - "{{inputs.parameters.mgmt_project_name}}"
+      volumeMounts:
+      - name: fleet-repo-volume
+        mountPath: '{{inputs.parameters.fleet_mount_path}}'
+    volumes:
+      - name: fleet-repo-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.fleet_volume_name}}'
+    securityContext:
+      runAsUser: 10000
+    #   runAsGroup: 10000
+    #   fsGroup: 10000
+
+
+  # Delete cluster from **ANY** cloud
+  - name: delete-cluster
+    inputs:
+      parameters:
+      # Volumes with cloned repos
+      - name: fleet_volume_name
+      - name: fleet_mount_path
+        value: "/fleet"
+
+      # Specific parameters
+      - name: cluster_kustomization_name
+      - name: project_name
+        value: "osm_admin"
+
+      # Other parameters - Recommended to keep defaults
+      - name: fleet_repo_dir
+        value: "/fleet/fleet-osm/"
+      - name: mgmt_resources_dir
+        value: "{{inputs.parameters.fleet_repo_dir}}/{{inputs.parameters.project_name}}/managed-resources/_management"
+
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+      - delete_remote_cluster
+      - "{{inputs.parameters.cluster_kustomization_name}}"
+      - "{{inputs.parameters.project_name}}"
+      - "{{inputs.parameters.fleet_repo_dir}}"
+      - "{{inputs.parameters.mgmt_resources_dir}}"
+
+      volumeMounts:
+      - name: fleet-repo-volume
+        mountPath: '{{inputs.parameters.fleet_mount_path}}'
+    volumes:
+      - name: fleet-repo-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.fleet_volume_name}}'
+    securityContext:
+      runAsUser: 10000
+    #   runAsGroup: 10000
+    #   fsGroup: 10000
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/building-blocks/debugging-wft.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/building-blocks/debugging-wft.yaml
new file mode 100644 (file)
index 0000000..5d4d164
--- /dev/null
@@ -0,0 +1,107 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: debugging-wft
+  namespace: osm-workflows
+
+spec:
+  templates:
+  # Leaf templates
+  - name: ls-command
+    inputs:
+      parameters:
+      - name: volume_name
+      - name: folder
+      - name: mount_path
+    volumes:
+    - name: shared-volume
+      persistentVolumeClaim:
+        claimName: '{{inputs.parameters.volume_name}}'
+    script:
+      image: alpine:3.20
+      volumeMounts:
+      - name: shared-volume
+        mountPath: "{{inputs.parameters.mount_path}}"
+      command: ["sh"]
+      source: |
+        ls -laR "{{inputs.parameters.folder}}"
+  - name: find-command
+    inputs:
+      parameters:
+      - name: volume_name
+      - name: folder
+      - name: mount_path
+    volumes:
+    - name: shared-volume
+      persistentVolumeClaim:
+        claimName: '{{inputs.parameters.volume_name}}'
+    script:
+      image: alpine:3.20
+      volumeMounts:
+      - name: shared-volume
+        mountPath: "{{inputs.parameters.mount_path}}"
+      command: ["sh"]
+      source: |
+        find "{{inputs.parameters.folder}}"
+  - name: echo-command
+    inputs:
+      parameters:
+      - name: message
+    script:
+      image: alpine:3.20
+      command: ["sh"]
+      source: |
+        echo "{{inputs.parameters.message}}"
+  - name: cat-command
+    inputs:
+      parameters:
+      - name: volume_name
+      - name: mount_path
+      - name: filename
+    volumes:
+    - name: shared-volume
+      persistentVolumeClaim:
+        claimName: '{{inputs.parameters.volume_name}}'
+    script:
+      image: alpine:3.20
+      volumeMounts:
+      - name: shared-volume
+        mountPath: "{{inputs.parameters.mount_path}}"
+      command: ["sh"]
+      source: |
+        cat '{{inputs.parameters.filename}}'
+  - name: touch-command
+    inputs:
+      parameters:
+      - name: volume_name
+      - name: mount_path
+      - name: filename
+    volumes:
+    - name: shared-volume
+      persistentVolumeClaim:
+        claimName: '{{inputs.parameters.volume_name}}'
+    script:
+      image: alpine:3.20
+      volumeMounts:
+      - name: shared-volume
+        mountPath: "{{inputs.parameters.mount_path}}"
+      command: ["sh"]
+      source: |
+        touch "{{inputs.parameters.filename}}"
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/building-blocks/git-wft.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/building-blocks/git-wft.yaml
new file mode 100644 (file)
index 0000000..568a2dd
--- /dev/null
@@ -0,0 +1,173 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: git-wft
+  namespace: osm-workflows
+spec:
+  templates:
+
+  - name: git-clone
+    inputs:
+      parameters:
+      - name: repo_url
+      - name: destination_folder
+      - name: git_cred_secret
+      - name: git_volume_name
+      - name: mount_path
+    volumes:
+      - name: repos-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.git_volume_name}}'
+    script:
+      image: alpine/git:2.45.1
+      env:
+      - name: GIT_USER
+        valueFrom:
+          secretKeyRef:
+            name: "{{inputs.parameters.git_cred_secret}}"
+            key: username
+      - name: GIT_PASS
+        valueFrom:
+          secretKeyRef:
+            name: "{{inputs.parameters.git_cred_secret}}"
+            key: password
+      volumeMounts:
+      - name: repos-volume
+        mountPath: '{{inputs.parameters.mount_path}}'
+      command: ["sh"]
+      source: |
+        FULL_URL="{{inputs.parameters.repo_url}}"
+        DESTINATION="{{inputs.parameters.destination_folder}}"
+        CLONE_URL=""
+
+        echo "Cloning: ${FULL_URL} . . ."
+
+        [[ -n "${DESTINATION}" ]] && mkdir -p "${DESTINATION}"
+
+        # Determine final clone URL
+        if [[ -z "${GIT_USER}" ]]; then
+          CLONE_URL="${FULL_URL}"
+        elif [[ -n "${GIT_PASS}" ]]; then
+          PROTOCOL=$(echo "${FULL_URL}" | awk -F '://' '{print $1}')
+          BASE_URL=$(echo "${FULL_URL}" | awk -F '://' '{print $2}')
+          CLONE_URL="${PROTOCOL}://${GIT_USER}@${BASE_URL}"
+        else
+          echo "ERROR: Malformed invocation."
+          echo "  FULL_URL=${FULL_URL}"
+          echo "  GIT_USER=${GIT_USER}"
+          echo "  DESTINATION=${DESTINATION}"
+          exit 1
+        fi
+
+        # Clone
+        mkdir -p /repos
+        cd /repos
+        if [[ -z "${DESTINATION}" ]]; then
+          echo -e "${GIT_PASS}\n" | git clone "${CLONE_URL}"
+        else
+          echo -e "${GIT_PASS}\n" | git clone "${CLONE_URL}" "${DESTINATION}"
+        fi
+
+  - name: git-commit-merge-push
+    inputs:
+      parameters:
+      - name: repo_folder
+      - name: git_cred_secret
+      - name: git_volume_name
+      - name: mount_path
+      - name: commit_message
+      - name: main_branch
+        value: main
+      - name: contrib_branch
+        value: osm_contrib
+      - name: dry_run
+        value: false
+    volumes:
+      - name: repos-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.git_volume_name}}'
+    script:
+      image: alpine/git:2.45.1
+      env:
+      - name: GIT_USER
+        valueFrom:
+          secretKeyRef:
+            name: "{{inputs.parameters.git_cred_secret}}"
+            key: username
+      - name: GIT_PASS
+        valueFrom:
+          secretKeyRef:
+            name: "{{inputs.parameters.git_cred_secret}}"
+            key: password
+      volumeMounts:
+      - name: repos-volume
+        mountPath: '{{inputs.parameters.mount_path}}'
+      command: ["sh"]
+      source: |
+        DESTINATION="{{inputs.parameters.repo_folder}}"
+        COMMIT_MESSAGE="{{inputs.parameters.commit_message}}"
+        CONTRIB_BRANCH="{{inputs.parameters.contrib_branch}}"
+        MAIN_BRANCH="{{inputs.parameters.main_branch}}"
+        DRY_RUN="{{inputs.parameters.dry_run}}"
+
+        # Go to the repo folder
+        cd "${DESTINATION}"
+
+        # Setup global Git user and email
+        echo "Setting up global Git user and e-mail..."
+        git config --global user.name "${GIT_USER}"
+        git config --global user.email "${GIT_USER}@${GIT_USER}.local"
+
+        # Create contrib branch
+        echo "Creating ${CONTRIB_BRANCH} branch into ${DESTINATION}..."
+        git checkout -b ${CONTRIB_BRANCH}
+
+        # Creating commit
+        git status
+        git add -A
+        git commit -m "Operation ${CONTRIB_BRANCH}: ${COMMIT_MESSAGE}"
+
+        # Pull and merge branch
+        git checkout ${MAIN_BRANCH}
+        echo "Pulling latest commits from ${MAIN_BRANCH} branch (if any)..."
+        echo -e "${GIT_PASS}\n" | git pull
+
+        echo "Merging branch ${CONTRIB_BRANCH} onto ${MAIN_BRANCH}..."
+        git merge --no-ff "${CONTRIB_BRANCH}"
+
+        if [[ "${DRY_RUN}" != "true" ]]
+        then
+          echo "Pushing..."
+          cat << "EOF" > "${HOME}/git-creds.sh"
+        #!/bin/sh
+        if echo "$1" | grep -q '^Password'; then
+          echo "${GIT_PASS}"
+        else
+          echo "${GIT_USER}"
+        fi
+        exit 0
+        EOF
+
+          chmod +x "${HOME}/git-creds.sh"
+          TTY=$(tty) GIT_USERNAME="${GIT_USER}" GIT_ASKPASS=~/git-creds.sh git push origin "${MAIN_BRANCH}"
+
+        else
+          echo "DRY RUN - NO PUSH"
+        fi
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/building-blocks/k8s-resources-wft.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/building-blocks/k8s-resources-wft.yaml
new file mode 100644 (file)
index 0000000..1c0dfeb
--- /dev/null
@@ -0,0 +1,48 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: k8s-resources-wft
+  namespace: osm-workflows
+spec:
+  templates:
+
+  - name: generate-volume
+    serviceAccountName: argo
+    inputs:
+      parameters:
+        - name: pvc-size
+    resource:
+      action: create
+      setOwnerReference: true
+      manifest: |
+        apiVersion: v1
+        kind: PersistentVolumeClaim
+        metadata:
+          generateName: pvc-osm-
+        spec:
+          accessModes: ['ReadWriteOnce']
+          resources:
+            requests:
+              storage: '{{inputs.parameters.pvc-size}}'
+    outputs:
+      parameters:
+        - name: pvc-name
+          valueFrom:
+            jsonPath: '{.metadata.name}'
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/building-blocks/ksu-management-wft.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/building-blocks/ksu-management-wft.yaml
new file mode 100644 (file)
index 0000000..67a4f87
--- /dev/null
@@ -0,0 +1,1190 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: ksu-management-wft
+  namespace: osm-workflows
+spec:
+  templates:
+
+# Create a KSU based on an OKA Package which includes a `HelmRelease`
+  - name: create-ksu-oka-hr
+    inputs:
+      parameters:
+      # References to required external resources
+      - name: fleet_volume_name
+      - name: fleet_mount_path
+        value: "/fleet"
+      - name: sw_catalogs_volume_name
+      - name: sw_catalogs_mount_path
+        value: "/sw-catalogs"
+      # Specific parameters - Base KSU generation from template
+      - name: templates_path
+      ## Should substitute environment variables in the template?
+      - name: substitute_environment
+        value: "false"
+      ## Filter for substitution of environment variables
+      - name: substitution_filter
+        value: ""
+      ## Custom environment variables (formatted as .env), to be used for template parametrization
+      - name: custom_env_vars
+        value: ""
+      ## Root folder of the cloned SW Catalogs repo - Do not touch
+      - name: cloned_sw_catalogs_folder_name
+        value: "sw-catalogs-osm"
+      # Specific parameters - Patch HelmRelease in KSU with inline values
+      - name: kustomization_name
+      - name: helmrelease_name
+      - name: inline_values
+        value: ""
+      # Specific parameters - Secret generation
+      - name: is_preexisting_secret
+        value: "false"
+      - name: target_ns
+      - name: age_public_key
+      - name: values_secret_name
+      - name: reference_secret_for_values
+      - name: reference_key_for_values
+      - name: secret_key
+        value: "values.yaml"
+      # Specific parameters - Configmap generation
+      - name: is_preexisting_cm
+        value: "false"
+      - name: values_cm_name
+      - name: cm_key
+        value: "values.yaml"
+      - name: cm_values
+        value: ""
+      # Specific parameters - KSU rendering
+      - name: ksu_name
+      - name: profile_name
+      - name: profile_type
+      - name: project_name
+        value: "osm_admin"
+      - name: sync
+        value: "true"
+      ## Root folder of the cloned Fleet repo - Do not touch
+      - name: cloned_fleet_folder_name
+        value: "fleet-osm"
+      # Debug?
+      - name: debug
+        value: "false"
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      env:
+      - name: SECRET_VALUES
+        valueFrom:
+          secretKeyRef:
+            name: "{{inputs.parameters.reference_secret_for_values}}"
+            key: "{{inputs.parameters.reference_key_for_values}}"
+          default: ""
+      - name: DEBUG
+        value: "{{inputs.parameters.debug}}"
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+        - create_hr_ksu_into_profile
+        - "{{inputs.parameters.sw_catalogs_mount_path}}/{{inputs.parameters.cloned_sw_catalogs_folder_name}}/{{inputs.parameters.templates_path}}"
+        - "{{inputs.parameters.substitute_environment}}"
+        - "{{inputs.parameters.substitution_filter}}"
+        - "{{inputs.parameters.custom_env_vars}}"
+        - "{{inputs.parameters.kustomization_name}}"
+        - "{{inputs.parameters.helmrelease_name}}"
+        - "{{inputs.parameters.inline_values}}"
+        - "{{inputs.parameters.is_preexisting_secret}}"
+        - "{{inputs.parameters.target_ns}}"
+        - "{{inputs.parameters.values_secret_name}}"
+        - "{{inputs.parameters.secret_key}}"
+        - "{{inputs.parameters.age_public_key}}"
+        - ''
+        - "{{inputs.parameters.is_preexisting_cm}}"
+        - "{{inputs.parameters.values_cm_name}}"
+        - "{{inputs.parameters.cm_key}}"
+        - "{{inputs.parameters.cm_values}}"
+        - "{{inputs.parameters.ksu_name}}"
+        - "{{inputs.parameters.profile_name}}"
+        - "{{inputs.parameters.profile_type}}"
+        - "{{inputs.parameters.project_name}}"
+        - "{{inputs.parameters.fleet_mount_path}}/{{inputs.parameters.cloned_fleet_folder_name}}"
+        - "{{inputs.parameters.sync}}"
+      volumeMounts:
+      - name: fleet-volume
+        mountPath: '{{inputs.parameters.fleet_mount_path}}'
+      - name: sw-catalogs-repo-volume
+        mountPath: '{{inputs.parameters.sw_catalogs_mount_path}}'
+    volumes:
+      - name: fleet-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.fleet_volume_name}}'
+      - name: sw-catalogs-repo-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.sw_catalogs_volume_name}}'
+    securityContext:
+      fsGroup: 10000
+    #   runAsUser: 10000
+    #   runAsGroup: 10000
+
+
+# Update a KSU based on an OKA Package which includes a `HelmRelease`
+  - name: update-ksu-oka-hr
+    inputs:
+      parameters:
+      # References to required external resources
+      - name: fleet_volume_name
+      - name: fleet_mount_path
+        value: "/fleet"
+      - name: sw_catalogs_volume_name
+      - name: sw_catalogs_mount_path
+        value: "/sw-catalogs"
+      # Specific parameters - Base KSU generation from template
+      - name: templates_path
+      ## Should substitute environment variables in the template?
+      - name: substitute_environment
+        value: "false"
+      ## Filter for substitution of environment variables
+      - name: substitution_filter
+        value: ""
+      ## Custom environment variables (formatted as .env), to be used for template parametrization
+      - name: custom_env_vars
+        value: ""
+      ## Root folder of the cloned SW Catalogs repo - Do not touch
+      - name: cloned_sw_catalogs_folder_name
+        value: "sw-catalogs-osm"
+      # Specific parameters - Patch HelmRelease in KSU with inline values
+      - name: kustomization_name
+      - name: helmrelease_name
+      - name: inline_values
+        value: ""
+      # Specific parameters - Secret generation
+      - name: is_preexisting_secret
+        value: "false"
+      - name: target_ns
+      - name: age_public_key
+      - name: values_secret_name
+      - name: reference_secret_for_values
+      - name: reference_key_for_values
+      - name: secret_key
+        value: "values.yaml"
+      # Specific parameters - Configmap generation
+      - name: is_preexisting_cm
+        value: "false"
+      - name: values_cm_name
+      - name: cm_key
+        value: "values.yaml"
+      - name: cm_values
+        value: ""
+      # Specific parameters - KSU rendering
+      - name: ksu_name
+      - name: profile_name
+      - name: profile_type
+      - name: project_name
+        value: "osm_admin"
+      ## Root folder of the cloned Fleet repo - Do not touch
+      - name: cloned_fleet_folder_name
+        value: "fleet-osm"
+      # Debug?
+      - name: debug
+        value: "false"
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      env:
+      - name: SECRET_VALUES
+        valueFrom:
+          secretKeyRef:
+            name: "{{inputs.parameters.reference_secret_for_values}}"
+            key: "{{inputs.parameters.reference_key_for_values}}"
+          default: ""
+      - name: DEBUG
+        value: "{{inputs.parameters.debug}}"
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+        - update_hr_ksu_into_profile
+        - "{{inputs.parameters.sw_catalogs_mount_path}}/{{inputs.parameters.cloned_sw_catalogs_folder_name}}/{{inputs.parameters.templates_path}}"
+        - "{{inputs.parameters.substitute_environment}}"
+        - "{{inputs.parameters.substitution_filter}}"
+        - "{{inputs.parameters.custom_env_vars}}"
+        - "{{inputs.parameters.kustomization_name}}"
+        - "{{inputs.parameters.helmrelease_name}}"
+        - "{{inputs.parameters.inline_values}}"
+        - "{{inputs.parameters.is_preexisting_secret}}"
+        - "{{inputs.parameters.target_ns}}"
+        - "{{inputs.parameters.values_secret_name}}"
+        - "{{inputs.parameters.secret_key}}"
+        - "{{inputs.parameters.age_public_key}}"
+        - ''
+        - "{{inputs.parameters.is_preexisting_cm}}"
+        - "{{inputs.parameters.values_cm_name}}"
+        - "{{inputs.parameters.cm_key}}"
+        - "{{inputs.parameters.cm_values}}"
+        - "{{inputs.parameters.ksu_name}}"
+        - "{{inputs.parameters.profile_name}}"
+        - "{{inputs.parameters.profile_type}}"
+        - "{{inputs.parameters.project_name}}"
+        - "{{inputs.parameters.fleet_mount_path}}/{{inputs.parameters.cloned_fleet_folder_name}}"
+      volumeMounts:
+      - name: fleet-volume
+        mountPath: '{{inputs.parameters.fleet_mount_path}}'
+      - name: sw-catalogs-repo-volume
+        mountPath: '{{inputs.parameters.sw_catalogs_mount_path}}'
+    volumes:
+      - name: fleet-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.fleet_volume_name}}'
+      - name: sw-catalogs-repo-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.sw_catalogs_volume_name}}'
+    securityContext:
+      fsGroup: 10000
+    #   runAsUser: 10000
+    #   runAsGroup: 10000
+
+
+# Create a "generated" KSU from `HelmRelease` and Source Repo definitions
+  - name: create-ksu-generated-hr
+    inputs:
+      parameters:
+      # References to required external resources
+      - name: fleet_volume_name
+      - name: fleet_mount_path
+        value: "/fleet"
+      # HelmRelease generation
+      - name: helmrelease_name
+      - name: chart_name
+      - name: chart_version
+      - name: target_ns
+      - name: create_ns
+      # Repo source generation
+      - name: is_preexisting_repo
+        value: "false"
+      - name: helmrepo_name
+      - name: helmrepo_url
+      - name: helmrepo_ns
+        valueFrom:
+          expression: "{{input.parameters.target_ns}}"
+      - name: helmrepo_secret_ref
+      # HelmRelease inline values (if any)
+      - name: inline_values
+        value: ""
+      # Secret reference and generation (if required)
+      - name: is_preexisting_secret
+        value: "false"
+      - name: values_secret_name
+      - name: secret_key
+        value: "values.yaml"
+      - name: age_public_key
+      ## Secret values will be obtained from the
+      ## secret named after the input parameter `reference_secret_for_values`,
+      ## and from the key named after the input parameter `reference_key_for_values`
+      - name: reference_secret_for_values
+      - name: reference_key_for_values
+      # ConfigMap reference and generation (if required)
+      - name: is_preexisting_cm
+        value: "false"
+      - name: values_cm_name
+      - name: cm_key
+        value: "values.yaml"
+      - name: cm_values
+        value: ""
+      # KSU rendering
+      - name: ksu_name
+      - name: profile_name
+      - name: profile_type
+      - name: project_name
+        value: "osm_admin"
+      # By default, it will not syncronize, so that we can easily accumulate more than
+      # one Helm chart into the same KSU if desired
+      - name: sync
+        value: "false"
+      ## Root folder of the cloned Fleet repo - Do not touch
+      ### `FLEET_REPO_DIR` is the result of:
+      ### "{{inputs.parameters.fleet_mount_path}}/{{inputs.parameters.cloned_fleet_folder_name}}"
+      - name: cloned_fleet_folder_name
+        value: "fleet-osm"
+      # Debug?
+      - name: debug
+        value: "false"
+
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      env:
+      - name: SECRET_VALUES
+        valueFrom:
+          secretKeyRef:
+            name: "{{inputs.parameters.reference_secret_for_values}}"
+            key: "{{inputs.parameters.reference_key_for_values}}"
+          default: ""
+      - name: DEBUG
+        value: "{{inputs.parameters.debug}}"
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+      - create_generated_ksu_from_helm_into_profile
+      - "{{inputs.parameters.helmrelease_name}}"
+      - "{{inputs.parameters.chart_name}}"
+      - "{{inputs.parameters.chart_version}}"
+      - "{{inputs.parameters.target_ns}}"
+      - "{{inputs.parameters.create_ns}}"
+      - "{{inputs.parameters.is_preexisting_repo}}"
+      - "{{inputs.parameters.helmrepo_name}}"
+      - "{{inputs.parameters.helmrepo_url}}"
+      - "{{inputs.parameters.helmrepo_ns}}"
+      - "{{inputs.parameters.helmrepo_secret_ref}}"
+      - "{{inputs.parameters.inline_values}}"
+      - "{{inputs.parameters.is_preexisting_secret}}"
+      - "{{inputs.parameters.values_secret_name}}"
+      - "{{inputs.parameters.secret_key}}"
+      - "{{inputs.parameters.age_public_key}}"
+      - ''
+      - "{{inputs.parameters.is_preexisting_cm}}"
+      - "{{inputs.parameters.values_cm_name}}"
+      - "{{inputs.parameters.cm_key}}"
+      - "{{inputs.parameters.cm_values}}"
+      - "{{inputs.parameters.ksu_name}}"
+      - "{{inputs.parameters.profile_name}}"
+      - "{{inputs.parameters.profile_type}}"
+      - "{{inputs.parameters.project_name}}"
+      - "{{inputs.parameters.fleet_mount_path}}/{{inputs.parameters.cloned_fleet_folder_name}}"
+      - "{{inputs.parameters.sync}}"
+      volumeMounts:
+      - name: fleet-volume
+        mountPath: '{{inputs.parameters.fleet_mount_path}}'
+    volumes:
+      - name: fleet-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.fleet_volume_name}}'
+    securityContext:
+      fsGroup: 10000
+    #   runAsUser: 10000
+    #   runAsGroup: 10000
+
+
+# Update a "generated" KSU from `HelmRelease` and Source Repo definitions
+  - name: update-ksu-generated-hr
+    inputs:
+      parameters:
+      # References to required external resources
+      - name: fleet_volume_name
+      - name: fleet_mount_path
+        value: "/fleet"
+      # HelmRelease generation
+      - name: helmrelease_name
+      - name: chart_name
+      - name: chart_version
+      - name: target_ns
+      - name: create_ns
+      # Repo source generation
+      - name: is_preexisting_repo
+        value: "false"
+      - name: helmrepo_name
+      - name: helmrepo_url
+      - name: helmrepo_ns
+        valueFrom:
+          expression: "{{input.parameters.target_ns}}"
+      - name: helmrepo_secret_ref
+      # HelmRelease inline values (if any)
+      - name: inline_values
+        value: ""
+      # Secret reference and generation (if required)
+      - name: is_preexisting_secret
+        value: "false"
+      - name: values_secret_name
+      - name: secret_key
+        value: "values.yaml"
+      - name: age_public_key
+      ## Secret values will be obtained from the
+      ## secret named after the input parameter `reference_secret_for_values`,
+      ## and from the key named after the input parameter `reference_key_for_values`
+      - name: reference_secret_for_values
+      - name: reference_key_for_values
+      # ConfigMap reference and generation (if required)
+      - name: is_preexisting_cm
+        value: "false"
+      - name: values_cm_name
+      - name: cm_key
+        value: "values.yaml"
+      - name: cm_values
+        value: ""
+      # KSU rendering
+      - name: ksu_name
+      - name: profile_name
+      - name: profile_type
+      - name: project_name
+        value: "osm_admin"
+      ## Root folder of the cloned Fleet repo - Do not touch
+      ### `FLEET_REPO_DIR` is the result of:
+      ### "{{inputs.parameters.fleet_mount_path}}/{{inputs.parameters.cloned_fleet_folder_name}}"
+      - name: cloned_fleet_folder_name
+        value: "fleet-osm"
+      # Debug?
+      - name: debug
+        value: "false"
+
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      env:
+      - name: SECRET_VALUES
+        valueFrom:
+          secretKeyRef:
+            name: "{{inputs.parameters.reference_secret_for_values}}"
+            key: "{{inputs.parameters.reference_key_for_values}}"
+          default: ""
+      - name: DEBUG
+        value: "{{inputs.parameters.debug}}"
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+      - update_generated_ksu_from_helm_into_profile
+      - "{{inputs.parameters.helmrelease_name}}"
+      - "{{inputs.parameters.chart_name}}"
+      - "{{inputs.parameters.chart_version}}"
+      - "{{inputs.parameters.target_ns}}"
+      - "{{inputs.parameters.create_ns}}"
+      - "{{inputs.parameters.is_preexisting_repo}}"
+      - "{{inputs.parameters.helmrepo_name}}"
+      - "{{inputs.parameters.helmrepo_url}}"
+      - "{{inputs.parameters.helmrepo_ns}}"
+      - "{{inputs.parameters.helmrepo_secret_ref}}"
+      - "{{inputs.parameters.inline_values}}"
+      - "{{inputs.parameters.is_preexisting_secret}}"
+      - "{{inputs.parameters.values_secret_name}}"
+      - "{{inputs.parameters.secret_key}}"
+      - "{{inputs.parameters.age_public_key}}"
+      - ''
+      - "{{inputs.parameters.is_preexisting_cm}}"
+      - "{{inputs.parameters.values_cm_name}}"
+      - "{{inputs.parameters.cm_key}}"
+      - "{{inputs.parameters.cm_values}}"
+      - "{{inputs.parameters.ksu_name}}"
+      - "{{inputs.parameters.profile_name}}"
+      - "{{inputs.parameters.profile_type}}"
+      - "{{inputs.parameters.project_name}}"
+      - "{{inputs.parameters.fleet_mount_path}}/{{inputs.parameters.cloned_fleet_folder_name}}"
+      volumeMounts:
+      - name: fleet-volume
+        mountPath: '{{inputs.parameters.fleet_mount_path}}'
+    volumes:
+      - name: fleet-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.fleet_volume_name}}'
+    securityContext:
+      fsGroup: 10000
+    #   runAsUser: 10000
+    #   runAsGroup: 10000
+
+
+# Delete a KSU from a profile
+  - name: delete-ksu
+    inputs:
+      parameters:
+      # References to required external resources
+      - name: fleet_volume_name
+      - name: fleet_mount_path
+        value: "/fleet"
+      - name: sw_catalogs_volume_name
+      - name: sw_catalogs_mount_path
+        value: "/sw-catalogs"
+      # Specific parameters - KSU id
+      - name: ksu_name
+      - name: profile_name
+      - name: profile_type
+      - name: project_name
+        value: "osm_admin"
+      # Other parameters - Do not touch
+      - name: cloned_fleet_folder_name
+        value: "fleet-osm"
+      - name: cloned_sw_catalogs_folder_name
+        value: "sw-catalogs-osm"
+      # Debug?
+      - name: debug
+        value: "false"
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      env:
+      - name: DEBUG
+        value: "{{inputs.parameters.debug}}"
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+        - delete_ksu_from_profile
+        - "{{inputs.parameters.ksu_name}}"
+        - "{{inputs.parameters.profile_name}}"
+        - "{{inputs.parameters.profile_type}}"
+        - "{{inputs.parameters.project_name}}"
+        - "{{inputs.parameters.fleet_mount_path}}/{{inputs.parameters.cloned_fleet_folder_name}}"
+      volumeMounts:
+      - name: fleet-volume
+        mountPath: '{{inputs.parameters.fleet_mount_path}}'
+      - name: sw-catalogs-repo-volume
+        mountPath: '{{inputs.parameters.sw_catalogs_mount_path}}'
+    volumes:
+      - name: fleet-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.fleet_volume_name}}'
+      - name: sw-catalogs-repo-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.sw_catalogs_volume_name}}'
+    securityContext:
+      fsGroup: 10000
+    #   runAsUser: 10000
+    #   runAsGroup: 10000
+
+
+# Clone a KSU from a profile to another
+  - name: clone-ksu
+    inputs:
+      parameters:
+      # References to required external resources
+      - name: fleet_volume_name
+      - name: fleet_mount_path
+        value: "/fleet"
+      # Specific parameters - Source and destination KSU
+      ## Source KSU:
+      - name: source_ksu_name
+      - name: source_profile_name
+      - name: source_profile_type
+      - name: source_project_name
+        value: "osm_admin"
+      ## Destination KSU:
+      ## - If any of the destination parameters are not specified, it will assume
+      ##   they are the same as in source.
+      ## - It will reject if all are empty or equal to source, to avoid cloning a KSU over itself
+      - name: destination_ksu_name
+        value: ""
+      - name: destination_profile_name
+        value: ""
+      - name: destination_profile_type
+        value: ""
+      - name: destination_project_name
+        value: ""
+      # Other parameters - Do not touch
+      - name: cloned_fleet_folder_name
+        value: "fleet-osm"
+      # Debug?
+      - name: debug
+        value: "false"
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      env:
+      - name: DEBUG
+        value: "{{inputs.parameters.debug}}"
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+      - clone_ksu
+      - "{{inputs.parameters.source_ksu_name}}"
+      - "{{inputs.parameters.source_profile_name}}"
+      - "{{inputs.parameters.source_profile_type}}"
+      - "{{inputs.parameters.source_project_name}}"
+      - "{{inputs.parameters.destination_ksu_name}}"
+      - "{{inputs.parameters.destination_profile_name}}"
+      - "{{inputs.parameters.destination_profile_type}}"
+      - "{{inputs.parameters.destination_project_name}}"
+      - "{{inputs.parameters.fleet_mount_path}}/{{inputs.parameters.cloned_fleet_folder_name}}"
+      volumeMounts:
+      - name: fleet-volume
+        mountPath: '{{inputs.parameters.fleet_mount_path}}'
+    volumes:
+      - name: fleet-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.fleet_volume_name}}'
+    securityContext:
+      fsGroup: 10000
+    #   runAsUser: 10000
+    #   runAsGroup: 10000
+
+
+  # Read template folder from OKA Package and convert to `ResourceList`
+  # It can work as KRM generator function, since it accepts an optional input `ResourceList`
+  - name: folder2list
+    inputs:
+      parameters:
+      # References to required external resources
+      - name: sw_catalogs_volume_name
+      - name: temp_volume_name
+      # Filename for input stream
+      - name: input_stream_file
+        value: "/dev/null"
+      # Specific parameters
+      ## Relative path from `sw_catalogs_mount_path`
+      - name: templates_path
+      ## Should substitute environment variables in the template?
+      - name: substitute_environment
+        value: "false"
+      ## Filter for substitution of environment variables
+      - name: substitution_filter
+        value: ""
+      ## Custom environment variables (formatted as .env), to be used for template parametrization
+      - name: custom_env_vars
+        value: ""
+        # value: |
+        #     KEY1=value1
+        #     KEY2=value2
+      # Debug mode?
+      - name: debug
+        value: "false"
+      # Other parameters - Do not touch
+      - name: sw_catalogs_mount_path
+        value: "/sw-catalogs"
+      - name: cloned_sw_catalogs_folder_name
+        value: "sw-catalogs-osm"
+      - name: rand_str
+        value: "{{=sprig.randAlphaNum(9)}}"
+    outputs:
+      parameters:
+        - name: output_file
+          value: "/results/resourcelist.{{inputs.parameters.rand_str}}.yaml"
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      env:
+      - name: INFILE
+        value: "{{inputs.parameters.input_stream_file}}"
+      - name: OUTFILE
+        value: "/results/resourcelist.{{inputs.parameters.rand_str}}.yaml"
+      - name: CUSTOM_ENV
+        value: "{{inputs.parameters.custom_env_vars}}"
+      - name: DEBUG
+        value: "{{inputs.parameters.debug}}"
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+      - folder2list_generator
+      - "{{inputs.parameters.sw_catalogs_mount_path}}/{{inputs.parameters.cloned_sw_catalogs_folder_name}}/{{inputs.parameters.templates_path}}"
+      - "{{inputs.parameters.substitute_environment}}"
+      - "{{inputs.parameters.substitution_filter}}"
+      volumeMounts:
+      - name: temp-volume
+        mountPath: "/results"
+      - name: sw-catalogs-repo-volume
+        mountPath: '{{inputs.parameters.sw_catalogs_mount_path}}'
+    volumes:
+      - name: temp-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.temp_volume_name}}'
+      - name: sw-catalogs-repo-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.sw_catalogs_volume_name}}'
+    securityContext:
+      fsGroup: 10000
+    #   runAsUser: 10000
+    #   runAsGroup: 10000
+
+
+  # Transform `ResourceList`'s main Kustomization to patch `HelmRelease` to use
+  # inline values
+  - name: transform-ks-add-values-to-hr
+    inputs:
+      parameters:
+      # References to required external resources
+      - name: temp_volume_name
+      # Specific parameters - Generator
+      ## Filename for input stream
+      - name: input_stream_file
+      # Specific parameters
+      ## Patched objects
+      - name: kustomization_name
+      - name: helmrelease_name
+      ## Input values for the Helm Chart
+      - name: inline_values
+      # Debug mode?
+      - name: debug
+        value: "false"
+      # Other parameters - Do not touch
+      - name: rand_str
+        value: "{{=sprig.randAlphaNum(9)}}"
+    outputs:
+      parameters:
+        - name: output_file
+          value: "/results/resourcelist.{{inputs.parameters.rand_str}}.yaml"
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      env:
+      - name: INFILE
+        value: "{{inputs.parameters.input_stream_file}}"
+      - name: OUTFILE
+        value: "/results/resourcelist.{{inputs.parameters.rand_str}}.yaml"
+      - name: DEBUG
+        value: "{{inputs.parameters.debug}}"
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+      - add_values_to_helmrelease_via_ks
+      - "{{inputs.parameters.kustomization_name}}"
+      - "{{inputs.parameters.helmrelease_name}}"
+      - "{{inputs.parameters.inline_values}}"
+      volumeMounts:
+      - name: temp-volume
+        mountPath: "/results"
+    volumes:
+    - name: temp-volume
+      persistentVolumeClaim:
+        claimName: '{{inputs.parameters.temp_volume_name}}'
+    securityContext:
+      fsGroup: 10000
+      # runAsUser: 10000
+      # runAsGroup: 10000
+
+
+  # Transform `ResourceList`'s main Kustomization to patch `HelmRelease` to use
+  # values from a Secret, a ConfigMap or both.
+  - name: transform-ks-add-referenced-values-to-hr
+    inputs:
+      parameters:
+      # References to required external resources
+      - name: temp_volume_name
+      # Specific parameters - Generator
+      ## Filename for input stream
+      - name: input_stream_file
+      # Specific parameters
+      - name: kustomization_name
+      - name: helmrelease_name
+      ## Source for values (Secret, ConfigMap or both)
+      - name: values_secret_name
+        value: ""
+      - name: values_cm_name
+        value: ""
+      # Debug mode?
+      - name: debug
+        value: "false"
+      # Other parameters - Do not touch
+      - name: rand_str
+        value: "{{=sprig.randAlphaNum(9)}}"
+    outputs:
+      parameters:
+        - name: output_file
+          value: "/results/resourcelist.{{inputs.parameters.rand_str}}.yaml"
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      env:
+      - name: INFILE
+        value: "{{inputs.parameters.input_stream_file}}"
+      - name: OUTFILE
+        value: "/results/resourcelist.{{inputs.parameters.rand_str}}.yaml"
+      - name: DEBUG
+        value: "{{inputs.parameters.debug}}"
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+      - add_ref_values_to_hr_via_ks
+      - "{{inputs.parameters.kustomization_name}}"
+      - "{{inputs.parameters.helmrelease_name}}"
+      - "{{inputs.parameters.values_secret_name}}"
+      - "{{inputs.parameters.values_cm_name}}"
+      volumeMounts:
+      - name: temp-volume
+        mountPath: "/results"
+    volumes:
+    - name: temp-volume
+      persistentVolumeClaim:
+        claimName: '{{inputs.parameters.temp_volume_name}}'
+    securityContext:
+      fsGroup: 10000
+      # runAsUser: 10000
+      # runAsGroup: 10000
+
+
+  # KRM function to render a ResourceList with a KSU into a target profile
+  - name: render-ksu-into-profile
+    inputs:
+      parameters:
+      # References to required external resources
+      - name: fleet_volume_name
+      - name: temp_volume_name
+      # Filename for input stream
+      - name: input_stream_file
+      # Specific parameters
+      - name: ksu_name
+      - name: profile_name
+      - name: profile_type
+      - name: project_name
+        value: "osm_admin"
+      ## Whether the target KSU folder will be fully re-created on render
+      - name: sync
+        value: "false"
+      # Debug mode?
+      - name: debug
+        value: "false"
+      # Other parameters - Do not touch
+      - name: fleet_mount_path
+        value: "/fleet"
+      - name: fleet_repo_dir
+        value: "/fleet/fleet-osm/"
+      - name: rand_str
+        value: "{{=sprig.randAlphaNum(9)}}"
+    outputs:
+      parameters:
+        - name: output_file
+          value: "/results/resourcelist.{{inputs.parameters.rand_str}}.yaml"
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      env:
+      - name: INFILE
+        value: "{{inputs.parameters.input_stream_file}}"
+      - name: OUTFILE
+        value: "/results/resourcelist.{{inputs.parameters.rand_str}}.yaml"
+      - name: DEBUG
+        value: "{{inputs.parameters.debug}}"
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+      - render_ksu_into_profile
+      - "{{inputs.parameters.ksu_name}}"
+      - "{{inputs.parameters.profile_name}}"
+      - "{{inputs.parameters.profile_type}}"
+      - "{{inputs.parameters.project_name}}"
+      - "{{inputs.parameters.fleet_repo_dir}}"
+      - "{{inputs.parameters.sync}}"
+      volumeMounts:
+      - name: temp-volume
+        mountPath: "/results"
+      - name: fleet-volume
+        mountPath: '{{inputs.parameters.fleet_mount_path}}'
+    volumes:
+      - name: temp-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.temp_volume_name}}'
+      - name: fleet-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.fleet_volume_name}}'
+    securityContext:
+      fsGroup: 10000
+    #   runAsUser: 10000
+    #   runAsGroup: 10000
+
+
+  # KRM generator to create Secrets suitable to pass values to `HelmReleases`
+  - name: generator-secret-hr-values
+    inputs:
+      parameters:
+      # References to required external resources
+      - name: temp_volume_name
+      # Specific parameters - Generator
+      ## Filename for input stream
+      - name: input_stream_file
+        value: "/dev/null"
+      ## Name of final manifest filename into generated `ResourceList` object
+      - name: final_manifest_filename
+      # Specific parameters - Secret
+      - name: age_public_key
+      - name: values_secret_name
+      - name: target_ns
+      - name: reference_secret_for_values
+      - name: reference_key_for_values
+      - name: secret_key
+        value: "values.yaml"
+      # Debug mode?
+      - name: debug
+        value: "false"
+    outputs:
+      parameters:
+        - name: output_file
+          valueFrom:
+            parameter: '{{steps.generate-resourcelist.outputs.parameters.output_file}}'
+    steps:
+    - - name: build-manifest
+        templateRef:
+          name: ksu-management-wft
+          template: manifest-secret-hr-values
+        arguments:
+          parameters:
+          # References to required external resources
+          - name: temp_volume_name
+            value: "{{inputs.parameters.temp_volume_name}}"
+          # Specific parameters
+          - name: age_public_key
+            value: "{{inputs.parameters.age_public_key}}"
+          - name: values_secret_name
+            value: "{{inputs.parameters.values_secret_name}}"
+          - name: target_ns
+            value: "{{inputs.parameters.target_ns}}"
+          - name: reference_secret_for_values
+            value: "{{inputs.parameters.reference_secret_for_values}}"
+          - name: reference_key_for_values
+            value: "{{inputs.parameters.reference_key_for_values}}"
+          - name: secret_key
+            value: "{{inputs.parameters.secret_key}}"
+          # Debug?
+          - name: debug
+            value: "{{inputs.parameters.debug}}"
+    - - name: generate-resourcelist
+        templateRef:
+          name: ksu-management-wft
+          template: make-generator
+        arguments:
+          parameters:
+          # References to required external resources
+          - name: temp_volume_name
+            value: "{{inputs.parameters.temp_volume_name}}"
+          # Filename for input stream
+          - name: input_stream_file
+            value: "{{inputs.parameters.input_stream_file}}"
+          # File with raw manifest
+          - name: input_manifest_file
+            value: '{{steps.build-manifest.outputs.parameters.output_file}}'
+          # Name of final manifest filename into generated `ResourceList` object
+          - name: final_manifest_filename
+            value: "{{inputs.parameters.final_manifest_filename}}"
+          # Debug?
+          - name: debug
+            value: "{{inputs.parameters.debug}}"
+
+
+  # KRM generator to create ConfigMaps suitable to pass values to `HelmReleases`
+  - name: generator-cm-hr-values
+    inputs:
+      parameters:
+      # References to required external resources
+      - name: temp_volume_name
+      # Specific parameters - Generator
+      ## Filename for input stream
+      - name: input_stream_file
+        value: "/dev/null"
+      ## Name of final manifest filename into generated `ResourceList` object
+      - name: final_manifest_filename
+      # Specific parameters - ConfigMap
+      - name: values_cm_name
+      - name: target_ns
+      - name: cm_key
+        value: "values.yaml"
+      - name: cm_values
+      # Debug mode?
+      - name: debug
+        value: "false"
+    outputs:
+      parameters:
+        - name: output_file
+          valueFrom:
+            parameter: '{{steps.generate-resourcelist.outputs.parameters.output_file}}'
+    steps:
+    - - name: build-manifest
+        templateRef:
+          name: ksu-management-wft
+          template: manifest-cm-hr-values
+        arguments:
+          parameters:
+          # References to required external resources
+          - name: temp_volume_name
+            value: "{{inputs.parameters.temp_volume_name}}"
+          # Specific parameters
+          - name: values_cm_name
+            value: "{{inputs.parameters.values_cm_name}}"
+          - name: target_ns
+            value: "{{inputs.parameters.target_ns}}"
+          - name: cm_key
+            value: "{{inputs.parameters.cm_key}}"
+          - name: cm_values
+            value: "{{inputs.parameters.cm_values}}"
+          # Debug?
+          - name: debug
+            value: "{{inputs.parameters.debug}}"
+    - - name: generate-resourcelist
+        templateRef:
+          name: ksu-management-wft
+          template: make-generator
+        arguments:
+          parameters:
+          # References to required external resources
+          - name: temp_volume_name
+            value: "{{inputs.parameters.temp_volume_name}}"
+          # Filename for input stream
+          - name: input_stream_file
+            value: "{{inputs.parameters.input_stream_file}}"
+          # File with raw manifest
+          - name: input_manifest_file
+            value: '{{steps.build-manifest.outputs.parameters.output_file}}'
+          # Name of final manifest filename into generated `ResourceList` object
+          - name: final_manifest_filename
+            value: "{{inputs.parameters.final_manifest_filename}}"
+          # Debug?
+          - name: debug
+            value: "{{inputs.parameters.debug}}"
+
+
+  # Converts a manifest to a KRM generator
+  - name: make-generator
+    inputs:
+      parameters:
+      # References to required external resources
+      - name: temp_volume_name
+      # Filename for input stream
+      - name: input_stream_file
+        value: "/dev/null"
+      # File with raw manifest
+      - name: input_manifest_file
+      # Name of final manifest filename into generated `ResourceList` object
+      - name: final_manifest_filename
+      # Debug mode?
+      - name: debug
+        value: "false"
+      # Other parameters - Do not touch
+      - name: rand_str
+        value: "{{=sprig.randAlphaNum(9)}}"
+    outputs:
+      parameters:
+        - name: output_file
+          value: "/results/resourcelist.{{inputs.parameters.rand_str}}.yaml"
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      env:
+      - name: INFILE
+        value: "{{inputs.parameters.input_stream_file}}"
+      - name: OUTFILE
+        value: "/results/resourcelist.{{inputs.parameters.rand_str}}.yaml"
+      - name: DEBUG
+        value: "{{inputs.parameters.debug}}"
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+      - make_generator
+      - "{{inputs.parameters.final_manifest_filename}}"
+      - cat
+      - "{{inputs.parameters.input_manifest_file}}"
+      volumeMounts:
+      - name: temp-volume
+        mountPath: "/results"
+    volumes:
+    - name: temp-volume
+      persistentVolumeClaim:
+        claimName: '{{inputs.parameters.temp_volume_name}}'
+    securityContext:
+      fsGroup: 10000
+      # runAsUser: 10000
+      # runAsGroup: 10000
+
+
+  # Produces a secret manifest and encrypts it with SOPS
+  - name: manifest-secret-hr-values
+    inputs:
+      parameters:
+      # References to required external resources
+      - name: temp_volume_name
+      # Public age key to encrypt secret
+      - name: age_public_key
+      # Name of the secret to be created
+      - name: values_secret_name
+      # Namespace for the secret
+      - name: target_ns
+      # Input secret that contains the values to embed into the new secret
+      - name: reference_secret_for_values
+      - name: reference_key_for_values
+        value: "values.yaml"
+      # Key in the new secret where the values will be inserted
+      - name: secret_key
+        value: "values.yaml"
+      # Debug mode?
+      - name: debug
+        value: "false"
+      # Other parameters - Do not touch
+      - name: rand_str
+        value: "{{=sprig.randAlphaNum(9)}}"
+    outputs:
+      parameters:
+        - name: output_file
+          value: "/results/manifest.{{inputs.parameters.rand_str}}.yaml"
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      env:
+      - name: INSTREAM
+        valueFrom:
+          secretKeyRef:
+            name: "{{inputs.parameters.reference_secret_for_values}}"
+            key: "{{inputs.parameters.reference_key_for_values}}"
+      - name: OUTFILE
+        value: "/results/manifest.{{inputs.parameters.rand_str}}.yaml"
+      - name: DEBUG
+        value: "{{inputs.parameters.debug}}"
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+        - kubectl_encrypt
+        - "{{inputs.parameters.age_public_key}}"
+        - create
+        - secret
+        - generic
+        - "{{inputs.parameters.values_secret_name}}"
+        - --namespace={{inputs.parameters.target_ns}}
+        - --from-file={{inputs.parameters.secret_key}}=/dev/stdin
+        - -o=yaml
+        - --dry-run=client
+      volumeMounts:
+      - name: temp-volume
+        mountPath: "/results"
+    volumes:
+    - name: temp-volume
+      persistentVolumeClaim:
+        claimName: '{{inputs.parameters.temp_volume_name}}'
+    securityContext:
+      fsGroup: 10000
+    # runAsUser: 10000
+    # runAsGroup: 10000
+
+
+  # Produces a ConfigMap manifest
+  - name: manifest-cm-hr-values
+    inputs:
+      parameters:
+      # References to required external resources
+      - name: temp_volume_name
+      # Specific parameters
+      - name: values_cm_name
+      - name: target_ns
+      - name: cm_key
+        value: "values.yaml"
+      - name: cm_values
+      # Debug mode?
+      - name: debug
+        value: "false"
+      # Other parameters - Do not touch
+      - name: rand_str
+        value: "{{=sprig.randAlphaNum(9)}}"
+    outputs:
+      parameters:
+        - name: output_file
+          value: "/results/manifest.{{inputs.parameters.rand_str}}.yaml"
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      env:
+      - name: INSTREAM
+        value: "{{inputs.parameters.cm_values}}"
+      - name: OUTFILE
+        value: "/results/manifest.{{inputs.parameters.rand_str}}.yaml"
+      - name: DEBUG
+        value: "{{inputs.parameters.debug}}"
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+        - kubectl
+        - create
+        - configmap
+        - "{{inputs.parameters.values_cm_name}}"
+        - --namespace={{inputs.parameters.target_ns}}
+        - --from-file={{inputs.parameters.cm_key}}=/dev/stdin
+        - -o=yaml
+        - --dry-run=client
+      volumeMounts:
+      - name: temp-volume
+        mountPath: "/results"
+    volumes:
+    - name: temp-volume
+      persistentVolumeClaim:
+        claimName: '{{inputs.parameters.temp_volume_name}}'
+    securityContext:
+      fsGroup: 10000
+    # runAsUser: 10000
+    # runAsGroup: 10000
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/building-blocks/oka-management-wft.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/building-blocks/oka-management-wft.yaml
new file mode 100644 (file)
index 0000000..4a0e841
--- /dev/null
@@ -0,0 +1,192 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: oka-management-wft
+  namespace: osm-workflows
+spec:
+  templates:
+
+# Create an OKA based on an OKA Package pre-loaded into a pvc
+  - name: create-oka
+    inputs:
+      parameters:
+      # References to required external resources
+      - name: sw_catalogs_volume_name
+      - name: temp_volume_name
+      # Specific parameters - OKA
+      - name: oka_name
+      ## Choose among `infra-controllers`, `infra-configs`, `cloud-resources`, `apps`:
+      - name: oka_type
+      - name: project_name
+        value: "osm_admin"
+      - name: tarball_file
+        value: "true"
+      # Debug?
+      - name: debug
+        value: "false"
+      # Other parameters - Do not touch
+      - name: sw_catalogs_mount_path
+        value: "/sw-catalogs"
+      - name: cloned_sw_catalogs_folder_name
+        value: "sw-catalogs-osm"
+      - name: temp_volume_mount_path
+        value: "/oka"
+      - name: oka_location
+        value: "/oka"
+
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      env:
+      - name: DEBUG
+        value: "{{inputs.parameters.debug}}"
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+      - create_oka
+      - "{{inputs.parameters.oka_name}}"
+      - "{{inputs.parameters.oka_type}}"
+      - "{{inputs.parameters.project_name}}"
+      - "{{inputs.parameters.sw_catalogs_mount_path}}/{{inputs.parameters.cloned_sw_catalogs_folder_name}}"
+      - "{{inputs.parameters.oka_location}}"
+      - "{{inputs.parameters.tarball_file}}"
+      volumeMounts:
+      - name: sw-catalogs-repo-volume
+        mountPath: '{{inputs.parameters.sw_catalogs_mount_path}}'
+      - name: temp-volume
+        mountPath: '{{inputs.parameters.temp_volume_mount_path}}'
+    volumes:
+      - name: sw-catalogs-repo-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.sw_catalogs_volume_name}}'
+      - name: temp-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.temp_volume_name}}'
+    securityContext:
+      fsGroup: 10000
+    #   runAsUser: 10000
+    #   runAsGroup: 10000
+
+
+# Update an OKA based on an OKA Package pre-loaded into a pvc
+  - name: update-oka
+    inputs:
+      parameters:
+      # References to required external resources
+      - name: sw_catalogs_volume_name
+      - name: temp_volume_name
+      # Specific parameters - OKA
+      - name: oka_name
+      ## Choose among `infra-controllers`, `infra-configs`, `cloud-resources`, `apps`:
+      - name: oka_type
+      - name: project_name
+        value: "osm_admin"
+      - name: tarball_file
+        value: "true"
+      # Debug?
+      - name: debug
+        value: "false"
+      # Other parameters - Do not touch
+      - name: sw_catalogs_mount_path
+        value: "/sw-catalogs"
+      - name: cloned_sw_catalogs_folder_name
+        value: "sw-catalogs-osm"
+      - name: temp_volume_mount_path
+        value: "/oka"
+      - name: oka_location
+        value: "/oka"
+
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      env:
+      - name: DEBUG
+        value: "{{inputs.parameters.debug}}"
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+      - update_oka
+      - "{{inputs.parameters.oka_name}}"
+      - "{{inputs.parameters.oka_type}}"
+      - "{{inputs.parameters.project_name}}"
+      - "{{inputs.parameters.sw_catalogs_mount_path}}/{{inputs.parameters.cloned_sw_catalogs_folder_name}}"
+      - "{{inputs.parameters.oka_location}}"
+      - "{{inputs.parameters.tarball_file}}"
+      volumeMounts:
+      - name: sw-catalogs-repo-volume
+        mountPath: '{{inputs.parameters.sw_catalogs_mount_path}}'
+      - name: temp-volume
+        mountPath: '{{inputs.parameters.temp_volume_mount_path}}'
+    volumes:
+      - name: sw-catalogs-repo-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.sw_catalogs_volume_name}}'
+      - name: temp-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.temp_volume_name}}'
+    securityContext:
+      fsGroup: 10000
+    #   runAsUser: 10000
+    #   runAsGroup: 10000
+
+
+# Delete an OKA
+  - name: delete-oka
+    inputs:
+      parameters:
+      # References to required external resources
+      - name: sw_catalogs_volume_name
+      # Specific parameters - OKA
+      - name: oka_name
+      ## Choose among `infra-controllers`, `infra-configs`, `cloud-resources`, `apps`:
+      - name: oka_type
+      - name: project_name
+        value: "osm_admin"
+      # Debug?
+      - name: debug
+        value: "false"
+      # Other parameters - Do not touch
+      - name: sw_catalogs_mount_path
+        value: "/sw-catalogs"
+      - name: cloned_sw_catalogs_folder_name
+        value: "sw-catalogs-osm"
+
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      env:
+      - name: DEBUG
+        value: "{{inputs.parameters.debug}}"
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+      - delete_oka
+      - "{{inputs.parameters.oka_name}}"
+      - "{{inputs.parameters.oka_type}}"
+      - "{{inputs.parameters.project_name}}"
+      - "{{inputs.parameters.sw_catalogs_mount_path}}/{{inputs.parameters.cloned_sw_catalogs_folder_name}}"
+      volumeMounts:
+      - name: sw-catalogs-repo-volume
+        mountPath: '{{inputs.parameters.sw_catalogs_mount_path}}'
+    volumes:
+      - name: sw-catalogs-repo-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.sw_catalogs_volume_name}}'
+    securityContext:
+      fsGroup: 10000
+    #   runAsUser: 10000
+    #   runAsGroup: 10000
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/building-blocks/profile-management-wft.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/building-blocks/profile-management-wft.yaml
new file mode 100644 (file)
index 0000000..64917be
--- /dev/null
@@ -0,0 +1,195 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: profile-management-wft
+  namespace: osm-workflows
+spec:
+  templates:
+
+  # Create a profile
+  - name: create-profile
+    inputs:
+      parameters:
+      # Volumes with cloned repos
+      - name: fleet_volume_name
+      - name: fleet_mount_path
+        value: "/fleet"
+
+      # Specific parameters
+      - name: profile_name
+      - name: profile_type
+      - name: project_name
+        value: "osm_admin"
+      - name: fleet_repo_url
+
+      # Other parameters - Recommended to keep defaults
+      - name: fleet_repo_dir
+        value: "/fleet/fleet-osm/"
+
+    volumes:
+      - name: fleet-repo-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.fleet_volume_name}}'
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      # securityContext:
+      #   runAsUser: 10000
+      #   runAsGroup: 10000
+      #   fsGroup: 10000
+      volumeMounts:
+      - name: fleet-repo-volume
+        mountPath: '{{inputs.parameters.fleet_mount_path}}'
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+      - create_profile
+      - "{{inputs.parameters.profile_name}}"
+      - "{{inputs.parameters.profile_type}}"
+      - "{{inputs.parameters.project_name}}"
+      - "{{inputs.parameters.fleet_repo_url}}"
+      - "{{inputs.parameters.fleet_repo_dir}}"
+
+
+  # Delete a profile
+  - name: delete-profile
+    inputs:
+      parameters:
+      # Volumes with cloned repos
+      - name: fleet_volume_name
+      - name: fleet_mount_path
+        value: "/fleet"
+
+      # Specific parameters
+      - name: profile_name
+      - name: profile_type
+      - name: project_name
+        value: "osm_admin"
+
+      # Other parameters - Recommended to keep defaults
+      - name: fleet_repo_dir
+        value: "/fleet/fleet-osm/"
+
+    volumes:
+      - name: fleet-repo-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.fleet_volume_name}}'
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      # securityContext:
+      #   runAsUser: 10000
+      #   runAsGroup: 10000
+      #   fsGroup: 10000
+      volumeMounts:
+      - name: fleet-repo-volume
+        mountPath: '{{inputs.parameters.fleet_mount_path}}'
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+      - delete_profile
+      - "{{inputs.parameters.profile_name}}"
+      - "{{inputs.parameters.profile_type}}"
+      - "{{inputs.parameters.project_name}}"
+      - "{{inputs.parameters.fleet_repo_dir}}"
+
+
+  # Attach a profile to a cluster
+  - name: attach-profile-to-cluster
+    inputs:
+      parameters:
+      # Volumes with cloned repos
+      - name: fleet_volume_name
+      - name: fleet_mount_path
+        value: "/fleet"
+
+      # Specific parameters
+      - name: profile_name
+      - name: profile_type
+      - name: project_name
+        value: "osm_admin"
+      - name: cluster_kustomization_name
+
+      # Other parameters - Recommended to keep defaults
+      - name: fleet_repo_dir
+        value: "/fleet/fleet-osm/"
+    volumes:
+      - name: fleet-repo-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.fleet_volume_name}}'
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      # securityContext:
+      #   runAsUser: 10000
+      #   runAsGroup: 10000
+      #   fsGroup: 10000
+      volumeMounts:
+      - name: fleet-repo-volume
+        mountPath: '{{inputs.parameters.fleet_mount_path}}'
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+      - attach_profile_to_cluster
+      - "{{inputs.parameters.profile_name}}"
+      - "{{inputs.parameters.profile_type}}"
+      - "{{inputs.parameters.project_name}}"
+      - "{{inputs.parameters.cluster_kustomization_name}}"
+      - "{{inputs.parameters.fleet_repo_dir}}"
+
+
+  # Detach profile from cluster
+  - name: detach-profile-from-cluster
+    inputs:
+      parameters:
+      # Volumes with cloned repos
+      - name: fleet_volume_name
+      - name: fleet_mount_path
+        value: "/fleet"
+
+      # Specific parameters
+      - name: profile_name
+      - name: profile_type
+      - name: project_name
+        value: "osm_admin"
+      - name: cluster_kustomization_name
+
+      # Other parameters - Recommended to keep defaults
+      - name: fleet_repo_dir
+        value: "/fleet/fleet-osm/"
+    volumes:
+      - name: fleet-repo-volume
+        persistentVolumeClaim:
+          claimName: '{{inputs.parameters.fleet_volume_name}}'
+    container:
+      image: ttl.sh/osm-krm-functions:24h
+      # imagePullPolicy: Always
+      # securityContext:
+      #   runAsUser: 10000
+      #   runAsGroup: 10000
+      #   fsGroup: 10000
+      volumeMounts:
+      - name: fleet-repo-volume
+        mountPath: '{{inputs.parameters.fleet_mount_path}}'
+      command: ["/app/scripts/entrypoint.sh"]
+      args:
+      - detach_profile_from_cluster
+      - "{{inputs.parameters.profile_name}}"
+      - "{{inputs.parameters.profile_type}}"
+      - "{{inputs.parameters.project_name}}"
+      - "{{inputs.parameters.cluster_kustomization_name}}"
+      - "{{inputs.parameters.fleet_repo_dir}}"
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-attach-profile.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-attach-profile.yaml
new file mode 100644 (file)
index 0000000..5a4bd20
--- /dev/null
@@ -0,0 +1,150 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: full-attach-profile-wft
+  namespace: osm-workflows
+
+spec:
+  arguments:
+    parameters:
+
+    # Fleet repo
+    - name: git_fleet_url
+    - name: fleet_destination_folder
+    - name: git_fleet_cred_secret
+
+    # Specific parameters
+    - name: profile_name
+    - name: profile_type
+    - name: project_name
+      value: "osm_admin"
+    - name: cluster_kustomization_name
+
+    # Debugging
+    - name: dry_run
+      value: false
+
+
+  # # Cleanup policy
+  # ttlStrategy:
+  #   secondsAfterCompletion: 100 # Time to live after workflow is completed, replaces ttlSecondsAfterFinished
+  #   secondsAfterSuccess: 50     # Time to live after workflow is successful
+  #   secondsAfterFailure: 50     # Time to live after workflow fails
+
+  entrypoint: attach-profile
+
+  templates:
+
+  # Main template
+  - name: attach-profile
+    inputs:
+      parameters:
+      # Git repos
+      - name: git_fleet_url
+      - name: fleet_destination_folder
+      - name: git_fleet_cred_secret
+
+      # Specific parameters
+      - name: profile_name
+      - name: profile_type
+      - name: project_name
+      - name: cluster_kustomization_name
+
+      # Debugging
+      - name: dry_run
+    steps:
+
+    # ------ Preparations for transaction
+    - - name: generate-fleet-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+    - - name: clone-fleet
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+    # ------ end of preparations for transaction
+
+    # ------ Transformations
+    # Attach profile to cluster
+    - - name: attach-profile
+        templateRef:
+          name: profile-management-wft
+          template: attach-profile-to-cluster
+        arguments:
+          parameters:
+          # Volumes with cloned repos
+          - name: fleet_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: fleet_mount_path
+            value: "/fleet"
+          # Specific parameters
+          - name: profile_name
+            value: "{{inputs.parameters.profile_name}}"
+          - name: profile_type
+            value: "{{inputs.parameters.profile_type}}"
+          - name: project_name
+            value: "{{inputs.parameters.project_name}}"
+          - name: fleet_repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+          - name: cluster_kustomization_name
+            value: "{{inputs.parameters.cluster_kustomization_name}}"
+    # ------ end of transformations
+
+    # ------ Commit transaction
+    - - name: push-to-fleet
+        templateRef:
+          name: git-wft
+          template: git-commit-merge-push
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: commit_message
+            value: "Attach {{inputs.parameters.profile_name}} profile to {{inputs.parameters.cluster_kustomization_name}} cluster"
+          - name: main_branch
+            value: main
+          - name: contrib_branch
+            value: osm_contrib
+          - name: dry_run
+            value: "{{inputs.parameters.dry_run}}"
+# ------ end of commit transaction
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-bootstrap-cluster-wft.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-bootstrap-cluster-wft.yaml
new file mode 100644 (file)
index 0000000..54e012f
--- /dev/null
@@ -0,0 +1,207 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: full-bootstrap-cluster-wft
+  namespace: osm-workflows
+
+spec:
+  arguments:
+    parameters:
+
+    # Fleet repo
+    - name: git_fleet_url
+    - name: fleet_destination_folder
+    - name: git_fleet_cred_secret
+
+    # SW-Catalogs repo
+    - name: git_sw_catalogs_url
+    - name: sw_catalogs_destination_folder
+    - name: git_sw_catalogs_cred_secret
+
+    # Specific parameters - Bootstrap
+    - name: cluster_name
+    - name: cluster_kustomization_name
+    - name: public_key_mgmt
+    - name: public_key_new_cluster
+    - name: secret_name_private_age_key_for_new_cluster
+    - name: key_name_in_secret
+      value: "agekey"
+
+    # Recommended to keep this default
+    - name: imported_cluster
+      value: "true"
+
+    # Debug/dry run?
+    - name: debug
+      value: "false"
+    - name: dry_run
+      value: "false"
+
+
+  # # Cleanup policy
+  # ttlStrategy:
+  #   secondsAfterCompletion: 100 # Time to live after workflow is completed, replaces ttlSecondsAfterFinished
+  #   secondsAfterSuccess: 50     # Time to live after workflow is successful
+  #   secondsAfterFailure: 50     # Time to live after workflow fails
+
+  entrypoint: bootstrap-cluster
+
+  templates:
+
+  # Main template
+  - name: bootstrap-cluster
+    inputs:
+      parameters:
+      # Git repos
+      - name: git_fleet_url
+      - name: fleet_destination_folder
+      - name: git_fleet_cred_secret
+      - name: git_sw_catalogs_url
+      - name: sw_catalogs_destination_folder
+      - name: git_sw_catalogs_cred_secret
+
+      # Specific parameters - Bootstrap
+      - name: cluster_name
+      - name: cluster_kustomization_name
+      - name: public_key_mgmt
+      - name: public_key_new_cluster
+      - name: secret_name_private_age_key_for_new_cluster
+      - name: key_name_in_secret
+      - name: imported_cluster
+
+      # Debugging
+      - name: debug
+      - name: dry_run
+    steps:
+
+    # ------ Preparations for transaction
+    - - name: generate-fleet-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+      - name: generate-sw-catalogs-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+    - - name: clone-fleet
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+      - name: clone-sw-catalogs
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/sw-catalogs"
+          - name: repo_url
+            value: "{{inputs.parameters.git_sw_catalogs_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.sw_catalogs_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_sw_catalogs_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+    # ------ end of preparations for transaction
+
+    # ------ Transformations
+    # Bootstrap the remote cluster
+    - - name: bootstrap-cluster
+        templateRef:
+          name: cluster-management-wft
+          template: bootstrap-remote-cluster
+        arguments:
+          parameters:
+          # Volumes with cloned repos
+          - name: fleet_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: fleet_mount_path
+            value: "/fleet"
+          - name: sw_catalogs_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+          - name: sw_catalogs_mount_path
+            value: "/sw-catalogs"
+
+          # Specific parameters
+          - name: cluster_name
+            value: "{{inputs.parameters.cluster_name}}"
+          - name: cluster_kustomization_name
+            value: "{{inputs.parameters.cluster_kustomization_name}}"
+          - name: public_key_mgmt
+            value: "{{inputs.parameters.public_key_mgmt}}"
+          - name: public_key_new_cluster
+            value: "{{inputs.parameters.public_key_new_cluster}}"
+          - name: secret_name_private_age_key_for_new_cluster
+            value: "{{inputs.parameters.secret_name_private_age_key_for_new_cluster}}"
+          - name: key_name_in_secret
+            value: "{{inputs.parameters.key_name_in_secret}}"
+          - name: fleet_repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+          - name: sw_catalogs_repo_url
+            value: "{{inputs.parameters.git_sw_catalogs_url}}"
+          - name: imported_cluster
+            value: "{{inputs.parameters.imported_cluster}}"
+    # ------ end of transformations
+
+    # ------ Commit transaction
+    - - name: push-to-fleet
+        templateRef:
+          name: git-wft
+          template: git-commit-merge-push
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: commit_message
+            value: "Bootstrap imported cluster {{inputs.parameters.cluster_kustomization_name}}"
+          - name: main_branch
+            value: main
+          - name: contrib_branch
+            value: osm_contrib
+          - name: dry_run
+            value: "{{inputs.parameters.dry_run}}"
+# ------ end of commit transaction
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-clone-ksu.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-clone-ksu.yaml
new file mode 100644 (file)
index 0000000..ac32376
--- /dev/null
@@ -0,0 +1,180 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: full-clone-ksu-wtf
+  namespace: osm-workflows
+spec:
+  arguments:
+    parameters:
+    # Fleet repo
+    - name: git_fleet_url
+    - name: fleet_destination_folder
+    - name: git_fleet_cred_secret
+    # Specific parameters - Source and destination KSU
+    ## Source KSU:
+    - name: source_ksu_name
+    - name: source_profile_name
+    - name: source_profile_type
+    - name: source_project_name
+      value: "osm_admin"
+    ## Destination KSU:
+    ## - If any of the destination parameters are not specified, it will assume
+    ##   they are the same as in source.
+    ## - It will reject if all are empty or equal to source, to avoid cloning a KSU over itself
+    - name: destination_ksu_name
+      value: ""
+    - name: destination_profile_name
+      value: ""
+    - name: destination_profile_type
+      value: ""
+    - name: destination_project_name
+      value: ""
+    # Debug/dry run?
+    - name: debug
+      value: "false"
+    - name: dry_run
+      value: "false"
+
+  # Cleanup policy
+  ttlStrategy:
+    secondsAfterCompletion: 6000  # Time to live after workflow is completed, replaces ttlSecondsAfterFinished
+    secondsAfterSuccess: 6000     # Time to live after workflow is successful
+    secondsAfterFailure: 9000     # Time to live after workflow fails
+
+  entrypoint: clone-ksu
+
+  templates:
+  # Main template
+  - name: clone-ksu
+    inputs:
+      parameters:
+      # Fleet repo
+      - name: git_fleet_url
+      - name: fleet_destination_folder
+      - name: git_fleet_cred_secret
+      # Specific parameters - Source and destination KSU
+      ## Source KSU:
+      - name: source_ksu_name
+      - name: source_profile_name
+      - name: source_profile_type
+      - name: source_project_name
+      ## Destination KSU:
+      - name: destination_ksu_name
+      - name: destination_profile_name
+      - name: destination_profile_type
+      - name: destination_project_name
+      # Debug/dry run?
+      - name: debug
+      - name: dry_run
+
+    steps:
+    # ------ Preparations for transaction
+    - - name: generate-fleet-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+      - name: generate-sw-catalogs-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+    - - name: clone-fleet
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+    # ------ end of preparations for transaction
+
+    # ------ Transformations
+    - - name: clone-ksu
+        templateRef:
+          name: ksu-management-wft
+          template: clone-ksu
+        arguments:
+          parameters:
+          # References to required external resources
+          - name: fleet_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          # Specific parameters - Source and destination KSU
+          ## Source KSU:
+          - name: source_ksu_name
+            value: "{{inputs.parameters.source_ksu_name}}"
+          - name: source_profile_name
+            value: "{{inputs.parameters.source_profile_name}}"
+          - name: source_profile_type
+            value: "{{inputs.parameters.source_profile_type}}"
+          - name: source_project_name
+            value: "{{inputs.parameters.source_project_name}}"
+          ## Destination KSU:
+          - name: destination_ksu_name
+            value: "{{inputs.parameters.destination_ksu_name}}"
+          - name: destination_profile_name
+            value: "{{inputs.parameters.destination_profile_name}}"
+          - name: destination_profile_type
+            value: "{{inputs.parameters.destination_profile_type}}"
+          - name: destination_project_name
+            value: "{{inputs.parameters.destination_project_name}}"
+          # Debug?
+          - name: debug
+            value: "{{inputs.parameters.debug}}"
+    # ------ end of transformations
+
+    # ------ Commit transaction
+    - - name: push-to-fleet
+        templateRef:
+          name: git-wft
+          template: git-commit-merge-push
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: commit_message
+            value: "Clone KSU {{inputs.parameters.source_ksu_name}} at {{inputs.parameters.source_profile_name}} profile of {{inputs.parameters.source_profile_type}} type @ {{inputs.parameters.source_project_name}} project as {{inputs.parameters.destination_ksu_name}} KSU at {{inputs.parameters.destination_profile_name}} profile of {{inputs.parameters.destination_profile_type}} type @ {{inputs.parameters.destination_project_name}}"
+          - name: main_branch
+            value: main
+          - name: contrib_branch
+            value: osm_contrib
+          - name: dry_run
+            value: "{{inputs.parameters.dry_run}}"
+# ------ end of commit transaction
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-create-aks-cluster-and-bootstrap-wft.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-create-aks-cluster-and-bootstrap-wft.yaml
new file mode 100644 (file)
index 0000000..76ac3eb
--- /dev/null
@@ -0,0 +1,251 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: full-create-aks-cluster-and-bootstrap-wft
+  namespace: osm-workflows
+
+spec:
+  arguments:
+    parameters:
+
+    # Fleet repo
+    - name: git_fleet_url
+    - name: fleet_destination_folder
+    - name: git_fleet_cred_secret
+
+    # SW-Catalogs repo
+    - name: git_sw_catalogs_url
+    - name: sw_catalogs_destination_folder
+    - name: git_sw_catalogs_cred_secret
+
+    # Specific parameters - AKS cluster
+    - name: cluster_name
+    - name: vm_size
+    - name: node_count
+    - name: cluster_location
+    - name: rg_name
+    - name: k8s_version
+    - name: providerconfig_name
+    - name: cluster_kustomization_name
+
+    # Specific parameters - Bootstrap
+    - name: public_key_mgmt
+    - name: public_key_new_cluster
+    - name: secret_name_private_age_key_for_new_cluster
+    - name: key_name_in_secret
+      value: "agekey"
+    - name: fleet_repo_url
+    - name: sw_catalogs_repo_url
+
+    # Debugging
+    - name: dry_run
+      value: false
+
+
+  # # Cleanup policy
+  # ttlStrategy:
+  #   secondsAfterCompletion: 100 # Time to live after workflow is completed, replaces ttlSecondsAfterFinished
+  #   secondsAfterSuccess: 50     # Time to live after workflow is successful
+  #   secondsAfterFailure: 50     # Time to live after workflow fails
+
+  entrypoint: create-aks-cluster-and-bootstrap
+
+  templates:
+
+  # Main template
+  - name: create-aks-cluster-and-bootstrap
+    inputs:
+      parameters:
+      # Git repos
+      - name: git_fleet_url
+      - name: fleet_destination_folder
+      - name: git_fleet_cred_secret
+      - name: git_sw_catalogs_url
+      - name: sw_catalogs_destination_folder
+      - name: git_sw_catalogs_cred_secret
+
+      # Specific parameters - AKS cluster
+      - name: cluster_name
+      - name: vm_size
+      - name: node_count
+      - name: cluster_location
+      - name: rg_name
+      - name: k8s_version
+      - name: providerconfig_name
+      - name: cluster_kustomization_name
+
+      # Specific parameters - Bootstrap
+      - name: public_key_mgmt
+      - name: public_key_new_cluster
+      - name: secret_name_private_age_key_for_new_cluster
+      - name: key_name_in_secret
+      - name: fleet_repo_url
+      - name: sw_catalogs_repo_url
+
+      # Debugging
+      - name: dry_run
+    steps:
+
+    # ------ Preparations for transaction
+    - - name: generate-fleet-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+      - name: generate-sw-catalogs-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+    - - name: clone-fleet
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+      - name: clone-sw-catalogs
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/sw-catalogs"
+          - name: repo_url
+            value: "{{inputs.parameters.git_sw_catalogs_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.sw_catalogs_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_sw_catalogs_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+    # ------ end of preparations for transaction
+
+    # ------ Transformations
+    # Create cluster in target cloud
+    - - name: create-cluster-aks
+        templateRef:
+          name: cluster-management-wft
+          template: create-cluster-aks
+        arguments:
+          parameters:
+          # Volumes with cloned repos
+          - name: fleet_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: fleet_mount_path
+            value: "/fleet"
+          - name: sw_catalogs_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+          - name: sw_catalogs_mount_path
+            value: "/sw-catalogs"
+          # Specific parameters
+          - name: cluster_name
+            value: "{{inputs.parameters.cluster_name}}"
+          - name: vm_size
+            value: "{{inputs.parameters.vm_size}}"
+          - name: node_count
+            value: "{{inputs.parameters.node_count}}"
+          - name: cluster_location
+            value: "{{inputs.parameters.cluster_location}}"
+          - name: rg_name
+            value: "{{inputs.parameters.rg_name}}"
+          - name: k8s_version
+            value: "{{inputs.parameters.k8s_version}}"
+          - name: providerconfig_name
+            value: "{{inputs.parameters.providerconfig_name}}"
+          - name: cluster_kustomization_name
+            value: "{{inputs.parameters.cluster_kustomization_name}}"
+
+    # Bootstrap the new remote cluster
+    - - name: bootstrap-new-cluster
+        templateRef:
+          name: cluster-management-wft
+          template: bootstrap-remote-cluster
+        arguments:
+          parameters:
+          # Volumes with cloned repos
+          - name: fleet_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: fleet_mount_path
+            value: "/fleet"
+          - name: sw_catalogs_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+          - name: sw_catalogs_mount_path
+            value: "/sw-catalogs"
+
+          # Specific parameters
+          - name: cluster_name
+            value: "{{inputs.parameters.cluster_name}}"
+          - name: cluster_kustomization_name
+            value: "{{inputs.parameters.cluster_kustomization_name}}"
+          - name: public_key_mgmt
+            value: "{{inputs.parameters.public_key_mgmt}}"
+          - name: public_key_new_cluster
+            value: "{{inputs.parameters.public_key_new_cluster}}"
+          - name: secret_name_private_age_key_for_new_cluster
+            value: "{{inputs.parameters.secret_name_private_age_key_for_new_cluster}}"
+          - name: key_name_in_secret
+            value: "{{inputs.parameters.key_name_in_secret}}"
+          - name: fleet_repo_url
+            value: "{{inputs.parameters.fleet_repo_url}}"
+          - name: sw_catalogs_repo_url
+            value: "{{inputs.parameters.sw_catalogs_repo_url}}"
+    # ------ end of transformations
+
+    # ------ Commit transaction
+    - - name: push-to-fleet
+        templateRef:
+          name: git-wft
+          template: git-commit-merge-push
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: commit_message
+            value: "Create AKS cluster {{inputs.parameters.cluster_kustomization_name}}"
+          - name: main_branch
+            value: main
+          - name: contrib_branch
+            value: osm_contrib
+          - name: dry_run
+            value: "{{inputs.parameters.dry_run}}"
+# ------ end of commit transaction
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-create-crossplane-cluster-and-bootstrap-wft.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-create-crossplane-cluster-and-bootstrap-wft.yaml
new file mode 100644 (file)
index 0000000..d5b2ed2
--- /dev/null
@@ -0,0 +1,286 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: full-create-crossplane-cluster-and-bootstrap-wft
+  namespace: osm-workflows
+
+spec:
+  arguments:
+    parameters:
+
+    # Fleet repo
+    - name: git_fleet_url
+    - name: fleet_destination_folder
+    - name: git_fleet_cred_secret
+
+    # SW-Catalogs repo
+    - name: git_sw_catalogs_url
+    - name: sw_catalogs_destination_folder
+    - name: git_sw_catalogs_cred_secret
+
+    # Specific parameters - Generic cluster creation
+    - name: cluster_kustomization_name
+    - name: cluster_name
+    - name: cluster_type
+    - name: providerconfig_name
+    - name: vm_size
+    - name: node_count
+    - name: cluster_location
+    - name: k8s_version
+
+    # Specific parameters - Bootstrap and credentials
+    - name: public_key_mgmt
+    - name: public_key_new_cluster
+    - name: secret_name_private_age_key_for_new_cluster
+    - name: key_name_in_secret
+      value: "agekey"
+    # Using `git_fleet_url` instead:
+    # - name: fleet_repo_url
+    # Using `git_sw_catalogs_url` instead:
+    # - name: sw_catalogs_repo_url
+    - name: mgmt_project_name
+      value: "osm_admin"
+
+    # Specific parameters - AKS only
+    - name: rg_name
+      values: ""
+
+    # Specific parameters - GKE only
+    - name: preemptible_nodes
+      values: "false"
+
+    # Advanced parameters - Recommended to keep defaults
+    - name: skip_bootstrap
+      value: "false"
+    - name: mgmt_cluster_name
+      value: "_management"
+    - name: base_templates_path
+      value: "cloud-resources"
+    - name: cloned_fleet_folder_name
+      value: "fleet-osm"
+    - name: cloned_sw_catalogs_folder_name
+      value: "sw-catalogs-osm"
+
+    # Debug/dry run?
+    - name: debug
+      value: "false"
+    - name: dry_run
+      value: "false"
+
+
+  # # Cleanup policy
+  # ttlStrategy:
+  #   secondsAfterCompletion: 100 # Time to live after workflow is completed, replaces ttlSecondsAfterFinished
+  #   secondsAfterSuccess: 50     # Time to live after workflow is successful
+  #   secondsAfterFailure: 50     # Time to live after workflow fails
+
+  entrypoint: create-cluster-and-bootstrap
+
+  templates:
+  # Main template
+  - name: create-cluster-and-bootstrap
+    inputs:
+      parameters:
+      # Fleet repo
+      - name: git_fleet_url
+      - name: fleet_destination_folder
+      - name: git_fleet_cred_secret
+      # SW-Catalogs repo
+      - name: git_sw_catalogs_url
+      - name: sw_catalogs_destination_folder
+      - name: git_sw_catalogs_cred_secret
+      # Specific parameters
+      - name: cluster_kustomization_name
+      - name: cluster_name
+      - name: cluster_type
+      - name: providerconfig_name
+      - name: vm_size
+      - name: node_count
+      - name: cluster_location
+      - name: k8s_version
+      - name: public_key_mgmt
+      - name: public_key_new_cluster
+      - name: secret_name_private_age_key_for_new_cluster
+      - name: key_name_in_secret
+      # - name: fleet_repo_url
+      # - name: sw_catalogs_repo_url
+      - name: mgmt_project_name
+      - name: skip_bootstrap
+      ## AKS only (otherwise, ignored)
+      - name: rg_name
+      ## GKE only (otherwise, ignored)
+      - name: preemptible_nodes
+      # Other parameters - Recommended to keep defaults
+      - name: mgmt_cluster_name
+      - name: base_templates_path
+      - name: cloned_fleet_folder_name
+      - name: cloned_sw_catalogs_folder_name
+      # Debug/dry run?
+      - name: debug
+      - name: dry_run
+
+    steps:
+    # ------ Preparations for transaction
+    - - name: generate-fleet-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+      - name: generate-sw-catalogs-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+    - - name: clone-fleet
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+      - name: clone-sw-catalogs
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/sw-catalogs"
+          - name: repo_url
+            value: "{{inputs.parameters.git_sw_catalogs_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.sw_catalogs_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_sw_catalogs_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+    # ------ end of preparations for transaction
+
+    # ------ Transformations
+    # Create cluster in target cloud
+    - - name: create-cluster
+        templateRef:
+          name: cluster-management-wft
+          template: create-crossplane-cluster
+        arguments:
+          parameters:
+          # Volumes with cloned repos
+          - name: fleet_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: fleet_mount_path
+            value: "/fleet"
+          - name: sw_catalogs_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+          - name: sw_catalogs_mount_path
+            value: "/sw-catalogs"
+          # Specific parameters
+          - name: cluster_kustomization_name
+            value: "{{inputs.parameters.cluster_kustomization_name}}"
+          - name: cluster_name
+            value: "{{inputs.parameters.cluster_name}}"
+          - name: cluster_type
+            value: "{{inputs.parameters.cluster_type}}"
+          - name: providerconfig_name
+            value: "{{inputs.parameters.providerconfig_name}}"
+          - name: vm_size
+            value: "{{inputs.parameters.vm_size}}"
+          - name: node_count
+            value: "{{inputs.parameters.node_count}}"
+          - name: cluster_location
+            value: "{{inputs.parameters.cluster_location}}"
+          - name: k8s_version
+            value: "{{inputs.parameters.k8s_version}}"
+          - name: public_key_mgmt
+            value: "{{inputs.parameters.public_key_mgmt}}"
+          - name: public_key_new_cluster
+            value: "{{inputs.parameters.public_key_new_cluster}}"
+          - name: secret_name_private_age_key_for_new_cluster
+            value: "{{inputs.parameters.secret_name_private_age_key_for_new_cluster}}"
+          - name: key_name_in_secret
+            value: "{{inputs.parameters.key_name_in_secret}}"
+          ## Fed with `git_fleet_url` to avoid duplicates
+          - name: fleet_repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+          ## Fed with `git_sw_catalogs_url` to avoid duplicates
+          - name: sw_catalogs_repo_url
+            value: "{{inputs.parameters.git_sw_catalogs_url}}"
+          - name: mgmt_project_name
+            value: "{{inputs.parameters.mgmt_project_name}}"
+          - name: skip_bootstrap
+            value: "{{inputs.parameters.skip_bootstrap}}"
+          ## AKS only
+          - name: rg_name
+            value: "{{inputs.parameters.rg_name}}"
+          ## GKE only
+          - name: preemptible_nodes
+            value: "{{inputs.parameters.preemptible_nodes}}"
+          # Other parameters - Recommended to keep defaults
+          - name: mgmt_cluster_name
+            value: "{{inputs.parameters.mgmt_cluster_name}}"
+          - name: base_templates_path
+            value: "{{inputs.parameters.base_templates_path}}"
+          - name: cloned_fleet_folder_name
+            value: "{{inputs.parameters.cloned_fleet_folder_name}}"
+          - name: cloned_sw_catalogs_folder_name
+            value: "{{inputs.parameters.cloned_sw_catalogs_folder_name}}"
+          # Debug?
+          - name: debug
+            value: "{{inputs.parameters.debug}}"
+    # ------ end of transformations
+
+    # ------ Commit transaction
+    - - name: push-to-fleet
+        templateRef:
+          name: git-wft
+          template: git-commit-merge-push
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: commit_message
+            value: "Create {{inputs.parameters.cluster_type}} cluster {{inputs.parameters.cluster_kustomization_name}} at {{inputs.parameters.cluster_location}}"
+          - name: main_branch
+            value: main
+          - name: contrib_branch
+            value: osm_contrib
+          - name: dry_run
+            value: "{{inputs.parameters.dry_run}}"
+# ------ end of commit transaction
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-create-ksu-generated-hr.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-create-ksu-generated-hr.yaml
new file mode 100644 (file)
index 0000000..7b74541
--- /dev/null
@@ -0,0 +1,285 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: full-create-ksu-generated-hr-wtf
+  namespace: osm-workflows
+spec:
+  arguments:
+    parameters:
+    # Fleet repo
+    - name: git_fleet_url
+    - name: fleet_destination_folder
+    - name: git_fleet_cred_secret
+    # HelmRelease generation
+    - name: helmrelease_name
+    - name: chart_name
+    - name: chart_version
+    - name: target_ns
+    - name: create_ns
+    # Repo source generation
+    - name: is_preexisting_repo
+      value: "false"
+    - name: helmrepo_name
+    - name: helmrepo_url
+    - name: helmrepo_ns
+      valueFrom:
+        expression: "{{inputs.parameters.target_ns}}"
+    - name: helmrepo_secret_ref
+    # HelmRelease inline values (if any)
+    - name: inline_values
+      value: ""
+    # Secret reference and generation (if required)
+    - name: is_preexisting_secret
+      value: "false"
+    - name: values_secret_name
+    - name: secret_key
+      value: "values.yaml"
+    - name: age_public_key
+    ################################################################
+    ## A temporary secret should exist already in the `osm-workflows`
+    ## namespace containing the desired secret key-values
+    ## in a well-known key (in the example, `creds`).
+    ##
+    ## For instance:
+    ##
+    ## creds: |
+    ##     jenkinsUser: admin
+    ##     jenkinsPassword: myJ3nk1n2P2ssw0rd
+    ##
+    ## Secret values will be obtained from the
+    ## secret named after the input parameter `reference_secret_for_values`,
+    ## and from the key named after the input parameter `reference_key_for_values`
+    - name: reference_secret_for_values
+    - name: reference_key_for_values
+    # ConfigMap reference and generation (if required)
+    - name: is_preexisting_cm
+    - name: values_cm_name
+    - name: cm_key
+      value: "values.yaml"
+    - name: cm_values
+      value: ""
+    # KSU rendering
+    - name: ksu_name
+    - name: profile_name
+    - name: profile_type
+    - name: project_name
+      value: "osm_admin"
+    # By default, it will not syncronize, so that we can easily accumulate more than
+    # one Helm chart into the same KSU if desired
+    - name: sync
+      value: "false"
+    ## Root folder of the cloned Fleet repo - Do not touch
+    ### `FLEET_REPO_DIR` is the result of:
+    ### "{{inputs.parameters.fleet_mount_path}}/{{inputs.parameters.cloned_fleet_folder_name}}"
+    - name: cloned_fleet_folder_name
+      value: "fleet-osm"
+    # Debug/dry run?
+    - name: debug
+      value: "false"
+    - name: dry_run
+      value: "false"
+
+  # Cleanup policy
+  ttlStrategy:
+    secondsAfterCompletion: 6000  # Time to live after workflow is completed, replaces ttlSecondsAfterFinished
+    secondsAfterSuccess: 6000     # Time to live after workflow is successful
+    secondsAfterFailure: 9000     # Time to live after workflow fails
+
+  entrypoint: create-ksu-hr
+
+  templates:
+  # Main template
+  - name: create-ksu-hr
+    inputs:
+      parameters:
+      # Fleet repo
+      - name: git_fleet_url
+      - name: fleet_destination_folder
+      - name: git_fleet_cred_secret
+      # HelmRelease generation
+      - name: helmrelease_name
+      - name: chart_name
+      - name: chart_version
+      - name: target_ns
+      - name: create_ns
+      # Repo source generation
+      - name: is_preexisting_repo
+      - name: helmrepo_name
+      - name: helmrepo_url
+      - name: helmrepo_ns
+      - name: helmrepo_secret_ref
+      # HelmRelease inline values (if any)
+      - name: inline_values
+      # Secret reference and generation (if required)
+      - name: is_preexisting_secret
+      - name: values_secret_name
+      - name: secret_key
+      - name: age_public_key
+      - name: reference_secret_for_values
+      - name: reference_key_for_values
+      # ConfigMap reference and generation (if required)
+      - name: is_preexisting_cm
+      - name: values_cm_name
+      - name: cm_key
+      - name: cm_values
+      # KSU rendering
+      - name: ksu_name
+      - name: profile_name
+      - name: profile_type
+      - name: project_name
+      - name: sync
+      - name: cloned_fleet_folder_name
+      # Debug/dry run?
+      - name: debug
+        value: "false"
+      - name: dry_run
+        value: "false"
+
+    steps:
+    # ------ Preparations for transaction
+    - - name: generate-fleet-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+    - - name: clone-fleet
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+    # ------ end of preparations for transaction
+
+    # ------ Transformations
+    - - name: create-ksu-generated-hr
+        templateRef:
+          name: ksu-management-wft
+          template: create-ksu-generated-hr
+        arguments:
+          parameters:
+          # References to required external resources
+          - name: fleet_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: fleet_mount_path
+            value: "/fleet"
+          # HelmRelease generation
+          - name: helmrelease_name
+            value: "{{inputs.parameters.helmrelease_name}}"
+          - name: chart_name
+            value: "{{inputs.parameters.chart_name}}"
+          - name: chart_version
+            value: "{{inputs.parameters.chart_version}}"
+          - name: target_ns
+            value: "{{inputs.parameters.target_ns}}"
+          - name: create_ns
+            value: "{{inputs.parameters.create_ns}}"
+          # Repo source generation
+          - name: is_preexisting_repo
+            value: "{{inputs.parameters.is_preexisting_repo}}"
+          - name: helmrepo_name
+            value: "{{inputs.parameters.helmrepo_name}}"
+          - name: helmrepo_url
+            value: "{{inputs.parameters.helmrepo_url}}"
+          - name: helmrepo_ns
+            value: "{{inputs.parameters.helmrepo_ns}}"
+          - name: helmrepo_secret_ref
+            value: "{{inputs.parameters.helmrepo_secret_ref}}"
+          # HelmRelease inline values (if any)
+          - name: inline_values
+            value: "{{inputs.parameters.inline_values}}"
+          # Secret reference and generation (if required)
+          - name: is_preexisting_secret
+            value: "{{inputs.parameters.is_preexisting_secret}}"
+          - name: values_secret_name
+            value: "{{inputs.parameters.values_secret_name}}"
+          - name: secret_key
+            value: "{{inputs.parameters.secret_key}}"
+          - name: age_public_key
+            value: "{{inputs.parameters.age_public_key}}"
+          ## Secret values will be obtained from this key in this secret
+          - name: reference_secret_for_values
+            value: "{{inputs.parameters.reference_secret_for_values}}"
+          - name: reference_key_for_values
+            value: "{{inputs.parameters.reference_key_for_values}}"
+          # ConfigMap reference and generation (if required)
+          - name: is_preexisting_cm
+            value: "{{inputs.parameters.is_preexisting_cm}}"
+          - name: values_cm_name
+            value: "{{inputs.parameters.values_cm_name}}"
+          - name: cm_key
+            value: "{{inputs.parameters.cm_key}}"
+          - name: cm_values
+            value: "{{inputs.parameters.cm_values}}"
+          # KSU rendering
+          - name: ksu_name
+            value: "{{inputs.parameters.ksu_name}}"
+          - name: profile_name
+            value: "{{inputs.parameters.profile_name}}"
+          - name: profile_type
+            value: "{{inputs.parameters.profile_type}}"
+          - name: project_name
+            value: "{{inputs.parameters.project_name}}"
+          - name: sync
+            value: "{{inputs.parameters.sync}}"
+          ## Root folder of the cloned Fleet repo - Do not touch
+          - name: cloned_fleet_folder_name
+            value: "{{inputs.parameters.cloned_fleet_folder_name}}"
+          # Debug?
+          - name: debug
+            value: "{{inputs.parameters.debug}}"
+    # ------ end of transformations
+
+    # ------ Commit transaction
+    - - name: push-to-fleet
+        templateRef:
+          name: git-wft
+          template: git-commit-merge-push
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: commit_message
+            value: "Create KSU {{inputs.parameters.ksu_name}} into {{inputs.parameters.profile_name}} profile of {{inputs.parameters.profile_type}} type @ {{inputs.parameters.project_name}} project"
+          - name: main_branch
+            value: main
+          - name: contrib_branch
+            value: osm_contrib
+          - name: dry_run
+            value: "{{inputs.parameters.dry_run}}"
+# ------ end of commit transaction
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-create-ksu-hr.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-create-ksu-hr.yaml
new file mode 100644 (file)
index 0000000..b904218
--- /dev/null
@@ -0,0 +1,284 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: full-create-ksu-hr-wtf
+  namespace: osm-workflows
+spec:
+  arguments:
+    parameters:
+    # Fleet repo
+    - name: git_fleet_url
+    - name: fleet_destination_folder
+    - name: git_fleet_cred_secret
+    # SW-Catalogs repo
+    - name: git_sw_catalogs_url
+    - name: sw_catalogs_destination_folder
+    - name: git_sw_catalogs_cred_secret
+    # Specific parameters - Base KSU generation from template
+    ## Relative path from "SW Catalogs" repo root
+    - name: templates_path
+    ## Should substitute environment variables in the template?
+    - name: substitute_environment
+    ## Filter for substitution of environment variables
+    - name: substitution_filter
+    ## Custom environment variables (formatted as .env), to be used for template parametrization
+    - name: custom_env_vars
+    # Specific parameters - Patch HelmRelease in KSU with inline values
+    - name: kustomization_name
+    - name: helmrelease_name
+    - name: inline_values
+    # Specific parameters - Secret generation
+    - name: is_preexisting_secret
+    - name: target_ns
+    - name: age_public_key
+    - name: values_secret_name
+    - name: secret_key
+      value: "values.yaml"
+    ################################################################
+    # This temporary secret should exist already in the `osm-workflows`
+    # namespace and contain the desired secret key-values
+    # in a well-known key (in the example, `creds`).
+    #
+    # For instance:
+    #
+    # creds: |
+    #     jenkinsUser: admin
+    #     jenkinsPassword: myJ3nk1n2P2ssw0rd
+    - name: reference_secret_for_values
+    - name: reference_key_for_values
+    # Specific parameters - Configmap generation
+    - name: is_preexisting_cm
+    - name: values_cm_name
+    - name: cm_key
+      value: "values.yaml"
+    - name: cm_values
+      value: ""
+    # Specific parameters - KSU rendering
+    - name: ksu_name
+    - name: profile_name
+    - name: profile_type
+    - name: project_name
+      value: "osm_admin"
+    # By default, it will re-create the full KSU folder
+    - name: sync
+      version: "true"
+    # Debug/dry run?
+    - name: debug
+      value: "false"
+    - name: dry_run
+      value: "false"
+
+  # Cleanup policy
+  ttlStrategy:
+    secondsAfterCompletion: 6000  # Time to live after workflow is completed, replaces ttlSecondsAfterFinished
+    secondsAfterSuccess: 6000     # Time to live after workflow is successful
+    secondsAfterFailure: 9000     # Time to live after workflow fails
+
+  entrypoint: create-ksu-hr
+
+  templates:
+  # Main template
+  - name: create-ksu-hr
+    inputs:
+      parameters:
+      # Fleet repo
+      - name: git_fleet_url
+      - name: fleet_destination_folder
+      - name: git_fleet_cred_secret
+      # SW-Catalogs repo
+      - name: git_sw_catalogs_url
+      - name: sw_catalogs_destination_folder
+      - name: git_sw_catalogs_cred_secret
+      # Specific parameters - Base KSU generation from template
+      - name: templates_path
+      - name: substitute_environment
+      - name: substitution_filter
+      - name: custom_env_vars
+      # Specific parameters - Patch HelmRelease in KSU with inline values
+      - name: kustomization_name
+      - name: helmrelease_name
+      - name: inline_values
+      # Specific parameters - Secret generation
+      - name: is_preexisting_secret
+      - name: target_ns
+      - name: age_public_key
+      - name: values_secret_name
+      - name: reference_secret_for_values
+      - name: reference_key_for_values
+      - name: secret_key
+      # Specific parameters - Configmap generation
+      - name: is_preexisting_cm
+      - name: values_cm_name
+      - name: cm_key
+      - name: cm_values
+      # Specific parameters - KSU rendering
+      - name: ksu_name
+      - name: profile_name
+      - name: profile_type
+      - name: project_name
+      - name: sync
+      # Debug/dry run?
+      - name: debug
+      - name: dry_run
+
+    steps:
+    # ------ Preparations for transaction
+    - - name: generate-fleet-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+      - name: generate-sw-catalogs-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+    - - name: clone-fleet
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+      - name: clone-sw-catalogs
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/sw-catalogs"
+          - name: repo_url
+            value: "{{inputs.parameters.git_sw_catalogs_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.sw_catalogs_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_sw_catalogs_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+    # ------ end of preparations for transaction
+
+    # ------ Transformations
+    - - name: create-ksu-oka-hr
+        templateRef:
+          name: ksu-management-wft
+          template: create-ksu-oka-hr
+        arguments:
+          parameters:
+          # References to required external resources
+          - name: fleet_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: sw_catalogs_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+          # Specific parameters - Base KSU generation from template
+          - name: templates_path
+            value: "{{inputs.parameters.templates_path}}"
+          - name: substitute_environment
+            value: "{{inputs.parameters.substitute_environment}}"
+          - name: substitution_filter
+            value: "{{inputs.parameters.substitution_filter}}"
+          - name: custom_env_vars
+            value: "{{inputs.parameters.custom_env_vars}}"
+          # Specific parameters - Patch HelmRelease in KSU with inline values
+          - name: kustomization_name
+            value: "{{inputs.parameters.kustomization_name}}"
+          - name: helmrelease_name
+            value: "{{inputs.parameters.helmrelease_name}}"
+          - name: inline_values
+            value: "{{inputs.parameters.inline_values}}"
+          # Specific parameters - Secret generation
+          - name: is_preexisting_secret
+            value: "{{inputs.parameters.is_preexisting_secret}}"
+          - name: target_ns
+            value: "{{inputs.parameters.target_ns}}"
+          - name: age_public_key
+            value: "{{inputs.parameters.age_public_key}}"
+          - name: values_secret_name
+            value: "{{inputs.parameters.values_secret_name}}"
+          - name: reference_secret_for_values
+            value: "{{inputs.parameters.reference_secret_for_values}}"
+          - name: reference_key_for_values
+            value: "{{inputs.parameters.reference_key_for_values}}"
+          - name: secret_key
+            value: "{{inputs.parameters.secret_key}}"
+          # Specific parameters - Configmap generation
+          - name: is_preexisting_cm
+            value: "{{inputs.parameters.is_preexisting_cm}}"
+          - name: values_cm_name
+            value: "{{inputs.parameters.values_cm_name}}"
+          - name: cm_key
+            value: "{{inputs.parameters.cm_key}}"
+          - name: cm_values
+            value: "{{inputs.parameters.cm_values}}"
+          # Specific parameters - KSU rendering
+          - name: ksu_name
+            value: "{{inputs.parameters.ksu_name}}"
+          - name: profile_name
+            value: "{{inputs.parameters.profile_name}}"
+          - name: profile_type
+            value: "{{inputs.parameters.profile_type}}"
+          - name: project_name
+            value: "{{inputs.parameters.project_name}}"
+          - name: sync
+            value: "{{inputs.parameters.sync}}"
+          # Debug?
+          - name: debug
+            value: "{{inputs.parameters.debug}}"
+    # ------ end of transformations
+
+    # ------ Commit transaction
+    - - name: push-to-fleet
+        templateRef:
+          name: git-wft
+          template: git-commit-merge-push
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: commit_message
+            value: "Create KSU {{inputs.parameters.ksu_name}} into {{inputs.parameters.profile_name}} profile of {{inputs.parameters.profile_type}} type @ {{inputs.parameters.project_name}} project"
+          - name: main_branch
+            value: main
+          - name: contrib_branch
+            value: osm_contrib
+          - name: dry_run
+            value: "{{inputs.parameters.dry_run}}"
+# ------ end of commit transaction
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-create-oka.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-create-oka.yaml
new file mode 100644 (file)
index 0000000..5b76543
--- /dev/null
@@ -0,0 +1,146 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: full-create-oka-wtf
+  namespace: osm-workflows
+spec:
+  arguments:
+    parameters:
+    # SW-Catalogs repo
+    - name: git_sw_catalogs_url
+    - name: sw_catalogs_destination_folder
+    - name: git_sw_catalogs_cred_secret
+    # Temporary volume with OKA contents
+    - name: temp_volume_name
+    # Specific parameters - OKA
+    - name: oka_name
+    ## Choose among `infra-controllers`, `infra-configs`, `cloud-resources`, `apps`:
+    - name: oka_type
+    - name: project_name
+      value: "osm_admin"
+    - name: tarball_file
+      value: "true"
+    # Debug/dry run?
+    - name: debug
+      value: "false"
+    - name: dry_run
+      value: "false"
+
+  # Cleanup policy
+  ttlStrategy:
+    secondsAfterCompletion: 6000  # Time to live after workflow is completed, replaces ttlSecondsAfterFinished
+    secondsAfterSuccess: 6000     # Time to live after workflow is successful
+    secondsAfterFailure: 9000     # Time to live after workflow fails
+
+  entrypoint: create-oka
+
+  templates:
+  # Main template
+  - name: create-oka
+    inputs:
+      parameters:
+      - name: git_sw_catalogs_url
+      - name: sw_catalogs_destination_folder
+      - name: git_sw_catalogs_cred_secret
+      - name: temp_volume_name
+      - name: oka_name
+      - name: oka_type
+      - name: project_name
+      - name: tarball_file
+      - name: debug
+      - name: dry_run
+    steps:
+    # ------ Preparations for transaction
+    - - name: generate-sw-catalogs-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+    - - name: clone-sw-catalogs
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/sw-catalogs"
+          - name: repo_url
+            value: "{{inputs.parameters.git_sw_catalogs_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.sw_catalogs_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_sw_catalogs_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+    # ------ end of preparations for transaction
+
+    # ------ Transformations
+    - - name: create-oka
+        templateRef:
+          name: oka-management-wft
+          template: create-oka
+        arguments:
+          parameters:
+          # References to required external resources
+          - name: sw_catalogs_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+          - name: temp_volume_name
+            value: "{{inputs.parameters.temp_volume_name}}"
+          # Specific parameters
+          - name: oka_name
+            value: "{{inputs.parameters.oka_name}}"
+          - name: oka_type
+            value: "{{inputs.parameters.oka_type}}"
+          - name: project_name
+            value: "{{inputs.parameters.project_name}}"
+          - name: tarball_file
+            value: "{{inputs.parameters.tarball_file}}"
+          # Debug?
+          - name: debug
+            value: "{{inputs.parameters.debug}}"
+    # ------ end of transformations
+
+    # ------ Commit transaction
+    - - name: push-to-sw-catalogs
+        templateRef:
+          name: git-wft
+          template: git-commit-merge-push
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/sw-catalogs"
+          - name: repo_folder
+            value: "{{inputs.parameters.sw_catalogs_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_sw_catalogs_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+          - name: commit_message
+            value: "Create OKA {{inputs.parameters.oka_name}} of {{inputs.parameters.oka_type}} type @ {{inputs.parameters.project_name}} project"
+          - name: main_branch
+            value: main
+          - name: contrib_branch
+            value: osm_contrib
+          - name: dry_run
+            value: "{{inputs.parameters.dry_run}}"
+# ------ end of commit transaction
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-create-profile.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-create-profile.yaml
new file mode 100644 (file)
index 0000000..b9b63ea
--- /dev/null
@@ -0,0 +1,146 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: full-create-profile-wft
+  namespace: osm-workflows
+
+spec:
+  arguments:
+    parameters:
+
+    # Fleet repo
+    - name: git_fleet_url
+    - name: fleet_destination_folder
+    - name: git_fleet_cred_secret
+
+    # Specific parameters
+    - name: profile_name
+    - name: profile_type
+    - name: project_name
+      value: "osm_admin"
+
+    # Debugging
+    - name: dry_run
+      value: false
+
+
+  # # Cleanup policy
+  # ttlStrategy:
+  #   secondsAfterCompletion: 100 # Time to live after workflow is completed, replaces ttlSecondsAfterFinished
+  #   secondsAfterSuccess: 50     # Time to live after workflow is successful
+  #   secondsAfterFailure: 50     # Time to live after workflow fails
+
+  entrypoint: create-profile
+
+  templates:
+
+  # Main template
+  - name: create-profile
+    inputs:
+      parameters:
+      # Git repos
+      - name: git_fleet_url
+      - name: fleet_destination_folder
+      - name: git_fleet_cred_secret
+
+      # Specific parameters
+      - name: profile_name
+      - name: profile_type
+      - name: project_name
+
+      # Debugging
+      - name: dry_run
+    steps:
+
+    # ------ Preparations for transaction
+    - - name: generate-fleet-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+    - - name: clone-fleet
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+    # ------ end of preparations for transaction
+
+    # ------ Transformations
+    # Create profile
+    - - name: create-profile
+        templateRef:
+          name: profile-management-wft
+          template: create-profile
+        arguments:
+          parameters:
+          # Volumes with cloned repos
+          - name: fleet_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: fleet_mount_path
+            value: "/fleet"
+          # Specific parameters
+          - name: profile_name
+            value: "{{inputs.parameters.profile_name}}"
+          - name: profile_type
+            value: "{{inputs.parameters.profile_type}}"
+          - name: project_name
+            value: "{{inputs.parameters.project_name}}"
+          - name: fleet_repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+    # ------ end of transformations
+
+    # ------ Commit transaction
+    - - name: push-to-fleet
+        templateRef:
+          name: git-wft
+          template: git-commit-merge-push
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: commit_message
+            value: "Create profile {{inputs.parameters.profile_name}} of type {{inputs.parameters.profile_type}}"
+          - name: main_branch
+            value: main
+          - name: contrib_branch
+            value: osm_contrib
+          - name: dry_run
+            value: "{{inputs.parameters.dry_run}}"
+# ------ end of commit transaction
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-create-providerconfig-wft.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-create-providerconfig-wft.yaml
new file mode 100644 (file)
index 0000000..eb95a9b
--- /dev/null
@@ -0,0 +1,207 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: full-create-crossplane-providerconfig
+  namespace: osm-workflows
+
+spec:
+  arguments:
+    parameters:
+    # Fleet repo
+    - name: git_fleet_url
+    - name: fleet_destination_folder
+    - name: git_fleet_cred_secret
+    # SW-Catalogs repo
+    - name: git_sw_catalogs_url
+    - name: sw_catalogs_destination_folder
+    - name: git_sw_catalogs_cred_secret
+
+    # Specific parameters
+    - name: providerconfig_name
+    ## As of today, one among `azure`, `aws` or `gcp`
+    - name: provider_type
+    ## Final secret to reference from the `ProviderConfig`
+    - name: cred_secret_name
+    ## Temporary secret with secret contents for the workflow
+    ## - If `temp_cred_secret_name` is empty, assumes that the final secret already exists
+    - name: temp_cred_secret_name
+      value: ""
+    - name: temp_cred_secret_key
+      value: "creds"
+    - name: age_public_key_mgmt
+    - name: osm_project_name
+      value: "osm_admin"
+    ## Specific parameters - GCP only
+    - name: target_gcp_project
+      value: ""
+    # Debug/dry run?
+    - name: debug
+      value: "false"
+    - name: dry_run
+      value: "false"
+
+  # Cleanup policy
+  ttlStrategy:
+    secondsAfterCompletion: 6000  # Time to live after workflow is completed, replaces ttlSecondsAfterFinished
+    secondsAfterSuccess: 6000     # Time to live after workflow is successful
+    secondsAfterFailure: 9000     # Time to live after workflow fails
+
+  entrypoint: create-crossplane-providerconfig
+
+  templates:
+
+  # Main template
+  - name: create-crossplane-providerconfig
+    inputs:
+      parameters:
+      # Fleet repo
+      - name: git_fleet_url
+      - name: fleet_destination_folder
+      - name: git_fleet_cred_secret
+      # SW-Catalogs repo
+      - name: git_sw_catalogs_url
+      - name: sw_catalogs_destination_folder
+      - name: git_sw_catalogs_cred_secret
+      # Specific parameters
+      - name: providerconfig_name
+      - name: provider_type
+      - name: cred_secret_name
+      - name: temp_cred_secret_name
+      - name: temp_cred_secret_key
+      - name: age_public_key_mgmt
+      - name: osm_project_name
+      - name: target_gcp_project
+      # Debug/dry run?
+      - name: debug
+        value: "false"
+      - name: dry_run
+        value: "false"
+
+    steps:
+
+    # ------ Preparations for transaction
+    - - name: generate-fleet-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+      - name: generate-sw-catalogs-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+    - - name: clone-fleet
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+      - name: clone-sw-catalogs
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/sw-catalogs"
+          - name: repo_url
+            value: "{{inputs.parameters.git_sw_catalogs_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.sw_catalogs_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_sw_catalogs_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+    # ------ end of preparations for transaction
+
+    # ------ Transformations
+    - - name: create-crossplane-providerconfig
+        templateRef:
+          name: cloud-accounts-wft
+          template: create-crossplane-providerconfig
+        arguments:
+          parameters:
+          # References to required external resources
+          - name: fleet_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: sw_catalogs_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+          # Specific parameters
+          - name: providerconfig_name
+            value: "{{inputs.parameters.providerconfig_name}}"
+          - name: provider_type
+            value: "{{inputs.parameters.provider_type}}"
+          - name: cred_secret_name
+            value: "{{inputs.parameters.cred_secret_name}}"
+          - name: temp_cred_secret_name
+            value: "{{inputs.parameters.temp_cred_secret_name}}"
+          - name: temp_cred_secret_key
+            value: "{{inputs.parameters.temp_cred_secret_key}}"
+          - name: age_public_key_mgmt
+            value: "{{inputs.parameters.age_public_key_mgmt}}"
+          - name: osm_project_name
+            value: "{{inputs.parameters.osm_project_name}}"
+          - name: target_gcp_project
+            value: "{{inputs.parameters.target_gcp_project}}"
+          # Debug?
+          - name: debug
+            value: "{{inputs.parameters.debug}}"
+    # ------ end of transformations
+
+    # ------ Commit transaction
+    - - name: push-to-fleet
+        templateRef:
+          name: git-wft
+          template: git-commit-merge-push
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: commit_message
+            value: "Create ProviderConfig {{inputs.parameters.providerconfig_name}} for {{inputs.parameters.provider_type}}"
+          - name: main_branch
+            value: main
+          - name: contrib_branch
+            value: osm_contrib
+          - name: dry_run
+            value: "{{inputs.parameters.dry_run}}"
+# ------ end of commit transaction
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-delete-cluster-wft.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-delete-cluster-wft.yaml
new file mode 100644 (file)
index 0000000..7ef0dc2
--- /dev/null
@@ -0,0 +1,140 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: full-delete-cluster-wft
+  namespace: osm-workflows
+
+spec:
+  arguments:
+    parameters:
+
+    # Fleet repo
+    - name: git_fleet_url
+    - name: fleet_destination_folder
+    - name: git_fleet_cred_secret
+
+    # Specific parameters
+    - name: cluster_kustomization_name
+    - name: project_name
+      value: "osm_admin"
+
+    # Debugging
+    - name: dry_run
+      value: false
+
+
+  # # Cleanup policy
+  # ttlStrategy:
+  #   secondsAfterCompletion: 100 # Time to live after workflow is completed, replaces ttlSecondsAfterFinished
+  #   secondsAfterSuccess: 50     # Time to live after workflow is successful
+  #   secondsAfterFailure: 50     # Time to live after workflow fails
+
+  entrypoint: delete-cluster
+
+  templates:
+
+  # Main template
+  - name: delete-cluster
+    inputs:
+      parameters:
+      # Git repos
+      - name: git_fleet_url
+      - name: fleet_destination_folder
+      - name: git_fleet_cred_secret
+
+      # Specific parameters
+      - name: cluster_kustomization_name
+      - name: project_name
+
+      # Debugging
+      - name: dry_run
+
+    steps:
+
+    # ------ Preparations for transaction
+    - - name: generate-fleet-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+    - - name: clone-fleet
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+    # ------ end of preparations for transaction
+
+    # ------ Transformations
+    - - name: delete-cluster
+        templateRef:
+          name: cluster-management-wft
+          template: delete-cluster
+        arguments:
+          parameters:
+          # Volumes with cloned repos
+          - name: fleet_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: fleet_mount_path
+            value: "/fleet"
+          # Specific parameters
+          - name: cluster_kustomization_name
+            value: "{{inputs.parameters.cluster_kustomization_name}}"
+          - name: project_name
+            value: "{{inputs.parameters.project_name}}"
+    # ------ end of transformations
+
+    # ------ Commit transaction
+    - - name: push-to-fleet
+        templateRef:
+          name: git-wft
+          template: git-commit-merge-push
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: commit_message
+            value: "Delete cluster {{inputs.parameters.cluster_kustomization_name}}"
+          - name: main_branch
+            value: main
+          - name: contrib_branch
+            value: osm_contrib
+          - name: dry_run
+            value: "{{inputs.parameters.dry_run}}"
+# ------ end of commit transaction
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-delete-ksu.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-delete-ksu.yaml
new file mode 100644 (file)
index 0000000..b933cc9
--- /dev/null
@@ -0,0 +1,176 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: full-delete-ksu-wtf
+  namespace: osm-workflows
+spec:
+  arguments:
+    parameters:
+    # Fleet repo
+    - name: git_fleet_url
+    - name: fleet_destination_folder
+    - name: git_fleet_cred_secret
+    # SW-Catalogs repo
+    - name: git_sw_catalogs_url
+    - name: sw_catalogs_destination_folder
+    - name: git_sw_catalogs_cred_secret
+    # Specific parameters - KSU id
+    - name: ksu_name
+    - name: profile_name
+    - name: profile_type
+    - name: project_name
+    # Debug/dry run?
+    - name: debug
+      value: "false"
+    - name: dry_run
+      value: "false"
+
+  # Cleanup policy
+  ttlStrategy:
+    secondsAfterCompletion: 6000  # Time to live after workflow is completed, replaces ttlSecondsAfterFinished
+    secondsAfterSuccess: 6000     # Time to live after workflow is successful
+    secondsAfterFailure: 9000     # Time to live after workflow fails
+
+  entrypoint: delete-ksu
+
+  templates:
+  # Main template
+  - name: delete-ksu
+    inputs:
+      parameters:
+      # Fleet repo
+      - name: git_fleet_url
+      - name: fleet_destination_folder
+      - name: git_fleet_cred_secret
+      # SW-Catalogs repo
+      - name: git_sw_catalogs_url
+      - name: sw_catalogs_destination_folder
+      - name: git_sw_catalogs_cred_secret
+      # Specific parameters - KSU id
+      - name: ksu_name
+      - name: profile_name
+      - name: profile_type
+      - name: project_name
+      # Debug/dry run?
+      - name: debug
+      - name: dry_run
+
+    steps:
+    # ------ Preparations for transaction
+    - - name: generate-fleet-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+      - name: generate-sw-catalogs-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+    - - name: clone-fleet
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+      - name: clone-sw-catalogs
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/sw-catalogs"
+          - name: repo_url
+            value: "{{inputs.parameters.git_sw_catalogs_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.sw_catalogs_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_sw_catalogs_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+    # ------ end of preparations for transaction
+
+    # ------ Transformations
+    - - name: delete-ksu
+        templateRef:
+          name: ksu-management-wft
+          template: delete-ksu
+        arguments:
+          parameters:
+          # References to required external resources
+          - name: fleet_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: sw_catalogs_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+          # Specific parameters - KSU id
+          - name: ksu_name
+            value: "{{inputs.parameters.ksu_name}}"
+          - name: profile_name
+            value: "{{inputs.parameters.profile_name}}"
+          - name: profile_type
+            value: "{{inputs.parameters.profile_type}}"
+          - name: project_name
+            value: "{{inputs.parameters.project_name}}"
+          # Debug?
+          - name: debug
+            value: "{{inputs.parameters.debug}}"
+    # ------ end of transformations
+
+    # ------ Commit transaction
+    - - name: push-to-fleet
+        templateRef:
+          name: git-wft
+          template: git-commit-merge-push
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: commit_message
+            value: "Delete KSU {{inputs.parameters.ksu_name}} from {{inputs.parameters.profile_name}} profile of {{inputs.parameters.profile_type}} type @ {{inputs.parameters.project_name}} project"
+          - name: main_branch
+            value: main
+          - name: contrib_branch
+            value: osm_contrib
+          - name: dry_run
+            value: "{{inputs.parameters.dry_run}}"
+# ------ end of commit transaction
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-delete-oka.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-delete-oka.yaml
new file mode 100644 (file)
index 0000000..c39c595
--- /dev/null
@@ -0,0 +1,136 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: full-delete-oka-wtf
+  namespace: osm-workflows
+spec:
+  arguments:
+    parameters:
+    # SW-Catalogs repo
+    - name: git_sw_catalogs_url
+    - name: sw_catalogs_destination_folder
+    - name: git_sw_catalogs_cred_secret
+    # Specific parameters - OKA
+    - name: oka_name
+    ## Choose among `infra-controllers`, `infra-configs`, `cloud-resources`, `apps`:
+    - name: oka_type
+    - name: project_name
+      value: "osm_admin"
+    # Debug/dry run?
+    - name: debug
+      value: "false"
+    - name: dry_run
+      value: "false"
+
+  # Cleanup policy
+  ttlStrategy:
+    secondsAfterCompletion: 6000  # Time to live after workflow is completed, replaces ttlSecondsAfterFinished
+    secondsAfterSuccess: 6000     # Time to live after workflow is successful
+    secondsAfterFailure: 9000     # Time to live after workflow fails
+
+  entrypoint: delete-oka
+
+  templates:
+  # Main template
+  - name: delete-oka
+    inputs:
+      parameters:
+      - name: git_sw_catalogs_url
+      - name: sw_catalogs_destination_folder
+      - name: git_sw_catalogs_cred_secret
+      - name: oka_name
+      - name: oka_type
+      - name: project_name
+      - name: debug
+      - name: dry_run
+    steps:
+    # ------ Preparations for transaction
+    - - name: generate-sw-catalogs-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+    - - name: clone-sw-catalogs
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/sw-catalogs"
+          - name: repo_url
+            value: "{{inputs.parameters.git_sw_catalogs_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.sw_catalogs_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_sw_catalogs_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+    # ------ end of preparations for transaction
+
+    # ------ Transformations
+    - - name: delete-oka
+        templateRef:
+          name: oka-management-wft
+          template: delete-oka
+        arguments:
+          parameters:
+          # References to required external resources
+          - name: sw_catalogs_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+          # Specific parameters
+          - name: oka_name
+            value: "{{inputs.parameters.oka_name}}"
+          - name: oka_type
+            value: "{{inputs.parameters.oka_type}}"
+          - name: project_name
+            value: "{{inputs.parameters.project_name}}"
+          # Debug?
+          - name: debug
+            value: "{{inputs.parameters.debug}}"
+    # ------ end of transformations
+
+    # ------ Commit transaction
+    - - name: push-to-sw-catalogs
+        templateRef:
+          name: git-wft
+          template: git-commit-merge-push
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/sw-catalogs"
+          - name: repo_folder
+            value: "{{inputs.parameters.sw_catalogs_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_sw_catalogs_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+          - name: commit_message
+            value: "Delete OKA {{inputs.parameters.oka_name}} of {{inputs.parameters.oka_type}} type @ {{inputs.parameters.project_name}} project"
+          - name: main_branch
+            value: main
+          - name: contrib_branch
+            value: osm_contrib
+          - name: dry_run
+            value: "{{inputs.parameters.dry_run}}"
+# ------ end of commit transaction
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-delete-profile.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-delete-profile.yaml
new file mode 100644 (file)
index 0000000..8f127d2
--- /dev/null
@@ -0,0 +1,144 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: full-delete-profile-wft
+  namespace: osm-workflows
+
+spec:
+  arguments:
+    parameters:
+
+    # Fleet repo
+    - name: git_fleet_url
+    - name: fleet_destination_folder
+    - name: git_fleet_cred_secret
+
+    # Specific parameters
+    - name: profile_name
+    - name: profile_type
+    - name: project_name
+      value: "osm_admin"
+
+    # Debugging
+    - name: dry_run
+      value: false
+
+
+  # # Cleanup policy
+  # ttlStrategy:
+  #   secondsAfterCompletion: 100 # Time to live after workflow is completed, replaces ttlSecondsAfterFinished
+  #   secondsAfterSuccess: 50     # Time to live after workflow is successful
+  #   secondsAfterFailure: 50     # Time to live after workflow fails
+
+  entrypoint: delete-profile
+
+  templates:
+
+  # Main template
+  - name: delete-profile
+    inputs:
+      parameters:
+      # Git repos
+      - name: git_fleet_url
+      - name: fleet_destination_folder
+      - name: git_fleet_cred_secret
+
+      # Specific parameters
+      - name: profile_name
+      - name: profile_type
+      - name: project_name
+
+      # Debugging
+      - name: dry_run
+    steps:
+
+    # ------ Preparations for transaction
+    - - name: generate-fleet-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+    - - name: clone-fleet
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+    # ------ end of preparations for transaction
+
+    # ------ Transformations
+    # Delete profile
+    - - name: delete-profile
+        templateRef:
+          name: profile-management-wft
+          template: delete-profile
+        arguments:
+          parameters:
+          # Volumes with cloned repos
+          - name: fleet_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: fleet_mount_path
+            value: "/fleet"
+          # Specific parameters
+          - name: profile_name
+            value: "{{inputs.parameters.profile_name}}"
+          - name: profile_type
+            value: "{{inputs.parameters.profile_type}}"
+          - name: project_name
+            value: "{{inputs.parameters.project_name}}"
+    # ------ end of transformations
+
+    # ------ Commit transaction
+    - - name: push-to-fleet
+        templateRef:
+          name: git-wft
+          template: git-commit-merge-push
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: commit_message
+            value: "Delete profile {{inputs.parameters.profile_name}} of type {{inputs.parameters.profile_type}}"
+          - name: main_branch
+            value: main
+          - name: contrib_branch
+            value: osm_contrib
+          - name: dry_run
+            value: "{{inputs.parameters.dry_run}}"
+# ------ end of commit transaction
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-delete-providerconfig-wft.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-delete-providerconfig-wft.yaml
new file mode 100644 (file)
index 0000000..6a59d34
--- /dev/null
@@ -0,0 +1,180 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: full-delete-crossplane-providerconfig
+  namespace: osm-workflows
+
+spec:
+  arguments:
+    parameters:
+    # Fleet repo
+    - name: git_fleet_url
+    - name: fleet_destination_folder
+    - name: git_fleet_cred_secret
+    # SW-Catalogs repo
+    - name: git_sw_catalogs_url
+    - name: sw_catalogs_destination_folder
+    - name: git_sw_catalogs_cred_secret
+
+    # Specific parameters
+    - name: providerconfig_name
+    ## As of today, one among `azure`, `aws` or `gcp`
+    - name: provider_type
+    - name: osm_project_name
+      value: "osm_admin"
+    # Debug/dry run?
+    - name: debug
+      value: "false"
+    - name: dry_run
+      value: "false"
+
+  # Cleanup policy
+  ttlStrategy:
+    secondsAfterCompletion: 6000  # Time to live after workflow is completed, replaces ttlSecondsAfterFinished
+    secondsAfterSuccess: 6000     # Time to live after workflow is successful
+    secondsAfterFailure: 9000     # Time to live after workflow fails
+
+  entrypoint: delete-crossplane-providerconfig
+
+  templates:
+
+  # Main template
+  - name: delete-crossplane-providerconfig
+    inputs:
+      parameters:
+      # Fleet repo
+      - name: git_fleet_url
+      - name: fleet_destination_folder
+      - name: git_fleet_cred_secret
+      # SW-Catalogs repo
+      - name: git_sw_catalogs_url
+      - name: sw_catalogs_destination_folder
+      - name: git_sw_catalogs_cred_secret
+      # Specific parameters
+      - name: providerconfig_name
+      - name: provider_type
+      - name: osm_project_name
+      # Debug/dry run?
+      - name: debug
+        value: "false"
+      - name: dry_run
+        value: "false"
+
+    steps:
+
+    # ------ Preparations for transaction
+    - - name: generate-fleet-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+      - name: generate-sw-catalogs-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+    - - name: clone-fleet
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+      - name: clone-sw-catalogs
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/sw-catalogs"
+          - name: repo_url
+            value: "{{inputs.parameters.git_sw_catalogs_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.sw_catalogs_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_sw_catalogs_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+    # ------ end of preparations for transaction
+
+    # ------ Transformations
+    - - name: delete-crossplane-providerconfig
+        templateRef:
+          name: cloud-accounts-wft
+          template: delete-crossplane-providerconfig
+        arguments:
+          parameters:
+          # References to required external resources
+          - name: fleet_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: sw_catalogs_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+          # Specific parameters
+          - name: providerconfig_name
+            value: "{{inputs.parameters.providerconfig_name}}"
+          - name: provider_type
+            value: "{{inputs.parameters.provider_type}}"
+          - name: osm_project_name
+            value: "{{inputs.parameters.osm_project_name}}"
+          # Debug?
+          - name: debug
+            value: "{{inputs.parameters.debug}}"
+    # ------ end of transformations
+
+    # ------ Commit transaction
+    - - name: push-to-fleet
+        templateRef:
+          name: git-wft
+          template: git-commit-merge-push
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: commit_message
+            value: "Delete ProviderConfig {{inputs.parameters.providerconfig_name}} for {{inputs.parameters.provider_type}}"
+          - name: main_branch
+            value: main
+          - name: contrib_branch
+            value: osm_contrib
+          - name: dry_run
+            value: "{{inputs.parameters.dry_run}}"
+# ------ end of commit transaction
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-detach-profile.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-detach-profile.yaml
new file mode 100644 (file)
index 0000000..9d56489
--- /dev/null
@@ -0,0 +1,150 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: full-detach-profile-wft
+  namespace: osm-workflows
+
+spec:
+  arguments:
+    parameters:
+
+    # Fleet repo
+    - name: git_fleet_url
+    - name: fleet_destination_folder
+    - name: git_fleet_cred_secret
+
+    # Specific parameters
+    - name: profile_name
+    - name: profile_type
+    - name: project_name
+      value: "osm_admin"
+    - name: cluster_kustomization_name
+
+    # Debugging
+    - name: dry_run
+      value: false
+
+
+  # # Cleanup policy
+  # ttlStrategy:
+  #   secondsAfterCompletion: 100 # Time to live after workflow is completed, replaces ttlSecondsAfterFinished
+  #   secondsAfterSuccess: 50     # Time to live after workflow is successful
+  #   secondsAfterFailure: 50     # Time to live after workflow fails
+
+  entrypoint: detach-profile
+
+  templates:
+
+  # Main template
+  - name: detach-profile
+    inputs:
+      parameters:
+      # Git repos
+      - name: git_fleet_url
+      - name: fleet_destination_folder
+      - name: git_fleet_cred_secret
+
+      # Specific parameters
+      - name: profile_name
+      - name: profile_type
+      - name: project_name
+      - name: cluster_kustomization_name
+
+      # Debugging
+      - name: dry_run
+    steps:
+
+    # ------ Preparations for transaction
+    - - name: generate-fleet-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+    - - name: clone-fleet
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+    # ------ end of preparations for transaction
+
+    # ------ Transformations
+    # Detach profile from cluster
+    - - name: detach-profile
+        templateRef:
+          name: profile-management-wft
+          template: detach-profile-from-cluster
+        arguments:
+          parameters:
+          # Volumes with cloned repos
+          - name: fleet_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: fleet_mount_path
+            value: "/fleet"
+          # Specific parameters
+          - name: profile_name
+            value: "{{inputs.parameters.profile_name}}"
+          - name: profile_type
+            value: "{{inputs.parameters.profile_type}}"
+          - name: project_name
+            value: "{{inputs.parameters.project_name}}"
+          - name: fleet_repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+          - name: cluster_kustomization_name
+            value: "{{inputs.parameters.cluster_kustomization_name}}"
+    # ------ end of transformations
+
+    # ------ Commit transaction
+    - - name: push-to-fleet
+        templateRef:
+          name: git-wft
+          template: git-commit-merge-push
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: commit_message
+            value: "Detach {{inputs.parameters.profile_name}} profile from {{inputs.parameters.cluster_kustomization_name}} cluster"
+          - name: main_branch
+            value: main
+          - name: contrib_branch
+            value: osm_contrib
+          - name: dry_run
+            value: "{{inputs.parameters.dry_run}}"
+# ------ end of commit transaction
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-disconnect-flux-remote-cluster-wft.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-disconnect-flux-remote-cluster-wft.yaml
new file mode 100644 (file)
index 0000000..d2daa5b
--- /dev/null
@@ -0,0 +1,142 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: full-disconnect-flux-remote-cluster-wft
+  namespace: osm-workflows
+
+spec:
+  arguments:
+    parameters:
+
+    # Fleet repo
+    - name: git_fleet_url
+    - name: fleet_destination_folder
+    - name: git_fleet_cred_secret
+
+    # Specific parameters
+    - name: cluster_kustomization_name
+    - name: mgmt_project_name
+      value: "osm_admin"
+
+    # Debug/dry run?
+    - name: debug
+      value: "false"
+    - name: dry_run
+      value: "false"
+
+
+  # # Cleanup policy
+  # ttlStrategy:
+  #   secondsAfterCompletion: 100 # Time to live after workflow is completed, replaces ttlSecondsAfterFinished
+  #   secondsAfterSuccess: 50     # Time to live after workflow is successful
+  #   secondsAfterFailure: 50     # Time to live after workflow fails
+
+  entrypoint: disconnect-remote-cluster
+
+  templates:
+
+  # Main template
+  - name: disconnect-remote-cluster
+    inputs:
+      parameters:
+      # Git repos
+      - name: git_fleet_url
+      - name: fleet_destination_folder
+      - name: git_fleet_cred_secret
+
+      # Specific parameters
+      - name: cluster_kustomization_name
+      - name: mgmt_project_name
+
+      # Debugging
+      - name: debug
+      - name: dry_run
+    steps:
+
+    # ------ Preparations for transaction
+    - - name: generate-fleet-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+    - - name: clone-fleet
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+    # ------ end of preparations for transaction
+
+    # ------ Transformations
+    # Disconnect the remote cluster
+    - - name: disconnect-flux-remote-cluster
+        templateRef:
+          name: cluster-management-wft
+          template: disconnect-flux-remote-cluster
+        arguments:
+          parameters:
+          # Volumes with cloned repos
+          - name: fleet_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+
+          # Specific parameters
+          - name: cluster_kustomization_name
+            value: "{{inputs.parameters.cluster_kustomization_name}}"
+          - name: mgmt_project_name
+            value: "{{inputs.parameters.mgmt_project_name}}"
+    # ------ end of transformations
+
+    # ------ Commit transaction
+    - - name: push-to-fleet
+        templateRef:
+          name: git-wft
+          template: git-commit-merge-push
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: commit_message
+            value: "Disconnect imported cluster {{inputs.parameters.cluster_kustomization_name}}"
+          - name: main_branch
+            value: main
+          - name: contrib_branch
+            value: osm_contrib
+          - name: dry_run
+            value: "{{inputs.parameters.dry_run}}"
+# ------ end of commit transaction
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-update-aks-cluster.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-update-aks-cluster.yaml
new file mode 100644 (file)
index 0000000..711cf4d
--- /dev/null
@@ -0,0 +1,199 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: full-update-aks-cluster-wft
+  namespace: osm-workflows
+
+spec:
+  arguments:
+    parameters:
+
+    # Fleet repo
+    - name: git_fleet_url
+    - name: fleet_destination_folder
+    - name: git_fleet_cred_secret
+
+    # SW-Catalogs repo
+    - name: git_sw_catalogs_url
+    - name: sw_catalogs_destination_folder
+    - name: git_sw_catalogs_cred_secret
+
+    # Specific parameters - AKS cluster
+    - name: cluster_name
+    - name: vm_size
+    - name: node_count
+    - name: cluster_location
+    - name: rg_name
+    - name: k8s_version
+    - name: providerconfig_name
+    - name: cluster_kustomization_name
+
+    # Debugging
+    - name: dry_run
+      value: false
+
+
+  # # Cleanup policy
+  # ttlStrategy:
+  #   secondsAfterCompletion: 100 # Time to live after workflow is completed, replaces ttlSecondsAfterFinished
+  #   secondsAfterSuccess: 50     # Time to live after workflow is successful
+  #   secondsAfterFailure: 50     # Time to live after workflow fails
+
+  entrypoint: update-aks-cluster
+
+  templates:
+
+  # Main template
+  - name: update-aks-cluster
+    inputs:
+      parameters:
+      # Git repos
+      - name: git_fleet_url
+      - name: fleet_destination_folder
+      - name: git_fleet_cred_secret
+      - name: git_sw_catalogs_url
+      - name: sw_catalogs_destination_folder
+      - name: git_sw_catalogs_cred_secret
+
+      # Specific parameters - AKS cluster
+      - name: cluster_name
+      - name: vm_size
+      - name: node_count
+      - name: cluster_location
+      - name: rg_name
+      - name: k8s_version
+      - name: providerconfig_name
+      - name: cluster_kustomization_name
+
+      # Debugging
+      - name: dry_run
+    steps:
+
+    # ------ Preparations for transaction
+    - - name: generate-fleet-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+      - name: generate-sw-catalogs-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+    - - name: clone-fleet
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+      - name: clone-sw-catalogs
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/sw-catalogs"
+          - name: repo_url
+            value: "{{inputs.parameters.git_sw_catalogs_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.sw_catalogs_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_sw_catalogs_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+    # ------ end of preparations for transaction
+
+    # ------ Transformations
+    # Update cluster definition
+    - - name: update-cluster-aks
+        templateRef:
+          name: cluster-management-wft
+          template: create-cluster-aks
+        arguments:
+          parameters:
+          # Volumes with cloned repos
+          - name: fleet_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: fleet_mount_path
+            value: "/fleet"
+          - name: sw_catalogs_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+          - name: sw_catalogs_mount_path
+            value: "/sw-catalogs"
+          # Specific parameters
+          - name: cluster_name
+            value: "{{inputs.parameters.cluster_name}}"
+          - name: vm_size
+            value: "{{inputs.parameters.vm_size}}"
+          - name: node_count
+            value: "{{inputs.parameters.node_count}}"
+          - name: cluster_location
+            value: "{{inputs.parameters.cluster_location}}"
+          - name: rg_name
+            value: "{{inputs.parameters.rg_name}}"
+          - name: k8s_version
+            value: "{{inputs.parameters.k8s_version}}"
+          - name: providerconfig_name
+            value: "{{inputs.parameters.providerconfig_name}}"
+          - name: cluster_kustomization_name
+            value: "{{inputs.parameters.cluster_kustomization_name}}"
+    # ------ end of transformations
+
+    # ------ Commit transaction
+    - - name: push-to-fleet
+        templateRef:
+          name: git-wft
+          template: git-commit-merge-push
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: commit_message
+            value: "Update AKS cluster {{inputs.parameters.cluster_kustomization_name}}"
+          - name: main_branch
+            value: main
+          - name: contrib_branch
+            value: osm_contrib
+          - name: dry_run
+            value: "{{inputs.parameters.dry_run}}"
+# ------ end of commit transaction
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-update-crossplane-cluster-and-bootstrap-wft.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-update-crossplane-cluster-and-bootstrap-wft.yaml
new file mode 100644 (file)
index 0000000..3e661c4
--- /dev/null
@@ -0,0 +1,284 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: full-update-crossplane-cluster-and-bootstrap-wft
+  namespace: osm-workflows
+
+spec:
+  arguments:
+    parameters:
+
+    # Fleet repo
+    - name: git_fleet_url
+    - name: fleet_destination_folder
+    - name: git_fleet_cred_secret
+
+    # SW-Catalogs repo
+    - name: git_sw_catalogs_url
+    - name: sw_catalogs_destination_folder
+    - name: git_sw_catalogs_cred_secret
+
+    # Specific parameters - Generic cluster creation
+    - name: cluster_kustomization_name
+    - name: cluster_name
+    - name: cluster_type
+    - name: providerconfig_name
+    - name: vm_size
+    - name: node_count
+    - name: cluster_location
+    - name: k8s_version
+
+    # Specific parameters - Bootstrap and credentials
+    - name: public_key_mgmt
+    - name: public_key_new_cluster
+    - name: secret_name_private_age_key_for_new_cluster
+    - name: key_name_in_secret
+      value: "agekey"
+    # Using `git_fleet_url` instead:
+    # - name: fleet_repo_url
+    # Using `git_sw_catalogs_url` instead:
+    # - name: sw_catalogs_repo_url
+    - name: mgmt_project_name
+      value: "osm_admin"
+
+    # Specific parameters - AKS only
+    - name: rg_name
+      values: ""
+
+    # Specific parameters - GKE only
+    - name: preemptible_nodes
+      values: "false"
+
+    # Advanced parameters - Recommended to keep defaults
+    - name: mgmt_cluster_name
+      value: "_management"
+    - name: base_templates_path
+      value: "cloud-resources"
+    - name: cloned_fleet_folder_name
+      value: "fleet-osm"
+    - name: cloned_sw_catalogs_folder_name
+      value: "sw-catalogs-osm"
+
+    # Debug/dry run?
+    - name: debug
+      value: "false"
+    - name: dry_run
+      value: "false"
+
+
+  # # Cleanup policy
+  # ttlStrategy:
+  #   secondsAfterCompletion: 100 # Time to live after workflow is completed, replaces ttlSecondsAfterFinished
+  #   secondsAfterSuccess: 50     # Time to live after workflow is successful
+  #   secondsAfterFailure: 50     # Time to live after workflow fails
+
+  entrypoint: update-cluster-and-bootstrap
+
+  templates:
+  # Main template
+  - name: update-cluster-and-bootstrap
+    inputs:
+      parameters:
+      # Fleet repo
+      - name: git_fleet_url
+      - name: fleet_destination_folder
+      - name: git_fleet_cred_secret
+      # SW-Catalogs repo
+      - name: git_sw_catalogs_url
+      - name: sw_catalogs_destination_folder
+      - name: git_sw_catalogs_cred_secret
+      # Specific parameters
+      - name: cluster_kustomization_name
+      - name: cluster_name
+      - name: cluster_type
+      - name: providerconfig_name
+      - name: vm_size
+      - name: node_count
+      - name: cluster_location
+      - name: k8s_version
+      - name: public_key_mgmt
+      - name: public_key_new_cluster
+      - name: secret_name_private_age_key_for_new_cluster
+      - name: key_name_in_secret
+      # - name: fleet_repo_url
+      # - name: sw_catalogs_repo_url
+      - name: mgmt_project_name
+      # - name: skip_bootstrap
+      ## AKS only (otherwise, ignored)
+      - name: rg_name
+      ## GKE only (otherwise, ignored)
+      - name: preemptible_nodes
+      # Other parameters - Recommended to keep defaults
+      - name: mgmt_cluster_name
+      - name: base_templates_path
+      - name: cloned_fleet_folder_name
+      - name: cloned_sw_catalogs_folder_name
+      # Debug/dry run?
+      - name: debug
+      - name: dry_run
+
+    steps:
+    # ------ Preparations for transaction
+    - - name: generate-fleet-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+      - name: generate-sw-catalogs-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+    - - name: clone-fleet
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+      - name: clone-sw-catalogs
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/sw-catalogs"
+          - name: repo_url
+            value: "{{inputs.parameters.git_sw_catalogs_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.sw_catalogs_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_sw_catalogs_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+    # ------ end of preparations for transaction
+
+    # ------ Transformations
+    # Create cluster in target cloud
+    - - name: update-cluster
+        templateRef:
+          name: cluster-management-wft
+          template: update-crossplane-cluster
+        arguments:
+          parameters:
+          # Volumes with cloned repos
+          - name: fleet_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: fleet_mount_path
+            value: "/fleet"
+          - name: sw_catalogs_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+          - name: sw_catalogs_mount_path
+            value: "/sw-catalogs"
+          # Specific parameters
+          - name: cluster_kustomization_name
+            value: "{{inputs.parameters.cluster_kustomization_name}}"
+          - name: cluster_name
+            value: "{{inputs.parameters.cluster_name}}"
+          - name: cluster_type
+            value: "{{inputs.parameters.cluster_type}}"
+          - name: providerconfig_name
+            value: "{{inputs.parameters.providerconfig_name}}"
+          - name: vm_size
+            value: "{{inputs.parameters.vm_size}}"
+          - name: node_count
+            value: "{{inputs.parameters.node_count}}"
+          - name: cluster_location
+            value: "{{inputs.parameters.cluster_location}}"
+          - name: k8s_version
+            value: "{{inputs.parameters.k8s_version}}"
+          - name: public_key_mgmt
+            value: "{{inputs.parameters.public_key_mgmt}}"
+          - name: public_key_new_cluster
+            value: "{{inputs.parameters.public_key_new_cluster}}"
+          - name: secret_name_private_age_key_for_new_cluster
+            value: "{{inputs.parameters.secret_name_private_age_key_for_new_cluster}}"
+          - name: key_name_in_secret
+            value: "{{inputs.parameters.key_name_in_secret}}"
+          ## Fed with `git_fleet_url` to avoid duplicates
+          - name: fleet_repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+          ## Fed with `git_sw_catalogs_url` to avoid duplicates
+          - name: sw_catalogs_repo_url
+            value: "{{inputs.parameters.git_sw_catalogs_url}}"
+          - name: mgmt_project_name
+            value: "{{inputs.parameters.mgmt_project_name}}"
+          # - name: skip_bootstrap
+          #   value: "{{inputs.parameters.skip_bootstrap}}"
+          ## AKS only
+          - name: rg_name
+            value: "{{inputs.parameters.rg_name}}"
+          ## GKE only
+          - name: preemptible_nodes
+            value: "{{inputs.parameters.preemptible_nodes}}"
+          # Other parameters - Recommended to keep defaults
+          - name: mgmt_cluster_name
+            value: "{{inputs.parameters.mgmt_cluster_name}}"
+          - name: base_templates_path
+            value: "{{inputs.parameters.base_templates_path}}"
+          - name: cloned_fleet_folder_name
+            value: "{{inputs.parameters.cloned_fleet_folder_name}}"
+          - name: cloned_sw_catalogs_folder_name
+            value: "{{inputs.parameters.cloned_sw_catalogs_folder_name}}"
+          # Debug?
+          - name: debug
+            value: "{{inputs.parameters.debug}}"
+    # ------ end of transformations
+
+    # ------ Commit transaction
+    - - name: push-to-fleet
+        templateRef:
+          name: git-wft
+          template: git-commit-merge-push
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: commit_message
+            value: "Create AKS cluster {{inputs.parameters.cluster_kustomization_name}}"
+          - name: main_branch
+            value: main
+          - name: contrib_branch
+            value: osm_contrib
+          - name: dry_run
+            value: "{{inputs.parameters.dry_run}}"
+# ------ end of commit transaction
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-update-ksu-generated-hr.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-update-ksu-generated-hr.yaml
new file mode 100644 (file)
index 0000000..35f2ef3
--- /dev/null
@@ -0,0 +1,278 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: full-update-ksu-generated-hr-wtf
+  namespace: osm-workflows
+spec:
+  arguments:
+    parameters:
+    # Fleet repo
+    - name: git_fleet_url
+    - name: fleet_destination_folder
+    - name: git_fleet_cred_secret
+    # HelmRelease generation
+    - name: helmrelease_name
+    - name: chart_name
+    - name: chart_version
+    - name: target_ns
+    - name: create_ns
+    # Repo source generation
+    - name: is_preexisting_repo
+      value: "false"
+    - name: helmrepo_name
+    - name: helmrepo_url
+    - name: helmrepo_ns
+      valueFrom:
+        expression: "{{inputs.parameters.target_ns}}"
+    - name: helmrepo_secret_ref
+    # HelmRelease inline values (if any)
+    - name: inline_values
+      value: ""
+    # Secret reference and generation (if required)
+    - name: is_preexisting_secret
+      value: "false"
+    - name: values_secret_name
+    - name: secret_key
+      value: "values.yaml"
+    - name: age_public_key
+    ################################################################
+    ## A temporary secret should exist already in the `osm-workflows`
+    ## namespace containing the desired secret key-values
+    ## in a well-known key (in the example, `creds`).
+    ##
+    ## For instance:
+    ##
+    ## creds: |
+    ##     jenkinsUser: admin
+    ##     jenkinsPassword: myJ3nk1n2P2ssw0rd
+    ##
+    ## Secret values will be obtained from the
+    ## secret named after the input parameter `reference_secret_for_values`,
+    ## and from the key named after the input parameter `reference_key_for_values`
+    - name: reference_secret_for_values
+    - name: reference_key_for_values
+    # ConfigMap reference and generation (if required)
+    - name: is_preexisting_cm
+    - name: values_cm_name
+    - name: cm_key
+      value: "values.yaml"
+    - name: cm_values
+      value: ""
+    # KSU rendering
+    - name: ksu_name
+    - name: profile_name
+    - name: profile_type
+    - name: project_name
+      value: "osm_admin"
+    ## Root folder of the cloned Fleet repo - Do not touch
+    ### `FLEET_REPO_DIR` is the result of:
+    ### "{{inputs.parameters.fleet_mount_path}}/{{inputs.parameters.cloned_fleet_folder_name}}"
+    - name: cloned_fleet_folder_name
+      value: "fleet-osm"
+    # Debug/dry run?
+    - name: debug
+      value: "false"
+    - name: dry_run
+      value: "false"
+
+  # Cleanup policy
+  ttlStrategy:
+    secondsAfterCompletion: 6000  # Time to live after workflow is completed, replaces ttlSecondsAfterFinished
+    secondsAfterSuccess: 6000     # Time to live after workflow is successful
+    secondsAfterFailure: 9000     # Time to live after workflow fails
+
+  entrypoint: update-ksu-hr
+
+  templates:
+  # Main template
+  - name: update-ksu-hr
+    inputs:
+      parameters:
+      # Fleet repo
+      - name: git_fleet_url
+      - name: fleet_destination_folder
+      - name: git_fleet_cred_secret
+      # HelmRelease generation
+      - name: helmrelease_name
+      - name: chart_name
+      - name: chart_version
+      - name: target_ns
+      - name: create_ns
+      # Repo source generation
+      - name: is_preexisting_repo
+      - name: helmrepo_name
+      - name: helmrepo_url
+      - name: helmrepo_ns
+      - name: helmrepo_secret_ref
+      # HelmRelease inline values (if any)
+      - name: inline_values
+      # Secret reference and generation (if required)
+      - name: is_preexisting_secret
+      - name: values_secret_name
+      - name: secret_key
+      - name: age_public_key
+      - name: reference_secret_for_values
+      - name: reference_key_for_values
+      # ConfigMap reference and generation (if required)
+      - name: is_preexisting_cm
+      - name: values_cm_name
+      - name: cm_key
+      - name: cm_values
+      # KSU rendering
+      - name: ksu_name
+      - name: profile_name
+      - name: profile_type
+      - name: project_name
+      - name: cloned_fleet_folder_name
+      # Debug/dry run?
+      - name: debug
+        value: "false"
+      - name: dry_run
+        value: "false"
+
+    steps:
+    # ------ Preparations for transaction
+    - - name: generate-fleet-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+    - - name: clone-fleet
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+    # ------ end of preparations for transaction
+
+    # ------ Transformations
+    - - name: update-ksu-generated-hr
+        templateRef:
+          name: ksu-management-wft
+          template: update-ksu-generated-hr
+        arguments:
+          parameters:
+          # References to required external resources
+          - name: fleet_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: fleet_mount_path
+            value: "/fleet"
+          # HelmRelease generation
+          - name: helmrelease_name
+            value: "{{inputs.parameters.helmrelease_name}}"
+          - name: chart_name
+            value: "{{inputs.parameters.chart_name}}"
+          - name: chart_version
+            value: "{{inputs.parameters.chart_version}}"
+          - name: target_ns
+            value: "{{inputs.parameters.target_ns}}"
+          - name: create_ns
+            value: "{{inputs.parameters.create_ns}}"
+          # Repo source generation
+          - name: is_preexisting_repo
+            value: "{{inputs.parameters.is_preexisting_repo}}"
+          - name: helmrepo_name
+            value: "{{inputs.parameters.helmrepo_name}}"
+          - name: helmrepo_url
+            value: "{{inputs.parameters.helmrepo_url}}"
+          - name: helmrepo_ns
+            value: "{{inputs.parameters.helmrepo_ns}}"
+          - name: helmrepo_secret_ref
+            value: "{{inputs.parameters.helmrepo_secret_ref}}"
+          # HelmRelease inline values (if any)
+          - name: inline_values
+            value: "{{inputs.parameters.inline_values}}"
+          # Secret reference and generation (if required)
+          - name: is_preexisting_secret
+            value: "{{inputs.parameters.is_preexisting_secret}}"
+          - name: values_secret_name
+            value: "{{inputs.parameters.values_secret_name}}"
+          - name: secret_key
+            value: "{{inputs.parameters.secret_key}}"
+          - name: age_public_key
+            value: "{{inputs.parameters.age_public_key}}"
+          ## Secret values will be obtained from this key in this secret
+          - name: reference_secret_for_values
+            value: "{{inputs.parameters.reference_secret_for_values}}"
+          - name: reference_key_for_values
+            value: "{{inputs.parameters.reference_key_for_values}}"
+          # ConfigMap reference and generation (if required)
+          - name: is_preexisting_cm
+            value: "{{inputs.parameters.is_preexisting_cm}}"
+          - name: values_cm_name
+            value: "{{inputs.parameters.values_cm_name}}"
+          - name: cm_key
+            value: "{{inputs.parameters.cm_key}}"
+          - name: cm_values
+            value: "{{inputs.parameters.cm_values}}"
+          # KSU rendering
+          - name: ksu_name
+            value: "{{inputs.parameters.ksu_name}}"
+          - name: profile_name
+            value: "{{inputs.parameters.profile_name}}"
+          - name: profile_type
+            value: "{{inputs.parameters.profile_type}}"
+          - name: project_name
+            value: "{{inputs.parameters.project_name}}"
+          ## Root folder of the cloned Fleet repo - Do not touch
+          - name: cloned_fleet_folder_name
+            value: "{{inputs.parameters.cloned_fleet_folder_name}}"
+          # Debug?
+          - name: debug
+            value: "{{inputs.parameters.debug}}"
+    # ------ end of transformations
+
+    # ------ Commit transaction
+    - - name: push-to-fleet
+        templateRef:
+          name: git-wft
+          template: git-commit-merge-push
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: commit_message
+            value: "Update KSU {{inputs.parameters.ksu_name}} of {{inputs.parameters.profile_name}} profile of {{inputs.parameters.profile_type}} type @ {{inputs.parameters.project_name}} project"
+          - name: main_branch
+            value: main
+          - name: contrib_branch
+            value: osm_contrib
+          - name: dry_run
+            value: "{{inputs.parameters.dry_run}}"
+# ------ end of commit transaction
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-update-ksu-hr.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-update-ksu-hr.yaml
new file mode 100644 (file)
index 0000000..3d35084
--- /dev/null
@@ -0,0 +1,278 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: full-update-ksu-hr-wtf
+  namespace: osm-workflows
+spec:
+  arguments:
+    parameters:
+    # Fleet repo
+    - name: git_fleet_url
+    - name: fleet_destination_folder
+    - name: git_fleet_cred_secret
+    # SW-Catalogs repo
+    - name: git_sw_catalogs_url
+    - name: sw_catalogs_destination_folder
+    - name: git_sw_catalogs_cred_secret
+    # Specific parameters - Base KSU generation from template
+    ## Relative path from "SW Catalogs" repo root
+    - name: templates_path
+    ## Should substitute environment variables in the template?
+    - name: substitute_environment
+    ## Filter for substitution of environment variables
+    - name: substitution_filter
+    ## Custom environment variables (formatted as .env), to be used for template parametrization
+    - name: custom_env_vars
+    # Specific parameters - Patch HelmRelease in KSU with inline values
+    - name: kustomization_name
+    - name: helmrelease_name
+    - name: inline_values
+    # Specific parameters - Secret generation
+    - name: is_preexisting_secret
+    - name: target_ns
+    - name: age_public_key
+    - name: values_secret_name
+    - name: secret_key
+      value: "values.yaml"
+    ################################################################
+    # This temporary secret should exist already in the `osm-workflows`
+    # namespace and contain the desired secret key-values
+    # in a well-known key (in the example, `creds`).
+    #
+    # For instance:
+    #
+    # creds: |
+    #     jenkinsUser: admin
+    #     jenkinsPassword: myJ3nk1n2P2ssw0rd
+    - name: reference_secret_for_values
+    - name: reference_key_for_values
+    # Specific parameters - Configmap generation
+    - name: is_preexisting_cm
+    - name: values_cm_name
+    - name: cm_key
+      value: "values.yaml"
+    - name: cm_values
+      value: ""
+    # Specific parameters - KSU rendering
+    - name: ksu_name
+    - name: profile_name
+    - name: profile_type
+    - name: project_name
+      value: "osm_admin"
+    # Debug/dry run?
+    - name: debug
+      value: "false"
+    - name: dry_run
+      value: "false"
+
+  # Cleanup policy
+  ttlStrategy:
+    secondsAfterCompletion: 6000  # Time to live after workflow is completed, replaces ttlSecondsAfterFinished
+    secondsAfterSuccess: 6000     # Time to live after workflow is successful
+    secondsAfterFailure: 9000     # Time to live after workflow fails
+
+  entrypoint: update-ksu-hr
+
+  templates:
+  # Main template
+  - name: update-ksu-hr
+    inputs:
+      parameters:
+      # Fleet repo
+      - name: git_fleet_url
+      - name: fleet_destination_folder
+      - name: git_fleet_cred_secret
+      # SW-Catalogs repo
+      - name: git_sw_catalogs_url
+      - name: sw_catalogs_destination_folder
+      - name: git_sw_catalogs_cred_secret
+      # Specific parameters - Base KSU generation from template
+      - name: templates_path
+      - name: substitute_environment
+      - name: substitution_filter
+      - name: custom_env_vars
+      # Specific parameters - Patch HelmRelease in KSU with inline values
+      - name: kustomization_name
+      - name: helmrelease_name
+      - name: inline_values
+      # Specific parameters - Secret generation
+      - name: is_preexisting_secret
+      - name: target_ns
+      - name: age_public_key
+      - name: values_secret_name
+      - name: reference_secret_for_values
+      - name: reference_key_for_values
+      - name: secret_key
+      # Specific parameters - Configmap generation
+      - name: is_preexisting_cm
+      - name: values_cm_name
+      - name: cm_key
+      - name: cm_values
+      # Specific parameters - KSU rendering
+      - name: ksu_name
+      - name: profile_name
+      - name: profile_type
+      - name: project_name
+      # Debug/dry run?
+      - name: debug
+      - name: dry_run
+
+    steps:
+    # ------ Preparations for transaction
+    - - name: generate-fleet-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+      - name: generate-sw-catalogs-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+    - - name: clone-fleet
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+      - name: clone-sw-catalogs
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/sw-catalogs"
+          - name: repo_url
+            value: "{{inputs.parameters.git_sw_catalogs_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.sw_catalogs_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_sw_catalogs_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+    # ------ end of preparations for transaction
+
+    # ------ Transformations
+    - - name: update-ksu-oka-hr
+        templateRef:
+          name: ksu-management-wft
+          template: update-ksu-oka-hr
+        arguments:
+          parameters:
+          # References to required external resources
+          - name: fleet_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: sw_catalogs_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+          # Specific parameters - Base KSU generation from template
+          - name: templates_path
+            value: "{{inputs.parameters.templates_path}}"
+          - name: substitute_environment
+            value: "{{inputs.parameters.substitute_environment}}"
+          - name: substitution_filter
+            value: "{{inputs.parameters.substitution_filter}}"
+          - name: custom_env_vars
+            value: "{{inputs.parameters.custom_env_vars}}"
+          # Specific parameters - Patch HelmRelease in KSU with inline values
+          - name: kustomization_name
+            value: "{{inputs.parameters.kustomization_name}}"
+          - name: helmrelease_name
+            value: "{{inputs.parameters.helmrelease_name}}"
+          - name: inline_values
+            value: "{{inputs.parameters.inline_values}}"
+          # Specific parameters - Secret generation
+          - name: is_preexisting_secret
+            value: "{{inputs.parameters.is_preexisting_secret}}"
+          - name: target_ns
+            value: "{{inputs.parameters.target_ns}}"
+          - name: age_public_key
+            value: "{{inputs.parameters.age_public_key}}"
+          - name: values_secret_name
+            value: "{{inputs.parameters.values_secret_name}}"
+          - name: reference_secret_for_values
+            value: "{{inputs.parameters.reference_secret_for_values}}"
+          - name: reference_key_for_values
+            value: "{{inputs.parameters.reference_key_for_values}}"
+          - name: secret_key
+            value: "{{inputs.parameters.secret_key}}"
+          # Specific parameters - Configmap generation
+          - name: is_preexisting_cm
+            value: "{{inputs.parameters.is_preexisting_cm}}"
+          - name: values_cm_name
+            value: "{{inputs.parameters.values_cm_name}}"
+          - name: cm_key
+            value: "{{inputs.parameters.cm_key}}"
+          - name: cm_values
+            value: "{{inputs.parameters.cm_values}}"
+          # Specific parameters - KSU rendering
+          - name: ksu_name
+            value: "{{inputs.parameters.ksu_name}}"
+          - name: profile_name
+            value: "{{inputs.parameters.profile_name}}"
+          - name: profile_type
+            value: "{{inputs.parameters.profile_type}}"
+          - name: project_name
+            value: "{{inputs.parameters.project_name}}"
+          # Debug?
+          - name: debug
+            value: "{{inputs.parameters.debug}}"
+    # ------ end of transformations
+
+    # ------ Commit transaction
+    - - name: push-to-fleet
+        templateRef:
+          name: git-wft
+          template: git-commit-merge-push
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: commit_message
+            value: "Update KSU {{inputs.parameters.ksu_name}} of {{inputs.parameters.profile_name}} profile of {{inputs.parameters.profile_type}} type @ {{inputs.parameters.project_name}} project"
+          - name: main_branch
+            value: main
+          - name: contrib_branch
+            value: osm_contrib
+          - name: dry_run
+            value: "{{inputs.parameters.dry_run}}"
+# ------ end of commit transaction
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-update-oka.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-update-oka.yaml
new file mode 100644 (file)
index 0000000..dd563d9
--- /dev/null
@@ -0,0 +1,146 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: full-update-oka-wtf
+  namespace: osm-workflows
+spec:
+  arguments:
+    parameters:
+    # SW-Catalogs repo
+    - name: git_sw_catalogs_url
+    - name: sw_catalogs_destination_folder
+    - name: git_sw_catalogs_cred_secret
+    # Temporary volume with OKA contents
+    - name: temp_volume_name
+    # Specific parameters - OKA
+    - name: oka_name
+    ## Choose among `infra-controllers`, `infra-configs`, `cloud-resources`, `apps`:
+    - name: oka_type
+    - name: project_name
+      value: "osm_admin"
+    - name: tarball_file
+      value: "true"
+    # Debug/dry run?
+    - name: debug
+      value: "false"
+    - name: dry_run
+      value: "false"
+
+  # Cleanup policy
+  ttlStrategy:
+    secondsAfterCompletion: 6000  # Time to live after workflow is completed, replaces ttlSecondsAfterFinished
+    secondsAfterSuccess: 6000     # Time to live after workflow is successful
+    secondsAfterFailure: 9000     # Time to live after workflow fails
+
+  entrypoint: update-oka
+
+  templates:
+  # Main template
+  - name: update-oka
+    inputs:
+      parameters:
+      - name: git_sw_catalogs_url
+      - name: sw_catalogs_destination_folder
+      - name: git_sw_catalogs_cred_secret
+      - name: temp_volume_name
+      - name: oka_name
+      - name: oka_type
+      - name: project_name
+      - name: tarball_file
+      - name: debug
+      - name: dry_run
+    steps:
+    # ------ Preparations for transaction
+    - - name: generate-sw-catalogs-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+    - - name: clone-sw-catalogs
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/sw-catalogs"
+          - name: repo_url
+            value: "{{inputs.parameters.git_sw_catalogs_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.sw_catalogs_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_sw_catalogs_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+    # ------ end of preparations for transaction
+
+    # ------ Transformations
+    - - name: update-oka
+        templateRef:
+          name: oka-management-wft
+          template: update-oka
+        arguments:
+          parameters:
+          # References to required external resources
+          - name: sw_catalogs_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+          - name: temp_volume_name
+            value: "{{inputs.parameters.temp_volume_name}}"
+          # Specific parameters
+          - name: oka_name
+            value: "{{inputs.parameters.oka_name}}"
+          - name: oka_type
+            value: "{{inputs.parameters.oka_type}}"
+          - name: project_name
+            value: "{{inputs.parameters.project_name}}"
+          - name: tarball_file
+            value: "{{inputs.parameters.tarball_file}}"
+          # Debug?
+          - name: debug
+            value: "{{inputs.parameters.debug}}"
+    # ------ end of transformations
+
+    # ------ Commit transaction
+    - - name: push-to-sw-catalogs
+        templateRef:
+          name: git-wft
+          template: git-commit-merge-push
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/sw-catalogs"
+          - name: repo_folder
+            value: "{{inputs.parameters.sw_catalogs_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_sw_catalogs_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+          - name: commit_message
+            value: "Update OKA {{inputs.parameters.oka_name}} of {{inputs.parameters.oka_type}} type @ {{inputs.parameters.project_name}} project"
+          - name: main_branch
+            value: main
+          - name: contrib_branch
+            value: osm_contrib
+          - name: dry_run
+            value: "{{inputs.parameters.dry_run}}"
+# ------ end of commit transaction
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-update-providerconfig-wft.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-configs/osm-workflows/templates/wf-templates/canned-operations/full-update-providerconfig-wft.yaml
new file mode 100644 (file)
index 0000000..6e17e9b
--- /dev/null
@@ -0,0 +1,207 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+  name: full-update-crossplane-providerconfig
+  namespace: osm-workflows
+
+spec:
+  arguments:
+    parameters:
+    # Fleet repo
+    - name: git_fleet_url
+    - name: fleet_destination_folder
+    - name: git_fleet_cred_secret
+    # SW-Catalogs repo
+    - name: git_sw_catalogs_url
+    - name: sw_catalogs_destination_folder
+    - name: git_sw_catalogs_cred_secret
+
+    # Specific parameters
+    - name: providerconfig_name
+    ## As of today, one among `azure`, `aws` or `gcp`
+    - name: provider_type
+    ## Final secret to reference from the `ProviderConfig`
+    - name: cred_secret_name
+    ## Temporary secret with secret contents for the workflow
+    ## - If `temp_cred_secret_name` is empty, assumes that the final secret already exists
+    - name: temp_cred_secret_name
+      value: ""
+    - name: temp_cred_secret_key
+      value: "creds"
+    - name: age_public_key_mgmt
+    - name: osm_project_name
+      value: "osm_admin"
+    ## Specific parameters - GCP only
+    - name: target_gcp_project
+      value: ""
+    # Debug/dry run?
+    - name: debug
+      value: "false"
+    - name: dry_run
+      value: "false"
+
+  # Cleanup policy
+  ttlStrategy:
+    secondsAfterCompletion: 6000  # Time to live after workflow is completed, replaces ttlSecondsAfterFinished
+    secondsAfterSuccess: 6000     # Time to live after workflow is successful
+    secondsAfterFailure: 9000     # Time to live after workflow fails
+
+  entrypoint: update-crossplane-providerconfig
+
+  templates:
+
+  # Main template
+  - name: update-crossplane-providerconfig
+    inputs:
+      parameters:
+      # Fleet repo
+      - name: git_fleet_url
+      - name: fleet_destination_folder
+      - name: git_fleet_cred_secret
+      # SW-Catalogs repo
+      - name: git_sw_catalogs_url
+      - name: sw_catalogs_destination_folder
+      - name: git_sw_catalogs_cred_secret
+      # Specific parameters
+      - name: providerconfig_name
+      - name: provider_type
+      - name: cred_secret_name
+      - name: temp_cred_secret_name
+      - name: temp_cred_secret_key
+      - name: age_public_key_mgmt
+      - name: osm_project_name
+      - name: target_gcp_project
+      # Debug/dry run?
+      - name: debug
+        value: "false"
+      - name: dry_run
+        value: "false"
+
+    steps:
+
+    # ------ Preparations for transaction
+    - - name: generate-fleet-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+      - name: generate-sw-catalogs-volume-repo
+        templateRef:
+          name: k8s-resources-wft
+          template: generate-volume
+        arguments:
+          parameters:
+            - name: pvc-size
+              value: '100Mi'
+    - - name: clone-fleet
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_url
+            value: "{{inputs.parameters.git_fleet_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+      - name: clone-sw-catalogs
+        templateRef:
+          name: git-wft
+          template: git-clone
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/sw-catalogs"
+          - name: repo_url
+            value: "{{inputs.parameters.git_sw_catalogs_url}}"
+          - name: destination_folder
+            value: "{{inputs.parameters.sw_catalogs_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_sw_catalogs_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+    # ------ end of preparations for transaction
+
+    # ------ Transformations
+    - - name: update-crossplane-providerconfig
+        templateRef:
+          name: cloud-accounts-wft
+          template: update-crossplane-providerconfig
+        arguments:
+          parameters:
+          # References to required external resources
+          - name: fleet_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: sw_catalogs_volume_name
+            value: '{{steps.generate-sw-catalogs-volume-repo.outputs.parameters.pvc-name}}'
+          # Specific parameters
+          - name: providerconfig_name
+            value: "{{inputs.parameters.providerconfig_name}}"
+          - name: provider_type
+            value: "{{inputs.parameters.provider_type}}"
+          - name: cred_secret_name
+            value: "{{inputs.parameters.cred_secret_name}}"
+          - name: temp_cred_secret_name
+            value: "{{inputs.parameters.temp_cred_secret_name}}"
+          - name: temp_cred_secret_key
+            value: "{{inputs.parameters.temp_cred_secret_key}}"
+          - name: age_public_key_mgmt
+            value: "{{inputs.parameters.age_public_key_mgmt}}"
+          - name: osm_project_name
+            value: "{{inputs.parameters.osm_project_name}}"
+          - name: target_gcp_project
+            value: "{{inputs.parameters.target_gcp_project}}"
+          # Debug?
+          - name: debug
+            value: "{{inputs.parameters.debug}}"
+    # ------ end of transformations
+
+    # ------ Commit transaction
+    - - name: push-to-fleet
+        templateRef:
+          name: git-wft
+          template: git-commit-merge-push
+        arguments:
+          parameters:
+          - name: mount_path
+            value: "/fleet"
+          - name: repo_folder
+            value: "{{inputs.parameters.fleet_destination_folder}}"
+          - name: git_cred_secret
+            value: "{{inputs.parameters.git_fleet_cred_secret}}"
+          - name: git_volume_name
+            value: '{{steps.generate-fleet-volume-repo.outputs.parameters.pvc-name}}'
+          - name: commit_message
+            value: "Update ProviderConfig {{inputs.parameters.providerconfig_name}} for {{inputs.parameters.provider_type}}"
+          - name: main_branch
+            value: main
+          - name: contrib_branch
+            value: osm_contrib
+          - name: dry_run
+            value: "{{inputs.parameters.dry_run}}"
+# ------ end of commit transaction
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/argo-workflows/manifests/argo-namespace.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/argo-workflows/manifests/argo-namespace.yaml
new file mode 100644 (file)
index 0000000..6dc94f9
--- /dev/null
@@ -0,0 +1,23 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# Namespace
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: argo
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/argo-workflows/manifests/argo-wf-controller.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/argo-workflows/manifests/argo-wf-controller.yaml
new file mode 100644 (file)
index 0000000..103ba4b
--- /dev/null
@@ -0,0 +1,1369 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+# This is an auto-generated file. DO NOT EDIT
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  name: clusterworkflowtemplates.argoproj.io
+spec:
+  group: argoproj.io
+  names:
+    kind: ClusterWorkflowTemplate
+    listKind: ClusterWorkflowTemplateList
+    plural: clusterworkflowtemplates
+    shortNames:
+    - clusterwftmpl
+    - cwft
+    singular: clusterworkflowtemplate
+  scope: Cluster
+  versions:
+  - name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        properties:
+          apiVersion:
+            type: string
+          kind:
+            type: string
+          metadata:
+            type: object
+          spec:
+            type: object
+            x-kubernetes-map-type: atomic
+            x-kubernetes-preserve-unknown-fields: true
+        required:
+        - metadata
+        - spec
+        type: object
+    served: true
+    storage: true
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  name: cronworkflows.argoproj.io
+spec:
+  group: argoproj.io
+  names:
+    kind: CronWorkflow
+    listKind: CronWorkflowList
+    plural: cronworkflows
+    shortNames:
+    - cwf
+    - cronwf
+    singular: cronworkflow
+  scope: Namespaced
+  versions:
+  - name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        properties:
+          apiVersion:
+            type: string
+          kind:
+            type: string
+          metadata:
+            type: object
+          spec:
+            type: object
+            x-kubernetes-map-type: atomic
+            x-kubernetes-preserve-unknown-fields: true
+          status:
+            type: object
+            x-kubernetes-map-type: atomic
+            x-kubernetes-preserve-unknown-fields: true
+        required:
+        - metadata
+        - spec
+        type: object
+    served: true
+    storage: true
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  name: workflowartifactgctasks.argoproj.io
+spec:
+  group: argoproj.io
+  names:
+    kind: WorkflowArtifactGCTask
+    listKind: WorkflowArtifactGCTaskList
+    plural: workflowartifactgctasks
+    shortNames:
+    - wfat
+    singular: workflowartifactgctask
+  scope: Namespaced
+  versions:
+  - name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        properties:
+          apiVersion:
+            type: string
+          kind:
+            type: string
+          metadata:
+            type: object
+          spec:
+            type: object
+            x-kubernetes-map-type: atomic
+            x-kubernetes-preserve-unknown-fields: true
+          status:
+            type: object
+            x-kubernetes-map-type: atomic
+            x-kubernetes-preserve-unknown-fields: true
+        required:
+        - metadata
+        - spec
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  name: workfloweventbindings.argoproj.io
+spec:
+  group: argoproj.io
+  names:
+    kind: WorkflowEventBinding
+    listKind: WorkflowEventBindingList
+    plural: workfloweventbindings
+    shortNames:
+    - wfeb
+    singular: workfloweventbinding
+  scope: Namespaced
+  versions:
+  - name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        properties:
+          apiVersion:
+            type: string
+          kind:
+            type: string
+          metadata:
+            type: object
+          spec:
+            type: object
+            x-kubernetes-map-type: atomic
+            x-kubernetes-preserve-unknown-fields: true
+        required:
+        - metadata
+        - spec
+        type: object
+    served: true
+    storage: true
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  name: workflows.argoproj.io
+spec:
+  group: argoproj.io
+  names:
+    kind: Workflow
+    listKind: WorkflowList
+    plural: workflows
+    shortNames:
+    - wf
+    singular: workflow
+  scope: Namespaced
+  versions:
+  - additionalPrinterColumns:
+    - description: Status of the workflow
+      jsonPath: .status.phase
+      name: Status
+      type: string
+    - description: When the workflow was started
+      format: date-time
+      jsonPath: .status.startedAt
+      name: Age
+      type: date
+    - description: Human readable message indicating details about why the workflow
+        is in this condition.
+      jsonPath: .status.message
+      name: Message
+      type: string
+    name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        properties:
+          apiVersion:
+            type: string
+          kind:
+            type: string
+          metadata:
+            type: object
+          spec:
+            type: object
+            x-kubernetes-map-type: atomic
+            x-kubernetes-preserve-unknown-fields: true
+          status:
+            type: object
+            x-kubernetes-map-type: atomic
+            x-kubernetes-preserve-unknown-fields: true
+        required:
+        - metadata
+        - spec
+        type: object
+    served: true
+    storage: true
+    subresources: {}
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  name: workflowtaskresults.argoproj.io
+spec:
+  group: argoproj.io
+  names:
+    kind: WorkflowTaskResult
+    listKind: WorkflowTaskResultList
+    plural: workflowtaskresults
+    singular: workflowtaskresult
+  scope: Namespaced
+  versions:
+  - name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        properties:
+          apiVersion:
+            type: string
+          kind:
+            type: string
+          message:
+            type: string
+          metadata:
+            type: object
+          outputs:
+            properties:
+              artifacts:
+                items:
+                  properties:
+                    archive:
+                      properties:
+                        none:
+                          type: object
+                        tar:
+                          properties:
+                            compressionLevel:
+                              format: int32
+                              type: integer
+                          type: object
+                        zip:
+                          type: object
+                      type: object
+                    archiveLogs:
+                      type: boolean
+                    artifactGC:
+                      properties:
+                        podMetadata:
+                          properties:
+                            annotations:
+                              additionalProperties:
+                                type: string
+                              type: object
+                            labels:
+                              additionalProperties:
+                                type: string
+                              type: object
+                          type: object
+                        serviceAccountName:
+                          type: string
+                        strategy:
+                          enum:
+                          - ""
+                          - OnWorkflowCompletion
+                          - OnWorkflowDeletion
+                          - Never
+                          type: string
+                      type: object
+                    artifactory:
+                      properties:
+                        passwordSecret:
+                          properties:
+                            key:
+                              type: string
+                            name:
+                              type: string
+                            optional:
+                              type: boolean
+                          required:
+                          - key
+                          type: object
+                        url:
+                          type: string
+                        usernameSecret:
+                          properties:
+                            key:
+                              type: string
+                            name:
+                              type: string
+                            optional:
+                              type: boolean
+                          required:
+                          - key
+                          type: object
+                      required:
+                      - url
+                      type: object
+                    azure:
+                      properties:
+                        accountKeySecret:
+                          properties:
+                            key:
+                              type: string
+                            name:
+                              type: string
+                            optional:
+                              type: boolean
+                          required:
+                          - key
+                          type: object
+                        blob:
+                          type: string
+                        container:
+                          type: string
+                        endpoint:
+                          type: string
+                        useSDKCreds:
+                          type: boolean
+                      required:
+                      - blob
+                      - container
+                      - endpoint
+                      type: object
+                    deleted:
+                      type: boolean
+                    from:
+                      type: string
+                    fromExpression:
+                      type: string
+                    gcs:
+                      properties:
+                        bucket:
+                          type: string
+                        key:
+                          type: string
+                        serviceAccountKeySecret:
+                          properties:
+                            key:
+                              type: string
+                            name:
+                              type: string
+                            optional:
+                              type: boolean
+                          required:
+                          - key
+                          type: object
+                      required:
+                      - key
+                      type: object
+                    git:
+                      properties:
+                        branch:
+                          type: string
+                        depth:
+                          format: int64
+                          type: integer
+                        disableSubmodules:
+                          type: boolean
+                        fetch:
+                          items:
+                            type: string
+                          type: array
+                        insecureIgnoreHostKey:
+                          type: boolean
+                        passwordSecret:
+                          properties:
+                            key:
+                              type: string
+                            name:
+                              type: string
+                            optional:
+                              type: boolean
+                          required:
+                          - key
+                          type: object
+                        repo:
+                          type: string
+                        revision:
+                          type: string
+                        singleBranch:
+                          type: boolean
+                        sshPrivateKeySecret:
+                          properties:
+                            key:
+                              type: string
+                            name:
+                              type: string
+                            optional:
+                              type: boolean
+                          required:
+                          - key
+                          type: object
+                        usernameSecret:
+                          properties:
+                            key:
+                              type: string
+                            name:
+                              type: string
+                            optional:
+                              type: boolean
+                          required:
+                          - key
+                          type: object
+                      required:
+                      - repo
+                      type: object
+                    globalName:
+                      type: string
+                    hdfs:
+                      properties:
+                        addresses:
+                          items:
+                            type: string
+                          type: array
+                        force:
+                          type: boolean
+                        hdfsUser:
+                          type: string
+                        krbCCacheSecret:
+                          properties:
+                            key:
+                              type: string
+                            name:
+                              type: string
+                            optional:
+                              type: boolean
+                          required:
+                          - key
+                          type: object
+                        krbConfigConfigMap:
+                          properties:
+                            key:
+                              type: string
+                            name:
+                              type: string
+                            optional:
+                              type: boolean
+                          required:
+                          - key
+                          type: object
+                        krbKeytabSecret:
+                          properties:
+                            key:
+                              type: string
+                            name:
+                              type: string
+                            optional:
+                              type: boolean
+                          required:
+                          - key
+                          type: object
+                        krbRealm:
+                          type: string
+                        krbServicePrincipalName:
+                          type: string
+                        krbUsername:
+                          type: string
+                        path:
+                          type: string
+                      required:
+                      - path
+                      type: object
+                    http:
+                      properties:
+                        auth:
+                          properties:
+                            basicAuth:
+                              properties:
+                                passwordSecret:
+                                  properties:
+                                    key:
+                                      type: string
+                                    name:
+                                      type: string
+                                    optional:
+                                      type: boolean
+                                  required:
+                                  - key
+                                  type: object
+                                usernameSecret:
+                                  properties:
+                                    key:
+                                      type: string
+                                    name:
+                                      type: string
+                                    optional:
+                                      type: boolean
+                                  required:
+                                  - key
+                                  type: object
+                              type: object
+                            clientCert:
+                              properties:
+                                clientCertSecret:
+                                  properties:
+                                    key:
+                                      type: string
+                                    name:
+                                      type: string
+                                    optional:
+                                      type: boolean
+                                  required:
+                                  - key
+                                  type: object
+                                clientKeySecret:
+                                  properties:
+                                    key:
+                                      type: string
+                                    name:
+                                      type: string
+                                    optional:
+                                      type: boolean
+                                  required:
+                                  - key
+                                  type: object
+                              type: object
+                            oauth2:
+                              properties:
+                                clientIDSecret:
+                                  properties:
+                                    key:
+                                      type: string
+                                    name:
+                                      type: string
+                                    optional:
+                                      type: boolean
+                                  required:
+                                  - key
+                                  type: object
+                                clientSecretSecret:
+                                  properties:
+                                    key:
+                                      type: string
+                                    name:
+                                      type: string
+                                    optional:
+                                      type: boolean
+                                  required:
+                                  - key
+                                  type: object
+                                endpointParams:
+                                  items:
+                                    properties:
+                                      key:
+                                        type: string
+                                      value:
+                                        type: string
+                                    required:
+                                    - key
+                                    type: object
+                                  type: array
+                                scopes:
+                                  items:
+                                    type: string
+                                  type: array
+                                tokenURLSecret:
+                                  properties:
+                                    key:
+                                      type: string
+                                    name:
+                                      type: string
+                                    optional:
+                                      type: boolean
+                                  required:
+                                  - key
+                                  type: object
+                              type: object
+                          type: object
+                        headers:
+                          items:
+                            properties:
+                              name:
+                                type: string
+                              value:
+                                type: string
+                            required:
+                            - name
+                            - value
+                            type: object
+                          type: array
+                        url:
+                          type: string
+                      required:
+                      - url
+                      type: object
+                    mode:
+                      format: int32
+                      type: integer
+                    name:
+                      type: string
+                    optional:
+                      type: boolean
+                    oss:
+                      properties:
+                        accessKeySecret:
+                          properties:
+                            key:
+                              type: string
+                            name:
+                              type: string
+                            optional:
+                              type: boolean
+                          required:
+                          - key
+                          type: object
+                        bucket:
+                          type: string
+                        createBucketIfNotPresent:
+                          type: boolean
+                        endpoint:
+                          type: string
+                        key:
+                          type: string
+                        lifecycleRule:
+                          properties:
+                            markDeletionAfterDays:
+                              format: int32
+                              type: integer
+                            markInfrequentAccessAfterDays:
+                              format: int32
+                              type: integer
+                          type: object
+                        secretKeySecret:
+                          properties:
+                            key:
+                              type: string
+                            name:
+                              type: string
+                            optional:
+                              type: boolean
+                          required:
+                          - key
+                          type: object
+                        securityToken:
+                          type: string
+                        useSDKCreds:
+                          type: boolean
+                      required:
+                      - key
+                      type: object
+                    path:
+                      type: string
+                    raw:
+                      properties:
+                        data:
+                          type: string
+                      required:
+                      - data
+                      type: object
+                    recurseMode:
+                      type: boolean
+                    s3:
+                      properties:
+                        accessKeySecret:
+                          properties:
+                            key:
+                              type: string
+                            name:
+                              type: string
+                            optional:
+                              type: boolean
+                          required:
+                          - key
+                          type: object
+                        bucket:
+                          type: string
+                        caSecret:
+                          properties:
+                            key:
+                              type: string
+                            name:
+                              type: string
+                            optional:
+                              type: boolean
+                          required:
+                          - key
+                          type: object
+                        createBucketIfNotPresent:
+                          properties:
+                            objectLocking:
+                              type: boolean
+                          type: object
+                        encryptionOptions:
+                          properties:
+                            enableEncryption:
+                              type: boolean
+                            kmsEncryptionContext:
+                              type: string
+                            kmsKeyId:
+                              type: string
+                            serverSideCustomerKeySecret:
+                              properties:
+                                key:
+                                  type: string
+                                name:
+                                  type: string
+                                optional:
+                                  type: boolean
+                              required:
+                              - key
+                              type: object
+                          type: object
+                        endpoint:
+                          type: string
+                        insecure:
+                          type: boolean
+                        key:
+                          type: string
+                        region:
+                          type: string
+                        roleARN:
+                          type: string
+                        secretKeySecret:
+                          properties:
+                            key:
+                              type: string
+                            name:
+                              type: string
+                            optional:
+                              type: boolean
+                          required:
+                          - key
+                          type: object
+                        useSDKCreds:
+                          type: boolean
+                      type: object
+                    subPath:
+                      type: string
+                  required:
+                  - name
+                  type: object
+                type: array
+              exitCode:
+                type: string
+              parameters:
+                items:
+                  properties:
+                    default:
+                      type: string
+                    description:
+                      type: string
+                    enum:
+                      items:
+                        type: string
+                      type: array
+                    globalName:
+                      type: string
+                    name:
+                      type: string
+                    value:
+                      type: string
+                    valueFrom:
+                      properties:
+                        configMapKeyRef:
+                          properties:
+                            key:
+                              type: string
+                            name:
+                              type: string
+                            optional:
+                              type: boolean
+                          required:
+                          - key
+                          type: object
+                        default:
+                          type: string
+                        event:
+                          type: string
+                        expression:
+                          type: string
+                        jqFilter:
+                          type: string
+                        jsonPath:
+                          type: string
+                        parameter:
+                          type: string
+                        path:
+                          type: string
+                        supplied:
+                          type: object
+                      type: object
+                  required:
+                  - name
+                  type: object
+                type: array
+              result:
+                type: string
+            type: object
+          phase:
+            type: string
+          progress:
+            type: string
+        required:
+        - metadata
+        type: object
+    served: true
+    storage: true
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  name: workflowtasksets.argoproj.io
+spec:
+  group: argoproj.io
+  names:
+    kind: WorkflowTaskSet
+    listKind: WorkflowTaskSetList
+    plural: workflowtasksets
+    shortNames:
+    - wfts
+    singular: workflowtaskset
+  scope: Namespaced
+  versions:
+  - name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        properties:
+          apiVersion:
+            type: string
+          kind:
+            type: string
+          metadata:
+            type: object
+          spec:
+            type: object
+            x-kubernetes-map-type: atomic
+            x-kubernetes-preserve-unknown-fields: true
+          status:
+            type: object
+            x-kubernetes-map-type: atomic
+            x-kubernetes-preserve-unknown-fields: true
+        required:
+        - metadata
+        - spec
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  name: workflowtemplates.argoproj.io
+spec:
+  group: argoproj.io
+  names:
+    kind: WorkflowTemplate
+    listKind: WorkflowTemplateList
+    plural: workflowtemplates
+    shortNames:
+    - wftmpl
+    singular: workflowtemplate
+  scope: Namespaced
+  versions:
+  - name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        properties:
+          apiVersion:
+            type: string
+          kind:
+            type: string
+          metadata:
+            type: object
+          spec:
+            type: object
+            x-kubernetes-map-type: atomic
+            x-kubernetes-preserve-unknown-fields: true
+        required:
+        - metadata
+        - spec
+        type: object
+    served: true
+    storage: true
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: argo
+  namespace: argo
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: argo-server
+  namespace: argo
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: argo-role
+  namespace: argo
+rules:
+- apiGroups:
+  - coordination.k8s.io
+  resources:
+  - leases
+  verbs:
+  - create
+  - get
+  - update
+- apiGroups:
+  - ""
+  resources:
+  - secrets
+  verbs:
+  - get
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  labels:
+    rbac.authorization.k8s.io/aggregate-to-admin: "true"
+  name: argo-aggregate-to-admin
+rules:
+- apiGroups:
+  - argoproj.io
+  resources:
+  - workflows
+  - workflows/finalizers
+  - workfloweventbindings
+  - workfloweventbindings/finalizers
+  - workflowtemplates
+  - workflowtemplates/finalizers
+  - cronworkflows
+  - cronworkflows/finalizers
+  - clusterworkflowtemplates
+  - clusterworkflowtemplates/finalizers
+  - workflowtasksets
+  - workflowtasksets/finalizers
+  - workflowtaskresults
+  - workflowtaskresults/finalizers
+  verbs:
+  - create
+  - delete
+  - deletecollection
+  - get
+  - list
+  - patch
+  - update
+  - watch
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  labels:
+    rbac.authorization.k8s.io/aggregate-to-edit: "true"
+  name: argo-aggregate-to-edit
+rules:
+- apiGroups:
+  - argoproj.io
+  resources:
+  - workflows
+  - workflows/finalizers
+  - workfloweventbindings
+  - workfloweventbindings/finalizers
+  - workflowtemplates
+  - workflowtemplates/finalizers
+  - cronworkflows
+  - cronworkflows/finalizers
+  - clusterworkflowtemplates
+  - clusterworkflowtemplates/finalizers
+  - workflowtaskresults
+  - workflowtaskresults/finalizers
+  verbs:
+  - create
+  - delete
+  - deletecollection
+  - get
+  - list
+  - patch
+  - update
+  - watch
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  labels:
+    rbac.authorization.k8s.io/aggregate-to-view: "true"
+  name: argo-aggregate-to-view
+rules:
+- apiGroups:
+  - argoproj.io
+  resources:
+  - workflows
+  - workflows/finalizers
+  - workfloweventbindings
+  - workfloweventbindings/finalizers
+  - workflowtemplates
+  - workflowtemplates/finalizers
+  - cronworkflows
+  - cronworkflows/finalizers
+  - clusterworkflowtemplates
+  - clusterworkflowtemplates/finalizers
+  - workflowtaskresults
+  - workflowtaskresults/finalizers
+  verbs:
+  - get
+  - list
+  - watch
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  name: argo-cluster-role
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - pods
+  - pods/exec
+  verbs:
+  - create
+  - get
+  - list
+  - watch
+  - update
+  - patch
+  - delete
+- apiGroups:
+  - ""
+  resources:
+  - configmaps
+  verbs:
+  - get
+  - watch
+  - list
+- apiGroups:
+  - ""
+  resources:
+  - persistentvolumeclaims
+  - persistentvolumeclaims/finalizers
+  verbs:
+  - create
+  - update
+  - delete
+  - get
+- apiGroups:
+  - argoproj.io
+  resources:
+  - workflows
+  - workflows/finalizers
+  - workflowtasksets
+  - workflowtasksets/finalizers
+  - workflowartifactgctasks
+  verbs:
+  - get
+  - list
+  - watch
+  - update
+  - patch
+  - delete
+  - create
+- apiGroups:
+  - argoproj.io
+  resources:
+  - workflowtemplates
+  - workflowtemplates/finalizers
+  - clusterworkflowtemplates
+  - clusterworkflowtemplates/finalizers
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - argoproj.io
+  resources:
+  - workflowtaskresults
+  verbs:
+  - list
+  - watch
+  - deletecollection
+- apiGroups:
+  - ""
+  resources:
+  - serviceaccounts
+  verbs:
+  - get
+  - list
+- apiGroups:
+  - argoproj.io
+  resources:
+  - cronworkflows
+  - cronworkflows/finalizers
+  verbs:
+  - get
+  - list
+  - watch
+  - update
+  - patch
+  - delete
+- apiGroups:
+  - ""
+  resources:
+  - events
+  verbs:
+  - create
+  - patch
+- apiGroups:
+  - policy
+  resources:
+  - poddisruptionbudgets
+  verbs:
+  - create
+  - get
+  - delete
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  name: argo-server-cluster-role
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - configmaps
+  verbs:
+  - get
+  - watch
+  - list
+- apiGroups:
+  - ""
+  resources:
+  - secrets
+  verbs:
+  - get
+  - create
+- apiGroups:
+  - ""
+  resources:
+  - pods
+  - pods/exec
+  - pods/log
+  verbs:
+  - get
+  - list
+  - watch
+  - delete
+- apiGroups:
+  - ""
+  resources:
+  - events
+  verbs:
+  - watch
+  - create
+  - patch
+- apiGroups:
+  - ""
+  resources:
+  - serviceaccounts
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - argoproj.io
+  resources:
+  - eventsources
+  - sensors
+  - workflows
+  - workfloweventbindings
+  - workflowtemplates
+  - cronworkflows
+  - clusterworkflowtemplates
+  verbs:
+  - create
+  - get
+  - list
+  - watch
+  - update
+  - patch
+  - delete
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: argo-binding
+  namespace: argo
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: argo-role
+subjects:
+- kind: ServiceAccount
+  name: argo
+  namespace: argo
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: argo-binding
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: argo-cluster-role
+subjects:
+- kind: ServiceAccount
+  name: argo
+  namespace: argo
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: argo-server-binding
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: argo-server-cluster-role
+subjects:
+- kind: ServiceAccount
+  name: argo-server
+  namespace: argo
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: workflow-controller-configmap
+  namespace: argo
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: argo-server
+  namespace: argo
+spec:
+  ports:
+  - name: web
+    port: 2746
+    targetPort: 2746
+  selector:
+    app: argo-server
+---
+apiVersion: scheduling.k8s.io/v1
+kind: PriorityClass
+metadata:
+  name: workflow-controller
+value: 1000000
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: argo-server
+  namespace: argo
+spec:
+  selector:
+    matchLabels:
+      app: argo-server
+  template:
+    metadata:
+      labels:
+        app: argo-server
+    spec:
+      containers:
+      - args:
+        - server
+        env: []
+        image: quay.io/argoproj/argocli:v3.5.1
+        name: argo-server
+        ports:
+        - containerPort: 2746
+          name: web
+        readinessProbe:
+          httpGet:
+            path: /
+            port: 2746
+            scheme: HTTPS
+          initialDelaySeconds: 10
+          periodSeconds: 20
+        securityContext:
+          allowPrivilegeEscalation: false
+          capabilities:
+            drop:
+            - ALL
+          readOnlyRootFilesystem: true
+          runAsNonRoot: true
+        volumeMounts:
+        - mountPath: /tmp
+          name: tmp
+      nodeSelector:
+        kubernetes.io/os: linux
+      securityContext:
+        runAsNonRoot: true
+      serviceAccountName: argo-server
+      volumes:
+      - emptyDir: {}
+        name: tmp
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: workflow-controller
+  namespace: argo
+spec:
+  selector:
+    matchLabels:
+      app: workflow-controller
+  template:
+    metadata:
+      labels:
+        app: workflow-controller
+    spec:
+      containers:
+      - args: []
+        command:
+        - workflow-controller
+        env:
+        - name: LEADER_ELECTION_IDENTITY
+          valueFrom:
+            fieldRef:
+              apiVersion: v1
+              fieldPath: metadata.name
+        image: quay.io/argoproj/workflow-controller:v3.5.1
+        livenessProbe:
+          failureThreshold: 3
+          httpGet:
+            path: /healthz
+            port: 6060
+          initialDelaySeconds: 90
+          periodSeconds: 60
+          timeoutSeconds: 30
+        name: workflow-controller
+        ports:
+        - containerPort: 9090
+          name: metrics
+        - containerPort: 6060
+        securityContext:
+          allowPrivilegeEscalation: false
+          capabilities:
+            drop:
+            - ALL
+          readOnlyRootFilesystem: true
+          runAsNonRoot: true
+      nodeSelector:
+        kubernetes.io/os: linux
+      priorityClassName: workflow-controller
+      securityContext:
+        runAsNonRoot: true
+      serviceAccountName: argo
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/argo-workflows/templates/argo-workflows.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/argo-workflows/templates/argo-workflows.yaml
new file mode 100644 (file)
index 0000000..48f8312
--- /dev/null
@@ -0,0 +1,55 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# Namespace
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: argo
+
+---
+# Base Kustomization
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: argo-workflows
+  namespace: argo
+spec:
+  interval: 1h
+  retryInterval: 1m
+  timeout: 5m
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
+  path: ./infra-controllers/argo-workflows/manifests
+  prune: true
+
+  # (optional - comment otherwise) Set argo-server authentication
+  patches:
+  - target:
+      group: apps
+      version: v1
+      kind: Deployment
+      name: argo-server
+    patch: |-
+      - op: replace
+        path: /spec/template/spec/containers/0/args
+        value:
+          - server
+          - --auth-mode=server
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/cert-manager/manifests/cert-manager-chart.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/cert-manager/manifests/cert-manager-chart.yaml
new file mode 100644 (file)
index 0000000..863fa1c
--- /dev/null
@@ -0,0 +1,52 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: cert-manager
+
+---
+apiVersion: source.toolkit.fluxcd.io/v1beta2
+kind: HelmRepository
+metadata:
+  name: cert-manager
+  namespace: cert-manager
+spec:
+  interval: 24h
+  url: https://charts.jetstack.io
+
+---
+apiVersion: helm.toolkit.fluxcd.io/v2beta1
+kind: HelmRelease
+metadata:
+  name: cert-manager
+  namespace: cert-manager
+spec:
+  interval: 30m
+  chart:
+    spec:
+      chart: cert-manager
+      version: "1.x"
+      sourceRef:
+        kind: HelmRepository
+        name: cert-manager
+        namespace: cert-manager
+      interval: 12h
+  values:
+    installCRDs: true
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/cert-manager/templates/cert-manager-ks.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/cert-manager/templates/cert-manager-ks.yaml
new file mode 100644 (file)
index 0000000..68c3581
--- /dev/null
@@ -0,0 +1,31 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: cert-manager
+  namespace: flux-system
+spec:
+  interval: 1h0m0s
+  path: ./infra-controllers/cert-manager/manifests
+  prune: true
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/controller/manifests/crossplane-helmrelease.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/controller/manifests/crossplane-helmrelease.yaml
new file mode 100644 (file)
index 0000000..9c49bdd
--- /dev/null
@@ -0,0 +1,38 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# Helm release for controller
+apiVersion: helm.toolkit.fluxcd.io/v2beta1
+kind: HelmRelease
+metadata:
+  name: crossplane
+  namespace: crossplane-system
+spec:
+  chart:
+    spec:
+      chart: crossplane
+      reconcileStrategy: ChartVersion
+      sourceRef:
+        kind: HelmRepository
+        name: crossplane-stable
+        namespace: crossplane-system
+  install:
+    createNamespace: true
+  interval: 30s
+  releaseName: crossplane
+  targetNamespace: crossplane-system
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/controller/manifests/crossplane-helmrepo.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/controller/manifests/crossplane-helmrepo.yaml
new file mode 100644 (file)
index 0000000..5e63ea4
--- /dev/null
@@ -0,0 +1,26 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: source.toolkit.fluxcd.io/v1beta2
+kind: HelmRepository
+metadata:
+  name: crossplane-stable
+  namespace: crossplane-system
+spec:
+  interval: 30s
+  url: https://charts.crossplane.io/stable
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/controller/manifests/crossplane-namespace.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/controller/manifests/crossplane-namespace.yaml
new file mode 100644 (file)
index 0000000..ca673b2
--- /dev/null
@@ -0,0 +1,23 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# Namespace
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: crossplane-system
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/controller/manifests/kustomization.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/controller/manifests/kustomization.yaml
new file mode 100644 (file)
index 0000000..7fe8247
--- /dev/null
@@ -0,0 +1,23 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
+resources:
+  - crossplane-namespace.yaml
+  - crossplane-helmrepo.yaml
+  - crossplane-helmrelease.yaml
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/controller/templates/crossplane.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/controller/templates/crossplane.yaml
new file mode 100644 (file)
index 0000000..720202b
--- /dev/null
@@ -0,0 +1,41 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# Namespace
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: crossplane-system
+
+---
+# Crossplane controller
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: crossplane-controller
+  namespace: crossplane-system
+spec:
+  interval: 1h
+  retryInterval: 1m
+  timeout: 5m
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
+  path: ./infra-controllers/crossplane/controller/manifests
+  prune: true
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/aws/manifests/provider-ec2.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/aws/manifests/provider-ec2.yaml
new file mode 100644 (file)
index 0000000..692e39c
--- /dev/null
@@ -0,0 +1,27 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# CRDs for general EC2 compute services 
+apiVersion: pkg.crossplane.io/v1
+kind: Provider
+metadata:
+  name: provider-aws-ec2
+spec:
+  package: xpkg.upbound.io/upbound/provider-aws-ec2:v1.4.0
+  
+
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/aws/manifests/provider-eks.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/aws/manifests/provider-eks.yaml
new file mode 100644 (file)
index 0000000..ec3fc55
--- /dev/null
@@ -0,0 +1,26 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# CRDs for EKS service
+apiVersion: pkg.crossplane.io/v1
+kind: Provider
+metadata:
+  name: provider-aws-eks
+spec:
+  package: xpkg.upbound.io/upbound/provider-aws-eks:v1.4.0
+  
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/aws/manifests/provider-iam.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/aws/manifests/provider-iam.yaml
new file mode 100644 (file)
index 0000000..4aa50e8
--- /dev/null
@@ -0,0 +1,27 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# CRDs for IAM service
+apiVersion: pkg.crossplane.io/v1
+kind: Provider
+metadata:
+  name: provider-aws-iam
+spec:
+  package: xpkg.upbound.io/upbound/provider-aws-iam:v1.4.0
+  
+
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/aws/manifests/provider-vpc.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/aws/manifests/provider-vpc.yaml
new file mode 100644 (file)
index 0000000..cfa9a02
--- /dev/null
@@ -0,0 +1,26 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# CRDs for VPC service
+apiVersion: pkg.crossplane.io/v1
+kind: Provider
+metadata:
+  name: provider-aws-vpc
+spec:
+  package: xpkg.upbound.io/upbound/provider-aws-vpc:v1.4.0
+  
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/aws/templates/crossplane-aws-providers.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/aws/templates/crossplane-aws-providers.yaml
new file mode 100644 (file)
index 0000000..19325a2
--- /dev/null
@@ -0,0 +1,35 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# AWS Upbound lightweight provider families
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: aws-providers
+  namespace: crossplane-system
+spec:
+  interval: 1h
+  retryInterval: 1m
+  timeout: 5m
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
+  path: ./infra-controllers/crossplane/providers/aws/manifests
+  prune: true
+  
\ No newline at end of file
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/azure/manifests/provider-azure-container.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/azure/manifests/provider-azure-container.yaml
new file mode 100644 (file)
index 0000000..41b1d79
--- /dev/null
@@ -0,0 +1,23 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: pkg.crossplane.io/v1
+kind: Provider
+metadata:
+  name: provider-azure-containerservice
+spec:
+  package: xpkg.upbound.io/upbound/provider-azure-containerservice:v0.37.1
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/azure/manifests/provider-azure-dbformysql.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/azure/manifests/provider-azure-dbformysql.yaml
new file mode 100644 (file)
index 0000000..317e70d
--- /dev/null
@@ -0,0 +1,24 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: pkg.crossplane.io/v1
+kind: Provider
+metadata:
+  name: provider-azure-dbformysql
+spec:
+  package: xpkg.upbound.io/upbound/provider-azure-dbformysql:v0.38.2
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/azure/templates/crossplane-azure-providers.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/azure/templates/crossplane-azure-providers.yaml
new file mode 100644 (file)
index 0000000..436a9ff
--- /dev/null
@@ -0,0 +1,34 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# Azure providers
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: azure-providers
+  namespace: crossplane-system
+spec:
+  interval: 1h
+  retryInterval: 1m
+  timeout: 5m
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
+  path: ./infra-controllers/crossplane/providers/azure/manifests
+  prune: true
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/gcp/manifests/provider-gcp-cloudplatform.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/gcp/manifests/provider-gcp-cloudplatform.yaml
new file mode 100644 (file)
index 0000000..8f3f708
--- /dev/null
@@ -0,0 +1,25 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# CRDs for general CGP management
+apiVersion: pkg.crossplane.io/v1
+kind: Provider
+metadata:
+  name: provider-gcp-cloudplatform
+spec:
+  package: xpkg.upbound.io/upbound/provider-gcp-cloudplatform:v1.2.0
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/gcp/manifests/provider-gcp-container.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/gcp/manifests/provider-gcp-container.yaml
new file mode 100644 (file)
index 0000000..e7b5487
--- /dev/null
@@ -0,0 +1,25 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# CRDs for K8s and other container services
+apiVersion: pkg.crossplane.io/v1
+kind: Provider
+metadata:
+  name: provider-gcp-container
+spec:
+  package: xpkg.upbound.io/upbound/provider-gcp-container:v1.2.0
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/gcp/templates/crossplane-gcp-providers.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/crossplane/providers/gcp/templates/crossplane-gcp-providers.yaml
new file mode 100644 (file)
index 0000000..972bc89
--- /dev/null
@@ -0,0 +1,34 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# GCP providers
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: gcp-providers
+  namespace: crossplane-system
+spec:
+  interval: 1h
+  retryInterval: 1m
+  timeout: 5m
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
+  path: ./infra-controllers/crossplane/providers/gcp/manifests
+  prune: true
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/ingress-nginx/manifests/ingress-nginx.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/ingress-nginx/manifests/ingress-nginx.yaml
new file mode 100644 (file)
index 0000000..eb8ed2f
--- /dev/null
@@ -0,0 +1,56 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: ingress-nginx
+
+---
+apiVersion: source.toolkit.fluxcd.io/v1beta2
+kind: HelmRepository
+metadata:
+  name: ingress-nginx
+  namespace: ingress-nginx
+spec:
+  interval: 24h
+  url: https://kubernetes.github.io/ingress-nginx
+
+---
+apiVersion: helm.toolkit.fluxcd.io/v2beta1
+kind: HelmRelease
+metadata:
+  name: ingress-nginx
+  namespace: ingress-nginx
+spec:
+  interval: 30m
+  chart:
+    spec:
+      chart: ingress-nginx
+      version: "*"
+      sourceRef:
+        kind: HelmRepository
+        name: ingress-nginx
+        namespace: ingress-nginx
+      interval: 12h
+  values:
+    controller:
+      service:
+        type: "NodePort"
+    admissionWebhooks:
+      enabled: false
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/ingress-nginx/templates/ingress-nginx-ks.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/ingress-nginx/templates/ingress-nginx-ks.yaml
new file mode 100644 (file)
index 0000000..dc6c6cf
--- /dev/null
@@ -0,0 +1,31 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: ingress-nginx
+  namespace: flux-system
+spec:
+  interval: 1h0m0s
+  path: ./infra-controllers/ingress-nginx/manifests
+  prune: true
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/manifests/addons/grafana.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/manifests/addons/grafana.yaml
new file mode 100644 (file)
index 0000000..6b49072
--- /dev/null
@@ -0,0 +1,1158 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# Source: grafana/templates/serviceaccount.yaml
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  labels:
+    helm.sh/chart: grafana-6.57.4
+    app.kubernetes.io/name: grafana
+    app.kubernetes.io/instance: grafana
+    app.kubernetes.io/version: "9.5.5"
+    app.kubernetes.io/managed-by: Helm
+  name: grafana
+  namespace: istio-system
+---
+# Source: grafana/templates/configmap.yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: grafana
+  namespace: istio-system
+  labels:
+    helm.sh/chart: grafana-6.57.4
+    app.kubernetes.io/name: grafana
+    app.kubernetes.io/instance: grafana
+    app.kubernetes.io/version: "9.5.5"
+    app.kubernetes.io/managed-by: Helm
+data:
+  grafana.ini: |
+    [analytics]
+    check_for_updates = true
+    [grafana_net]
+    url = https://grafana.net
+    [log]
+    mode = console
+    [paths]
+    data = /var/lib/grafana/
+    logs = /var/log/grafana
+    plugins = /var/lib/grafana/plugins
+    provisioning = /etc/grafana/provisioning
+    [server]
+    domain = ''
+  datasources.yaml: |
+    apiVersion: 1
+    datasources:
+    - access: proxy
+      editable: true
+      isDefault: true
+      jsonData:
+        timeInterval: 5s
+      name: Prometheus
+      orgId: 1
+      type: prometheus
+      url: http://prometheus:9090
+    - access: proxy
+      editable: true
+      isDefault: false
+      jsonData:
+        timeInterval: 5s
+      name: Loki
+      orgId: 1
+      type: loki
+      url: http://loki:3100
+  dashboardproviders.yaml: |
+    apiVersion: 1
+    providers:
+    - disableDeletion: false
+      folder: istio
+      name: istio
+      options:
+        path: /var/lib/grafana/dashboards/istio
+      orgId: 1
+      type: file
+    - disableDeletion: false
+      folder: istio
+      name: istio-services
+      options:
+        path: /var/lib/grafana/dashboards/istio-services
+      orgId: 1
+      type: file
+---
+# Source: grafana/templates/service.yaml
+apiVersion: v1
+kind: Service
+metadata:
+  name: grafana
+  namespace: istio-system
+  labels:
+    helm.sh/chart: grafana-6.57.4
+    app.kubernetes.io/name: grafana
+    app.kubernetes.io/instance: grafana
+    app.kubernetes.io/version: "9.5.5"
+    app.kubernetes.io/managed-by: Helm
+spec:
+  type: ClusterIP
+  ports:
+    - name: service
+      port: 3000
+      protocol: TCP
+      targetPort: 3000
+  selector:
+    app.kubernetes.io/name: grafana
+    app.kubernetes.io/instance: grafana
+---
+# Source: grafana/templates/deployment.yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: grafana
+  namespace: istio-system
+  labels:
+    helm.sh/chart: grafana-6.57.4
+    app.kubernetes.io/name: grafana
+    app.kubernetes.io/instance: grafana
+    app.kubernetes.io/version: "9.5.5"
+    app.kubernetes.io/managed-by: Helm
+spec:
+  replicas: 1
+  revisionHistoryLimit: 10
+  selector:
+    matchLabels:
+      app.kubernetes.io/name: grafana
+      app.kubernetes.io/instance: grafana
+  strategy:
+    type: RollingUpdate
+  template:
+    metadata:
+      labels:
+        app.kubernetes.io/name: grafana
+        app.kubernetes.io/instance: grafana
+        app: grafana
+        sidecar.istio.io/inject: "false"
+      annotations:
+        checksum/config: aec3d18ca2ea82d1d48f8965db1440aba0680ed2f32c5a29e6cdb5e7afc8b395
+        checksum/dashboards-json-config: 01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b
+        checksum/sc-dashboard-provider-config: 01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b
+        kubectl.kubernetes.io/default-container: grafana
+    spec:
+      
+      serviceAccountName: grafana
+      automountServiceAccountToken: true
+      securityContext:
+        fsGroup: 472
+        runAsGroup: 472
+        runAsNonRoot: true
+        runAsUser: 472
+      enableServiceLinks: true
+      containers:
+        - name: grafana
+          image: "docker.io/grafana/grafana:9.5.5"
+          imagePullPolicy: IfNotPresent
+          securityContext:
+            allowPrivilegeEscalation: false
+            capabilities:
+              drop:
+              - ALL
+            seccompProfile:
+              type: RuntimeDefault
+          volumeMounts:
+            - name: config
+              mountPath: "/etc/grafana/grafana.ini"
+              subPath: grafana.ini
+            - name: storage
+              mountPath: "/var/lib/grafana"
+            - name: dashboards-istio
+              mountPath: "/var/lib/grafana/dashboards/istio"
+            - name: dashboards-istio-services
+              mountPath: "/var/lib/grafana/dashboards/istio-services"
+            - name: config
+              mountPath: "/etc/grafana/provisioning/datasources/datasources.yaml"
+              subPath: "datasources.yaml"
+            - name: config
+              mountPath: "/etc/grafana/provisioning/dashboards/dashboardproviders.yaml"
+              subPath: "dashboardproviders.yaml"
+          ports:
+            - name: grafana
+              containerPort: 3000
+              protocol: TCP
+            - name: gossip-tcp
+              containerPort: 9094
+              protocol: TCP
+            - name: gossip-udp
+              containerPort: 9094
+              protocol: UDP
+          env:
+            - name: POD_IP
+              valueFrom:
+                fieldRef:
+                  fieldPath: status.podIP
+            - name: GF_PATHS_DATA
+              value: /var/lib/grafana/
+            - name: GF_PATHS_LOGS
+              value: /var/log/grafana
+            - name: GF_PATHS_PLUGINS
+              value: /var/lib/grafana/plugins
+            - name: GF_PATHS_PROVISIONING
+              value: /etc/grafana/provisioning
+            - name: "GF_AUTH_ANONYMOUS_ENABLED"
+              value: "true"
+            - name: "GF_AUTH_ANONYMOUS_ORG_ROLE"
+              value: "Admin"
+            - name: "GF_AUTH_BASIC_ENABLED"
+              value: "false"
+            - name: "GF_SECURITY_ADMIN_PASSWORD"
+              value: "admin"
+            - name: "GF_SECURITY_ADMIN_USER"
+              value: "admin"
+          livenessProbe:
+            failureThreshold: 10
+            httpGet:
+              path: /api/health
+              port: 3000
+            initialDelaySeconds: 60
+            timeoutSeconds: 30
+          readinessProbe:
+            httpGet:
+              path: /api/health
+              port: 3000
+      volumes:
+        - name: config
+          configMap:
+            name: grafana
+        - name: dashboards-istio
+          configMap:
+            name: istio-grafana-dashboards
+        - name: dashboards-istio-services
+          configMap:
+            name: istio-services-grafana-dashboards
+        - name: storage
+          emptyDir: {}
+
+---
+
+apiVersion: v1
+data:
+  istio-performance-dashboard.json: |
+    {"annotations":{"list":[{"builtIn":1,"datasource":"-- Grafana --","enable":true,"hide":true,"iconColor":"rgba(0, 211, 255, 1)","name":"Annotations & Alerts","type":"dashboard"}]},"editable":false,"gnetId":null,"graphTooltip":0,"links":[],"panels":[{"collapsed":true,"gridPos":{"h":1,"w":24,"x":0,"y":0},"id":21,"panels":[{"content":"The charts on this dashboard are intended to show Istio main components cost in terms of resources utilization under steady load.\n\n- **vCPU / 1k rps:** shows vCPU utilization by the main Istio components normalized by 1000 requests/second. When idle or low traffic, this chart will be blank. The curve for istio-proxy refers to the services sidecars only.\n- **vCPU:** vCPU utilization by Istio components, not normalized.\n- **Memory:** memory footprint for the components. Telemetry and policy are normalized by 1k rps, and no data is shown  when there is no traffic. For ingress and istio-proxy, the data is per instance.\n- **Bytes transferred / sec:** shows the number of bytes flowing through each Istio component.\n\n\n","gridPos":{"h":6,"w":24,"x":0,"y":1},"id":19,"links":[],"mode":"markdown","timeFrom":null,"timeShift":null,"title":"Performance Dashboard README","transparent":true,"type":"text"}],"title":"Performance Dashboard Notes","type":"row"},{"collapsed":false,"gridPos":{"h":1,"w":24,"x":0,"y":1},"id":6,"panels":[],"title":"vCPU Usage","type":"row"},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":8,"w":12,"x":0,"y":2},"id":4,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":2,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"(sum(irate(container_cpu_usage_seconds_total{pod=~\"istio-ingressgateway-.*\",container=\"istio-proxy\"}[1m])) / (round(sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\", reporter=\"source\"}[1m])), 0.001)/1000))","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"istio-ingressgateway","refId":"A"},{"expr":"(sum(irate(container_cpu_usage_seconds_total{namespace!=\"istio-system\",container=\"istio-proxy\"}[1m]))/ (round(sum(irate(istio_requests_total[1m])), 0.001)/1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)","format":"time_series","intervalFactor":1,"legendFormat":"istio-proxy","refId":"B"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"vCPU / 1k rps","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":8,"w":12,"x":12,"y":2},"id":7,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":2,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(rate(container_cpu_usage_seconds_total{pod=~\"istio-ingressgateway-.*\",container=\"istio-proxy\"}[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"istio-ingressgateway","refId":"A"},{"expr":"sum(rate(container_cpu_usage_seconds_total{namespace!=\"istio-system\",container=\"istio-proxy\"}[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"istio-proxy","refId":"B"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"vCPU","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"collapsed":false,"gridPos":{"h":1,"w":24,"x":0,"y":10},"id":13,"panels":[],"title":"Memory and Data Rates","type":"row"},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":8,"w":12,"x":0,"y":11},"id":902,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":2,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(container_memory_working_set_bytes{pod=~\"istio-ingressgateway-.*\"}) / count(container_memory_working_set_bytes{pod=~\"istio-ingressgateway-.*\",container!=\"POD\"})","format":"time_series","intervalFactor":1,"legendFormat":"per istio-ingressgateway","refId":"A"},{"expr":"sum(container_memory_working_set_bytes{namespace!=\"istio-system\",container=\"istio-proxy\"}) / count(container_memory_working_set_bytes{namespace!=\"istio-system\",container=\"istio-proxy\"})","format":"time_series","intervalFactor":1,"legendFormat":"per istio proxy","refId":"B"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Memory Usage","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"bytes","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":8,"w":12,"x":12,"y":11},"id":11,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":2,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(irate(istio_response_bytes_sum{source_workload=\"istio-ingressgateway\", reporter=\"source\"}[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"istio-ingressgateway","refId":"A"},{"expr":"sum(irate(istio_response_bytes_sum{source_workload_namespace!=\"istio-system\", reporter=\"source\"}[1m])) + sum(irate(istio_request_bytes_sum{source_workload_namespace!=\"istio-system\", reporter=\"source\"}[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"istio-proxy","refId":"B"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Bytes transferred / sec","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"Bps","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"collapsed":false,"gridPos":{"h":1,"w":24,"x":0,"y":19},"id":17,"panels":[],"title":"Istio Component Versions","type":"row"},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":8,"w":24,"x":0,"y":20},"id":15,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":2,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(istio_build) by (component, tag)","format":"time_series","intervalFactor":1,"legendFormat":"{{ component }}: {{ tag }}","refId":"A"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Istio Components by Version","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"collapsed":false,"gridPos":{"h":1,"w":24,"x":0,"y":31},"id":71,"panels":[],"title":"Proxy Resource Usage","type":"row"},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":7,"w":6,"x":0,"y":32},"id":72,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(container_memory_working_set_bytes{container=\"istio-proxy\"})","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"Total (k8s)","refId":"A","step":2}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Memory","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"bytes","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":false}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":7,"w":6,"x":6,"y":32},"id":73,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(rate(container_cpu_usage_seconds_total{container=\"istio-proxy\"}[1m]))","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"Total (k8s)","refId":"A","step":2}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"vCPU","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":7,"w":6,"x":12,"y":32},"id":702,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(container_fs_usage_bytes{container=\"istio-proxy\"})","format":"time_series","intervalFactor":2,"legendFormat":"Total (k8s)","refId":"A","step":2}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Disk","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"bytes","label":"","logBase":1,"max":null,"min":null,"show":true},{"decimals":null,"format":"none","label":"","logBase":1024,"max":null,"min":null,"show":false}],"yaxis":{"align":false,"alignLevel":null}},{"collapsed":false,"gridPos":{"h":1,"w":24,"x":0,"y":39},"id":69,"panels":[],"title":"Istiod Resource Usage","type":"row"},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":7,"w":6,"x":0,"y":40},"id":5,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"process_virtual_memory_bytes{app=\"istiod\"}","format":"time_series","instant":false,"intervalFactor":2,"legendFormat":"Virtual Memory","refId":"I","step":2},{"expr":"process_resident_memory_bytes{app=\"istiod\"}","format":"time_series","intervalFactor":2,"legendFormat":"Resident Memory","refId":"H","step":2},{"expr":"go_memstats_heap_sys_bytes{app=\"istiod\"}","format":"time_series","hide":true,"intervalFactor":2,"legendFormat":"heap sys","refId":"A"},{"expr":"go_memstats_heap_alloc_bytes{app=\"istiod\"}","format":"time_series","hide":true,"intervalFactor":2,"legendFormat":"heap alloc","refId":"D"},{"expr":"go_memstats_alloc_bytes{app=\"istiod\"}","format":"time_series","intervalFactor":2,"legendFormat":"Alloc","refId":"F","step":2},{"expr":"go_memstats_heap_inuse_bytes{app=\"istiod\"}","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"Heap in-use","refId":"E","step":2},{"expr":"go_memstats_stack_inuse_bytes{app=\"istiod\"}","format":"time_series","intervalFactor":2,"legendFormat":"Stack in-use","refId":"G","step":2},{"expr":"sum(container_memory_working_set_bytes{container=~\"discovery|istio-proxy\", pod=~\"istiod-.*\"})","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"Total (k8s)","refId":"C","step":2},{"expr":"container_memory_working_set_bytes{container=~\"discovery|istio-proxy\", pod=~\"istiod-.*\"}","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"{{ container }} (k8s)","refId":"B","step":2}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Memory","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"bytes","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":false}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":7,"w":6,"x":6,"y":40},"id":602,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(rate(container_cpu_usage_seconds_total{container=~\"discovery|istio-proxy\", pod=~\"istiod-.*\"}[1m]))","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"Total (k8s)","refId":"A","step":2},{"expr":"sum(rate(container_cpu_usage_seconds_total{container=~\"discovery|istio-proxy\", pod=~\"istiod-.*\"}[1m])) by (container)","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"{{ container }} (k8s)","refId":"B","step":2},{"expr":"irate(process_cpu_seconds_total{app=\"istiod\"}[1m])","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"pilot (self-reported)","refId":"C","step":2}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"vCPU","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":7,"w":6,"x":12,"y":40},"id":74,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"process_open_fds{app=\"istiod\"}","format":"time_series","hide":true,"instant":false,"interval":"","intervalFactor":2,"legendFormat":"Open FDs (pilot)","refId":"A"},{"expr":"container_fs_usage_bytes{ container=~\"discovery|istio-proxy\", pod=~\"istiod-.*\"}","format":"time_series","intervalFactor":2,"legendFormat":"{{ container }}","refId":"B","step":2}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Disk","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"bytes","label":"","logBase":1,"max":null,"min":null,"show":true},{"decimals":null,"format":"none","label":"","logBase":1024,"max":null,"min":null,"show":false}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":7,"w":6,"x":18,"y":40},"id":402,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":false,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"go_goroutines{app=\"istiod\"}","format":"time_series","intervalFactor":2,"legendFormat":"Number of Goroutines","refId":"A","step":2}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Goroutines","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":"","logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}}],"refresh":"10s","schemaVersion":18,"style":"dark","tags":[],"templating":{"list":[{"current":{"selected":true,"text":"default","value":"default"},"hide":0,"includeAll":false,"label":null,"multi":false,"name":"datasource","options":[],"query":"prometheus","queryValue":"","refresh":1,"regex":"","skipUrlSync":false,"type":"datasource"}]},"time":{"from":"now-5m","to":"now"},"timepicker":{"refresh_intervals":["5s","10s","30s","1m","5m","15m","30m","1h","2h","1d"],"time_options":["5m","15m","1h","6h","12h","24h","2d","7d","30d"]},"timezone":"","title":"Istio Performance Dashboard","uid":"vu8e0VWZk","version":22}
+  pilot-dashboard.json: |
+    {"annotations":{"list":[{"builtIn":1,"datasource":"-- Grafana --","enable":true,"hide":true,"iconColor":"rgba(0, 211, 255, 1)","name":"Annotations & Alerts","type":"dashboard"}]},"editable":false,"gnetId":null,"graphTooltip":1,"links":[],"panels":[{"collapsed":false,"gridPos":{"h":1,"w":24,"x":0,"y":0},"id":60,"panels":[],"title":"Deployed Versions","type":"row"},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":5,"w":24,"x":0,"y":1},"id":56,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(istio_build{component=\"pilot\"}) by (tag)","format":"time_series","intervalFactor":1,"legendFormat":"{{ tag }}","refId":"A"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Pilot Versions","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":false}],"yaxis":{"align":false,"alignLevel":null}},{"collapsed":false,"gridPos":{"h":1,"w":24,"x":0,"y":6},"id":62,"panels":[],"title":"Resource Usage","type":"row"},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":7,"w":6,"x":0,"y":7},"id":5,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"process_virtual_memory_bytes{app=\"istiod\"}","format":"time_series","instant":false,"intervalFactor":2,"legendFormat":"Virtual Memory","refId":"I","step":2},{"expr":"process_resident_memory_bytes{app=\"istiod\"}","format":"time_series","intervalFactor":2,"legendFormat":"Resident Memory","refId":"H","step":2},{"expr":"go_memstats_heap_sys_bytes{app=\"istiod\"}","format":"time_series","hide":true,"intervalFactor":2,"legendFormat":"heap sys","refId":"A"},{"expr":"go_memstats_heap_alloc_bytes{app=\"istiod\"}","format":"time_series","hide":true,"intervalFactor":2,"legendFormat":"heap alloc","refId":"D"},{"expr":"go_memstats_alloc_bytes{app=\"istiod\"}","format":"time_series","intervalFactor":2,"legendFormat":"Alloc","refId":"F","step":2},{"expr":"go_memstats_heap_inuse_bytes{app=\"istiod\"}","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"Heap in-use","refId":"E","step":2},{"expr":"go_memstats_stack_inuse_bytes{app=\"istiod\"}","format":"time_series","intervalFactor":2,"legendFormat":"Stack in-use","refId":"G","step":2},{"expr":"container_memory_working_set_bytes{container=~\"discovery\", pod=~\"istiod-.*|istio-pilot-.*\"}","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"Discovery (container)","refId":"B","step":2},{"expr":"container_memory_working_set_bytes{container=~\"istio-proxy\", pod=~\"istiod-.*|istio-pilot-.*\"}","format":"time_series","intervalFactor":1,"legendFormat":"Sidecar (container)","refId":"C"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Memory","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"bytes","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":false}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":7,"w":6,"x":6,"y":7},"id":6,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(irate(container_cpu_usage_seconds_total{container=\"discovery\", pod=~\"istiod-.*|istio-pilot-.*\"}[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"Discovery (container)","refId":"A"},{"expr":"irate(process_cpu_seconds_total{app=\"istiod\"}[1m])","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"Discovery (process)","refId":"C","step":2},{"expr":"sum(irate(container_cpu_usage_seconds_total{container=\"istio-proxy\", pod=~\"istiod-.*|istio-pilot-.*\"}[1m]))","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"Sidecar (container)","refId":"B","step":2}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"CPU","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":7,"w":6,"x":12,"y":7},"id":7,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"container_fs_usage_bytes{container=\"discovery\", pod=~\"istiod-.*|istio-pilot-.*\"}","format":"time_series","intervalFactor":2,"legendFormat":"Discovery","refId":"B","step":2},{"expr":"container_fs_usage_bytes{container=\"istio-proxy\", pod=~\"istiod-.*|istio-pilot-.*\"}","format":"time_series","intervalFactor":1,"legendFormat":"Sidecar","refId":"A"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Disk","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"bytes","label":"","logBase":1,"max":null,"min":null,"show":true},{"decimals":null,"format":"none","label":"","logBase":1024,"max":null,"min":null,"show":false}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":7,"w":6,"x":18,"y":7},"id":4,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":false,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"go_goroutines{app=\"istiod\"}","format":"time_series","intervalFactor":2,"legendFormat":"Number of Goroutines","refId":"A","step":2}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Goroutines","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":"","logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"collapsed":false,"gridPos":{"h":1,"w":24,"x":0,"y":14},"id":58,"panels":[],"title":"Pilot Push Information","type":"row"},{"aliasColors":{},"bars":true,"dashLength":10,"dashes":false,"datasource":"Prometheus","description":"Shows the rate of pilot pushes","fill":1,"gridPos":{"h":8,"w":8,"x":0,"y":15},"id":622,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":false,"linewidth":1,"links":[],"nullPointMode":"null as zero","paceLength":10,"percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":true,"steppedLine":false,"targets":[{"expr":"sum(irate(pilot_xds_pushes{type=\"cds\"}[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"Cluster","refId":"C"},{"expr":"sum(irate(pilot_xds_pushes{type=\"eds\"}[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"Endpoints","refId":"D"},{"expr":"sum(irate(pilot_xds_pushes{type=\"lds\"}[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"Listeners","refId":"A"},{"expr":"sum(irate(pilot_xds_pushes{type=\"rds\"}[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"Routes","refId":"E"},{"expr":"sum(irate(pilot_xds_pushes{type=\"sds\"}[1m]))","interval":"","legendFormat":"Secrets","refId":"B"},{"expr":"sum(irate(pilot_xds_pushes{type=\"nds\"}[1m]))","interval":"","legendFormat":"Nametables","refId":"F"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Pilot Pushes","tooltip":{"shared":false,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":["total"]},"yaxes":[{"format":"ops","label":null,"logBase":1,"max":null,"min":"0","show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":false}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","description":"Captures a variety of pilot errors","fill":1,"gridPos":{"h":8,"w":8,"x":8,"y":15},"id":67,"legend":{"avg":false,"current":false,"hideEmpty":true,"hideZero":true,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(pilot_xds_cds_reject{app=\"istiod\"}) or (absent(pilot_xds_cds_reject{app=\"istiod\"}) - 1)","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"Rejected CDS Configs","refId":"C"},{"expr":"sum(pilot_xds_eds_reject{app=\"istiod\"}) or (absent(pilot_xds_eds_reject{app=\"istiod\"}) - 1)","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"Rejected EDS Configs","refId":"D"},{"expr":"sum(pilot_xds_rds_reject{app=\"istiod\"}) or (absent(pilot_xds_rds_reject{app=\"istiod\"}) - 1)","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"Rejected RDS Configs","refId":"A"},{"expr":"sum(pilot_xds_lds_reject{app=\"istiod\"}) or (absent(pilot_xds_lds_reject{app=\"istiod\"}) - 1)","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"Rejected LDS Configs","refId":"B"},{"expr":"sum(rate(pilot_xds_write_timeout{app=\"istiod\"}[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"Write Timeouts","refId":"F"},{"expr":"sum(rate(pilot_total_xds_internal_errors{app=\"istiod\"}[1m]))","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"Internal Errors","refId":"H"},{"expr":"sum(rate(pilot_total_xds_rejects{app=\"istiod\"}[1m]))","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"Config Rejection Rate","refId":"E"},{"expr":"sum(rate(pilot_xds_push_context_errors{app=\"istiod\"}[1m]))","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"Push Context Errors","refId":"K"},{"expr":"sum(rate(pilot_xds_write_timeout{app=\"istiod\"}[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"Push Timeouts","refId":"G"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Pilot Errors","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","description":"Shows the total time it takes to push a config update to a proxy","fill":1,"gridPos":{"h":8,"w":8,"x":16,"y":15},"id":624,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":2,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"histogram_quantile(0.5, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))","format":"time_series","intervalFactor":1,"legendFormat":"p50 ","refId":"A"},{"expr":"histogram_quantile(0.9, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))","format":"time_series","intervalFactor":1,"legendFormat":"p90","refId":"B"},{"expr":"histogram_quantile(0.99, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))","format":"time_series","intervalFactor":1,"legendFormat":"p99","refId":"C"},{"expr":"histogram_quantile(0.999, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))","format":"time_series","intervalFactor":1,"legendFormat":"p99.9","refId":"D"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Proxy Push Time","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"s","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":8,"w":12,"x":0,"y":23},"id":45,"legend":{"avg":false,"current":false,"hideEmpty":true,"hideZero":true,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null as zero","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"pilot_conflict_inbound_listener{app=\"istiod\"}","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"Inbound Listeners","refId":"B"},{"expr":"pilot_conflict_outbound_listener_tcp_over_current_tcp{app=\"istiod\"}","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"Outbound Listeners (tcp over current tcp)","refId":"C"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Conflicts","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":false}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":8,"w":12,"x":12,"y":23},"id":47,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"avg(pilot_virt_services{app=\"istiod\"})","format":"time_series","intervalFactor":1,"legendFormat":"Virtual Services","refId":"A"},{"expr":"avg(pilot_services{app=\"istiod\"})","format":"time_series","intervalFactor":1,"legendFormat":"Services","refId":"B"},{"expr":"sum(pilot_xds{app=\"istiod\"}) by (pod)","format":"time_series","intervalFactor":1,"legendFormat":"Connected Endpoints {{pod}}","refId":"E"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"ADS Monitoring","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"collapsed":false,"gridPos":{"h":1,"w":24,"x":0,"y":31},"id":64,"panels":[],"title":"Envoy Information","type":"row"},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","description":"Shows details about Envoy proxies in the mesh","fill":1,"gridPos":{"h":8,"w":8,"x":0,"y":32},"id":40,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(irate(envoy_cluster_upstream_cx_total{cluster_name=\"xds-grpc\"}[1m]))","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"XDS Connections","refId":"C"},{"expr":"sum(irate(envoy_cluster_upstream_cx_connect_fail{cluster_name=\"xds-grpc\"}[1m]))","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"XDS Connection Failures","refId":"A"},{"expr":"sum(increase(envoy_server_hot_restart_epoch[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"Envoy Restarts","refId":"B"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Envoy Details","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"ops","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"ops","label":null,"logBase":1,"max":null,"min":null,"show":false}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":8,"w":8,"x":8,"y":32},"id":41,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(envoy_cluster_upstream_cx_active{cluster_name=\"xds-grpc\"})","format":"time_series","intervalFactor":2,"legendFormat":"XDS Active Connections","refId":"C","step":2}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"XDS Active Connections","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","description":"Shows the size of XDS requests and responses","fill":1,"gridPos":{"h":8,"w":8,"x":16,"y":32},"id":42,"legend":{"avg":false,"current":false,"hideEmpty":false,"hideZero":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"max(rate(envoy_cluster_upstream_cx_rx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"XDS Response Bytes Max","refId":"D"},{"expr":"quantile(0.5, rate(envoy_cluster_upstream_cx_rx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"XDS Response Bytes Average","refId":"B"},{"expr":"max(rate(envoy_cluster_upstream_cx_tx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"XDS Request Bytes Max","refId":"A"},{"expr":"quantile(.5, rate(envoy_cluster_upstream_cx_tx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"XDS Request Bytes Average","refId":"C"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"XDS Requests Size","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"Bps","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"ops","label":null,"logBase":1,"max":null,"min":null,"show":false}],"yaxis":{"align":false,"alignLevel":null}},{"collapsed":false,"datasource":null,"gridPos":{"h":1,"w":24,"x":0,"y":40},"id":626,"panels":[],"title":"Webhooks","type":"row"},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":null,"fill":1,"fillGradient":0,"gridPos":{"h":8,"w":12,"x":0,"y":41},"hiddenSeries":false,"id":629,"legend":{"avg":false,"current":false,"hideEmpty":false,"hideZero":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"nullPointMode":"null","options":{"dataLinks":[]},"percentage":false,"pointradius":2,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(rate(galley_validation_passed[1m]))","interval":"","legendFormat":"Validations (Success)","refId":"A"},{"expr":"sum(rate(galley_validation_failed[1m]))","interval":"","legendFormat":"Validation (Failure)","refId":"B"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Configuration Validation","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":null,"description":"","fill":1,"fillGradient":0,"gridPos":{"h":8,"w":12,"x":12,"y":41},"hiddenSeries":false,"id":630,"legend":{"avg":false,"current":false,"hideZero":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"nullPointMode":"null","options":{"dataLinks":[]},"percentage":false,"pointradius":2,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(rate(sidecar_injection_success_total[1m]))","interval":"","legendFormat":"Injections (Success)","refId":"A"},{"expr":"sum(rate(sidecar_injection_failure_total[1m]))","interval":"","legendFormat":"Injections (Failure)","refId":"B"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Sidecar Injection","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}}],"refresh":"5s","schemaVersion":18,"style":"dark","tags":[],"templating":{"list":[{"current":{"selected":true,"text":"default","value":"default"},"hide":0,"includeAll":false,"label":null,"multi":false,"name":"datasource","options":[],"query":"prometheus","queryValue":"","refresh":1,"regex":"","skipUrlSync":false,"type":"datasource"}]},"time":{"from":"now-5m","to":"now"},"timepicker":{"refresh_intervals":["5s","10s","30s","1m","5m","15m","30m","1h","2h","1d"],"time_options":["5m","15m","1h","6h","12h","24h","2d","7d","30d"]},"timezone":"browser","title":"Istio Control Plane Dashboard","uid":"3--MLVZZk","version":11}
+kind: ConfigMap
+metadata:
+  creationTimestamp: null
+  name: istio-grafana-dashboards
+  namespace: istio-system
+
+---
+
+apiVersion: v1
+data:
+  istio-extension-dashboard.json: |
+    {"annotations":{"list":[{"builtIn":1,"datasource":"-- Grafana --","enable":true,"hide":true,"iconColor":"rgba(0, 211, 255, 1)","name":"Annotations & Alerts","type":"dashboard"}]},"editable":false,"gnetId":null,"graphTooltip":0,"links":[],"panels":[{"collapsed":false,"datasource":"Prometheus","gridPos":{"h":1,"w":24,"x":0,"y":0},"id":3,"panels":[],"title":"Wasm VMs","type":"row"},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","description":"","fieldConfig":{"defaults":{"custom":{"align":null},"links":[],"mappings":[],"thresholds":{"mode":"absolute","steps":[{"color":"green","value":null},{"color":"red","value":80}]}},"overrides":[]},"fill":1,"fillGradient":0,"gridPos":{"h":8,"w":12,"x":0,"y":1},"hiddenSeries":false,"id":2,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"nullPointMode":"null","options":{"alertThreshold":true},"percentage":false,"pluginVersion":"7.2.1","pointradius":2,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"avg(envoy_wasm_envoy_wasm_runtime_null_active)","interval":"","legendFormat":"native","refId":"A"},{"expr":"avg(envoy_wasm_envoy_wasm_runtime_v8_active)","interval":"","legendFormat":"v8","refId":"B"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Active","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"$$hashKey":"object:123","format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"$$hashKey":"object:124","format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fieldConfig":{"defaults":{"custom":{},"links":[]},"overrides":[]},"fill":1,"fillGradient":0,"gridPos":{"h":8,"w":12,"x":12,"y":1},"hiddenSeries":false,"id":6,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"nullPointMode":"null","options":{"alertThreshold":true},"percentage":false,"pluginVersion":"7.2.1","pointradius":2,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"avg(envoy_wasm_envoy_wasm_runtime_null_created)","interval":"","legendFormat":"native","refId":"A"},{"expr":"avg(envoy_wasm_envoy_wasm_runtime_v8_created)","interval":"","legendFormat":"v8","refId":"B"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Created","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"$$hashKey":"object:68","format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"$$hashKey":"object:69","format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"collapsed":false,"datasource":"Prometheus","gridPos":{"h":1,"w":24,"x":0,"y":9},"id":7,"panels":[],"title":"Wasm Module Remote Load","type":"row"},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fieldConfig":{"defaults":{"custom":{},"links":[]},"overrides":[]},"fill":1,"fillGradient":0,"gridPos":{"h":8,"w":8,"x":0,"y":10},"hiddenSeries":false,"id":11,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"nullPointMode":"null","options":{"alertThreshold":true},"percentage":false,"pluginVersion":"7.2.1","pointradius":2,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"avg(envoy_wasm_remote_load_cache_entries)","interval":"","legendFormat":"entries","refId":"A"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Cache Entry","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"$$hashKey":"object:178","format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"$$hashKey":"object:179","format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fieldConfig":{"defaults":{"custom":{},"links":[]},"overrides":[]},"fill":1,"fillGradient":0,"gridPos":{"h":8,"w":8,"x":8,"y":10},"hiddenSeries":false,"id":8,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"nullPointMode":"null","options":{"alertThreshold":true},"percentage":false,"pluginVersion":"7.2.1","pointradius":2,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"avg(envoy_wasm_remote_load_cache_hits)","interval":"","legendFormat":"hits","refId":"A"},{"expr":"avg(envoy_wasm_remote_load_cache_misses)","interval":"","legendFormat":"misses","refId":"B"},{"expr":"avg(envoy_wasm_remote_load_cache_negative_hits)","interval":"","legendFormat":"negative hits","refId":"C"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Cache Visit","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"$$hashKey":"object:233","format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"$$hashKey":"object:234","format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fieldConfig":{"defaults":{"custom":{},"links":[]},"overrides":[]},"fill":1,"fillGradient":0,"gridPos":{"h":8,"w":8,"x":16,"y":10},"hiddenSeries":false,"id":10,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"nullPointMode":"null","options":{"alertThreshold":true},"percentage":false,"pluginVersion":"7.2.1","pointradius":2,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"avg(envoy_wasm_remote_load_fetch_failures)","interval":"","legendFormat":"failures","refId":"A"},{"expr":"avg(envoy_wasm_remote_load_fetch_successes)","interval":"","legendFormat":"successes","refId":"B"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Remote Fetch","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"$$hashKey":"object:288","format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"$$hashKey":"object:289","format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"collapsed":false,"datasource":"Prometheus","gridPos":{"h":1,"w":24,"x":0,"y":18},"id":71,"panels":[],"title":"Proxy Resource Usage","type":"row"},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fieldConfig":{"defaults":{"custom":{}},"overrides":[]},"fill":1,"fillGradient":0,"gridPos":{"h":8,"w":12,"x":0,"y":19},"hiddenSeries":false,"id":72,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","options":{"alertThreshold":true},"percentage":false,"pluginVersion":"7.2.1","pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(container_memory_working_set_bytes{container=\"istio-proxy\"})","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"Total (k8s)","refId":"A","step":2}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Memory","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"$$hashKey":"object:396","format":"bytes","label":null,"logBase":1,"max":null,"min":null,"show":true},{"$$hashKey":"object:397","format":"short","label":null,"logBase":1,"max":null,"min":null,"show":false}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fieldConfig":{"defaults":{"custom":{}},"overrides":[]},"fill":1,"fillGradient":0,"gridPos":{"h":8,"w":12,"x":12,"y":19},"hiddenSeries":false,"id":73,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","options":{"alertThreshold":true},"percentage":false,"pluginVersion":"7.2.1","pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(rate(container_cpu_usage_seconds_total{container=\"istio-proxy\"}[1m]))","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"Total (k8s)","refId":"A","step":2}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"vCPU","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"$$hashKey":"object:447","format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"$$hashKey":"object:448","format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}}],"refresh":false,"schemaVersion":26,"style":"dark","tags":[],"templating":{"list":[{"current":{"selected":true,"text":"default","value":"default"},"hide":0,"includeAll":false,"label":null,"multi":false,"name":"datasource","options":[],"query":"prometheus","queryValue":"","refresh":1,"regex":"","skipUrlSync":false,"type":"datasource"}]},"time":{"from":"now-5m","to":"now"},"timepicker":{"refresh_intervals":["10s","30s","1m","5m","15m","30m","1h","2h","1d"]},"timezone":"","title":"Istio Wasm Extension Dashboard","uid":"7PAV7ctGz","version":17}
+  istio-mesh-dashboard.json: |
+    {"annotations":{"list":[{"builtIn":1,"datasource":"-- Grafana --","enable":true,"hide":true,"iconColor":"rgba(0, 211, 255, 1)","name":"Annotations & Alerts","type":"dashboard"}]},"editable":false,"gnetId":null,"graphTooltip":0,"id":null,"links":[],"panels":[{"content":"<div>\n  <div style=\"position: absolute; bottom: 0\">\n    <a href=\"https://istio.io\" target=\"_blank\" style=\"font-size: 30px; text-decoration: none; color: inherit\"><img src=\"https://istio.io/latest/img/istio-bluelogo-nobackground-unframed.svg\" style=\"height: 50px\"> Istio</a>\n  </div>\n  <div style=\"position: absolute; bottom: 0; right: 0; font-size: 15px\">\n    Istio is an <a href=\"https://github.com/istio/istio\" target=\"_blank\">open platform</a> that provides a uniform way to <a href=\"https://istio.io/docs/concepts/security/\" target=\"_blank\">secure</a>,\n    <a href=\"https://istio.io/docs/concepts/traffic-management/\" target=\"_blank\">connect</a>, and \n    <a href=\"https://istio.io/docs/concepts/observability/\" target=\"_blank\">monitor</a> microservices.\n    <br>\n    Need help? <a href=\"https://istio.io/get-involved/\" target=\"_blank\">Join the Istio community</a>.\n  </div>\n</div>","gridPos":{"h":3,"w":24,"x":0,"y":0},"height":"50px","id":13,"links":[],"mode":"html","style":{"font-size":"18pt"},"title":"","transparent":true,"type":"text"},{"cacheTimeout":null,"colorBackground":false,"colorValue":false,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"datasource":"Prometheus","format":"ops","gauge":{"maxValue":100,"minValue":0,"show":false,"thresholdLabels":false,"thresholdMarkers":true},"gridPos":{"h":3,"w":6,"x":0,"y":3},"id":20,"interval":null,"links":[],"options":{"colorMode":"value","graphMode":"area","justifyMode":"auto","orientation":"horizontal","reduceOptions":{"calcs":["lastNotNull"],"fields":"","values":false},"textMode":"auto"},"mappingType":1,"mappingTypes":[{"name":"value to text","value":1},{"name":"range to text","value":2}],"maxDataPoints":100,"nullPointMode":"connected","nullText":null,"postfix":"","postfixFontSize":"50%","prefix":"","prefixFontSize":"50%","rangeMaps":[{"from":"null","text":"N/A","to":"null"}],"sparkline":{"fillColor":"rgba(31, 118, 189, 0.18)","full":true,"lineColor":"rgb(31, 120, 193)","show":true},"tableColumn":"","targets":[{"expr":"round(sum(irate(istio_requests_total{reporter=\"source\"}[1m])), 0.001)","intervalFactor":1,"refId":"A","step":4}],"thresholds":"","title":"Global Request Volume","type":"singlestat","valueFontSize":"80%","valueMaps":[{"op":"=","text":"N/A","value":"null"}],"valueName":"avg"},{"cacheTimeout":null,"colorBackground":false,"colorValue":false,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"datasource":"Prometheus","format":"percentunit","gauge":{"maxValue":100,"minValue":80,"show":false,"thresholdLabels":false,"thresholdMarkers":false},"gridPos":{"h":3,"w":6,"x":6,"y":3},"id":21,"interval":null,"links":[],"options":{"colorMode":"value","graphMode":"area","justifyMode":"auto","orientation":"horizontal","reduceOptions":{"calcs":["lastNotNull"],"fields":"","values":false},"textMode":"auto"},"mappingType":1,"mappingTypes":[{"name":"value to text","value":1},{"name":"range to text","value":2}],"maxDataPoints":100,"nullPointMode":"connected","nullText":null,"postfix":"","postfixFontSize":"50%","prefix":"","prefixFontSize":"50%","rangeMaps":[{"from":"null","text":"N/A","to":"null"}],"sparkline":{"fillColor":"rgba(31, 118, 189, 0.18)","full":true,"lineColor":"rgb(31, 120, 193)","show":true},"tableColumn":"","targets":[{"expr":"sum(rate(istio_requests_total{reporter=\"source\", response_code!~\"5.*\"}[1m])) / sum(rate(istio_requests_total{reporter=\"source\"}[1m]))","format":"time_series","intervalFactor":1,"refId":"A","step":4}],"thresholds":"95, 99, 99.5","title":"Global Success Rate (non-5xx responses)","type":"singlestat","valueFontSize":"80%","valueMaps":[{"op":"=","text":"N/A","value":"null"}],"valueName":"avg"},{"cacheTimeout":null,"colorBackground":false,"colorValue":false,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"datasource":"Prometheus","format":"ops","gauge":{"maxValue":100,"minValue":0,"show":false,"thresholdLabels":false,"thresholdMarkers":true},"gridPos":{"h":3,"w":6,"x":12,"y":3},"id":22,"interval":null,"links":[],"options":{"colorMode":"value","graphMode":"area","justifyMode":"auto","orientation":"horizontal","reduceOptions":{"calcs":["lastNotNull"],"fields":"","values":false},"textMode":"auto"},"mappingType":1,"mappingTypes":[{"name":"value to text","value":1},{"name":"range to text","value":2}],"maxDataPoints":100,"nullPointMode":"connected","nullText":null,"postfix":"","postfixFontSize":"50%","prefix":"","prefixFontSize":"50%","rangeMaps":[{"from":"null","text":"N/A","to":"null"}],"sparkline":{"fillColor":"rgba(31, 118, 189, 0.18)","full":true,"lineColor":"rgb(31, 120, 193)","show":true},"tableColumn":"","targets":[{"expr":"sum(irate(istio_requests_total{reporter=\"source\", response_code=~\"4.*\"}[1m]))","format":"time_series","intervalFactor":1,"refId":"A","step":4}],"thresholds":"","title":"4xxs","type":"singlestat","valueFontSize":"80%","valueMaps":[{"op":"=","text":"N/A","value":"null"}],"valueName":"avg"},{"cacheTimeout":null,"colorBackground":false,"colorValue":false,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"datasource":"Prometheus","format":"ops","gauge":{"maxValue":100,"minValue":0,"show":false,"thresholdLabels":false,"thresholdMarkers":true},"gridPos":{"h":3,"w":6,"x":18,"y":3},"id":23,"interval":null,"links":[],"options":{"colorMode":"value","graphMode":"area","justifyMode":"auto","orientation":"horizontal","reduceOptions":{"calcs":["lastNotNull"],"fields":"","values":false},"textMode":"auto"},"mappingType":1,"mappingTypes":[{"name":"value to text","value":1},{"name":"range to text","value":2}],"maxDataPoints":100,"nullPointMode":"connected","nullText":null,"postfix":"","postfixFontSize":"50%","prefix":"","prefixFontSize":"50%","rangeMaps":[{"from":"null","text":"N/A","to":"null"}],"sparkline":{"fillColor":"rgba(31, 118, 189, 0.18)","full":true,"lineColor":"rgb(31, 120, 193)","show":true},"tableColumn":"","targets":[{"expr":"sum(irate(istio_requests_total{reporter=\"source\", response_code=~\"5.*\"}[1m]))","format":"time_series","intervalFactor":1,"refId":"A","step":4}],"thresholds":"","title":"5xxs","type":"singlestat","valueFontSize":"80%","valueMaps":[{"op":"=","text":"N/A","value":"null"}],"valueName":"avg"},{"cacheTimeout":null,"colorBackground":false,"colorValue":false,"colors":["#299c46","rgba(237, 129, 40, 0.89)","#d44a3a"],"datasource":"Prometheus","format":"none","gauge":{"maxValue":100,"minValue":0,"show":false,"thresholdLabels":false,"thresholdMarkers":true},"gridPos":{"h":3,"w":6,"x":0,"y":6},"id":113,"interval":null,"links":[],"options":{"colorMode":"value","graphMode":"area","justifyMode":"auto","orientation":"horizontal","reduceOptions":{"calcs":["lastNotNull"],"fields":"","values":false},"textMode":"auto"},"mappingType":1,"mappingTypes":[{"name":"value to text","value":1},{"name":"range to text","value":2}],"maxDataPoints":100,"nullPointMode":"connected","nullText":null,"postfix":"","postfixFontSize":"50%","prefix":"","prefixFontSize":"50%","rangeMaps":[{"from":"null","text":"N/A","to":"null"}],"sparkline":{"fillColor":"rgba(31, 118, 189, 0.18)","full":false,"lineColor":"rgb(31, 120, 193)","show":true},"tableColumn":"","targets":[{"expr":"max(pilot_k8s_cfg_events{type=\"VirtualService\", event=\"add\"}) - (max(pilot_k8s_cfg_events{type=\"VirtualService\", event=\"delete\"}) or max(up * 0))","format":"time_series","intervalFactor":1,"refId":"A"}],"thresholds":"","timeFrom":null,"timeShift":null,"title":"Virtual Services","type":"singlestat","valueFontSize":"80%","valueMaps":[{"op":"=","text":"N/A","value":"null"}],"valueName":"current"},{"cacheTimeout":null,"colorBackground":false,"colorValue":false,"colors":["#299c46","rgba(237, 129, 40, 0.89)","#d44a3a"],"datasource":"Prometheus","format":"none","gauge":{"maxValue":100,"minValue":0,"show":false,"thresholdLabels":false,"thresholdMarkers":true},"gridPos":{"h":3,"w":6,"x":6,"y":6},"id":114,"interval":null,"links":[],"options":{"colorMode":"value","graphMode":"area","justifyMode":"auto","orientation":"horizontal","reduceOptions":{"calcs":["lastNotNull"],"fields":"","values":false},"textMode":"auto"},"mappingType":1,"mappingTypes":[{"name":"value to text","value":1},{"name":"range to text","value":2}],"maxDataPoints":100,"nullPointMode":"connected","nullText":null,"postfix":"","postfixFontSize":"50%","prefix":"","prefixFontSize":"50%","rangeMaps":[{"from":"null","text":"N/A","to":"null"}],"sparkline":{"fillColor":"rgba(31, 118, 189, 0.18)","full":false,"lineColor":"rgb(31, 120, 193)","show":true},"tableColumn":"","targets":[{"expr":"max(pilot_k8s_cfg_events{type=\"DestinationRule\", event=\"add\"}) - (max(pilot_k8s_cfg_events{type=\"DestinationRule\", event=\"delete\"}) or max(up * 0))","format":"time_series","intervalFactor":1,"refId":"A"}],"thresholds":"","timeFrom":null,"timeShift":null,"title":"Destination Rules","type":"singlestat","valueFontSize":"80%","valueMaps":[{"op":"=","text":"N/A","value":"null"}],"valueName":"current"},{"cacheTimeout":null,"colorBackground":false,"colorValue":false,"colors":["#299c46","rgba(237, 129, 40, 0.89)","#d44a3a"],"datasource":"Prometheus","format":"none","gauge":{"maxValue":100,"minValue":0,"show":false,"thresholdLabels":false,"thresholdMarkers":true},"gridPos":{"h":3,"w":6,"x":12,"y":6},"id":115,"interval":null,"links":[],"options":{"colorMode":"value","graphMode":"area","justifyMode":"auto","orientation":"horizontal","reduceOptions":{"calcs":["lastNotNull"],"fields":"","values":false},"textMode":"auto"},"mappingType":1,"mappingTypes":[{"name":"value to text","value":1},{"name":"range to text","value":2}],"maxDataPoints":100,"nullPointMode":"connected","nullText":null,"postfix":"","postfixFontSize":"50%","prefix":"","prefixFontSize":"50%","rangeMaps":[{"from":"null","text":"N/A","to":"null"}],"sparkline":{"fillColor":"rgba(31, 118, 189, 0.18)","full":false,"lineColor":"rgb(31, 120, 193)","show":true},"tableColumn":"","targets":[{"expr":"max(pilot_k8s_cfg_events{type=\"Gateway\", event=\"add\"}) - (max(pilot_k8s_cfg_events{type=\"Gateway\", event=\"delete\"}) or max(up * 0))","format":"time_series","intervalFactor":1,"refId":"A"}],"thresholds":"","timeFrom":null,"timeShift":null,"title":"Gateways","type":"singlestat","valueFontSize":"80%","valueMaps":[{"op":"=","text":"N/A","value":"null"}],"valueName":"current"},{"cacheTimeout":null,"colorBackground":false,"colorValue":false,"colors":["#299c46","rgba(237, 129, 40, 0.89)","#d44a3a"],"datasource":"Prometheus","format":"none","gauge":{"maxValue":100,"minValue":0,"show":false,"thresholdLabels":false,"thresholdMarkers":true},"gridPos":{"h":3,"w":6,"x":18,"y":6},"id":116,"interval":null,"links":[],"options":{"colorMode":"value","graphMode":"area","justifyMode":"auto","orientation":"horizontal","reduceOptions":{"calcs":["lastNotNull"],"fields":"","values":false},"textMode":"auto"},"mappingType":1,"mappingTypes":[{"name":"value to text","value":1},{"name":"range to text","value":2}],"maxDataPoints":100,"nullPointMode":"connected","nullText":null,"postfix":"","postfixFontSize":"50%","prefix":"","prefixFontSize":"50%","rangeMaps":[{"from":"null","text":"N/A","to":"null"}],"sparkline":{"fillColor":"rgba(31, 118, 189, 0.18)","full":false,"lineColor":"rgb(31, 120, 193)","show":true},"tableColumn":"","targets":[{"expr":"max(pilot_k8s_cfg_events{type=\"WorkloadEntry\", event=\"add\"}) - (max(pilot_k8s_cfg_events{type=\"WorkloadEntry\", event=\"delete\"}) or max(up * 0))","format":"time_series","intervalFactor":1,"refId":"A"}],"thresholds":"","timeFrom":null,"timeShift":null,"title":"Workload Entries","type":"singlestat","valueFontSize":"80%","valueMaps":[{"op":"=","text":"N/A","value":"null"}],"valueName":"current"},{"cacheTimeout":null,"colorBackground":false,"colorValue":false,"colors":["#299c46","rgba(237, 129, 40, 0.89)","#d44a3a"],"datasource":"Prometheus","format":"none","gauge":{"maxValue":100,"minValue":0,"show":false,"thresholdLabels":false,"thresholdMarkers":true},"gridPos":{"h":3,"w":6,"x":0,"y":6},"id":117,"interval":null,"links":[],"options":{"colorMode":"value","graphMode":"area","justifyMode":"auto","orientation":"horizontal","reduceOptions":{"calcs":["lastNotNull"],"fields":"","values":false},"textMode":"auto"},"mappingType":1,"mappingTypes":[{"name":"value to text","value":1},{"name":"range to text","value":2}],"maxDataPoints":100,"nullPointMode":"connected","nullText":null,"postfix":"","postfixFontSize":"50%","prefix":"","prefixFontSize":"50%","rangeMaps":[{"from":"null","text":"N/A","to":"null"}],"sparkline":{"fillColor":"rgba(31, 118, 189, 0.18)","full":false,"lineColor":"rgb(31, 120, 193)","show":true},"tableColumn":"","targets":[{"expr":"max(pilot_k8s_cfg_events{type=\"ServiceEntry\", event=\"add\"}) - (max(pilot_k8s_cfg_events{type=\"ServiceEntry\", event=\"delete\"}) or max(up * 0))","format":"time_series","intervalFactor":1,"refId":"A"}],"thresholds":"","timeFrom":null,"timeShift":null,"title":"Service Entries","type":"singlestat","valueFontSize":"80%","valueMaps":[{"op":"=","text":"N/A","value":"null"}],"valueName":"current"},{"cacheTimeout":null,"colorBackground":false,"colorValue":false,"colors":["#299c46","rgba(237, 129, 40, 0.89)","#d44a3a"],"datasource":"Prometheus","format":"none","gauge":{"maxValue":100,"minValue":0,"show":false,"thresholdLabels":false,"thresholdMarkers":true},"gridPos":{"h":3,"w":6,"x":6,"y":6},"id":90,"interval":null,"links":[],"options":{"colorMode":"value","graphMode":"area","justifyMode":"auto","orientation":"horizontal","reduceOptions":{"calcs":["lastNotNull"],"fields":"","values":false},"textMode":"auto"},"mappingType":1,"mappingTypes":[{"name":"value to text","value":1},{"name":"range to text","value":2}],"maxDataPoints":100,"nullPointMode":"connected","nullText":null,"postfix":"","postfixFontSize":"50%","prefix":"","prefixFontSize":"50%","rangeMaps":[{"from":"null","text":"N/A","to":"null"}],"sparkline":{"fillColor":"rgba(31, 118, 189, 0.18)","full":false,"lineColor":"rgb(31, 120, 193)","show":true},"tableColumn":"","targets":[{"expr":"max(pilot_k8s_cfg_events{type=\"PeerAuthentication\", event=\"add\"}) - (max(pilot_k8s_cfg_events{type=\"PeerAuthentication\", event=\"delete\"}) or max(up * 0))","format":"time_series","intervalFactor":1,"refId":"A"}],"thresholds":"","timeFrom":null,"timeShift":null,"title":"PeerAuthentication Policies","type":"singlestat","valueFontSize":"80%","valueMaps":[{"op":"=","text":"N/A","value":"null"}],"valueName":"current"},{"cacheTimeout":null,"colorBackground":false,"colorValue":false,"colors":["#299c46","rgba(237, 129, 40, 0.89)","#d44a3a"],"datasource":"Prometheus","format":"none","gauge":{"maxValue":100,"minValue":0,"show":false,"thresholdLabels":false,"thresholdMarkers":true},"gridPos":{"h":3,"w":6,"x":12,"y":6},"id":91,"interval":null,"links":[],"options":{"colorMode":"value","graphMode":"area","justifyMode":"auto","orientation":"horizontal","reduceOptions":{"calcs":["lastNotNull"],"fields":"","values":false},"textMode":"auto"},"mappingType":1,"mappingTypes":[{"name":"value to text","value":1},{"name":"range to text","value":2}],"maxDataPoints":100,"nullPointMode":"connected","nullText":null,"postfix":"","postfixFontSize":"50%","prefix":"","prefixFontSize":"50%","rangeMaps":[{"from":"null","text":"N/A","to":"null"}],"sparkline":{"fillColor":"rgba(31, 118, 189, 0.18)","full":false,"lineColor":"rgb(31, 120, 193)","show":true},"tableColumn":"","targets":[{"expr":"max(pilot_k8s_cfg_events{type=\"RequestAuthentication\", event=\"add\"}) - (max(pilot_k8s_cfg_events{type=\"RequestAuthentication\", event=\"delete\"}) or max(up * 0))","format":"time_series","intervalFactor":1,"refId":"A"}],"thresholds":"","timeFrom":null,"timeShift":null,"title":"RequestAuthentication Policies","type":"singlestat","valueFontSize":"80%","valueMaps":[{"op":"=","text":"N/A","value":"null"}],"valueName":"current"},{"cacheTimeout":null,"colorBackground":false,"colorValue":false,"colors":["#299c46","rgba(237, 129, 40, 0.89)","#d44a3a"],"datasource":"Prometheus","format":"none","gauge":{"maxValue":100,"minValue":0,"show":false,"thresholdLabels":false,"thresholdMarkers":true},"gridPos":{"h":3,"w":6,"x":18,"y":6},"id":92,"interval":null,"links":[],"options":{"colorMode":"value","graphMode":"area","justifyMode":"auto","orientation":"horizontal","reduceOptions":{"calcs":["lastNotNull"],"fields":"","values":false},"textMode":"auto"},"mappingType":1,"mappingTypes":[{"name":"value to text","value":1},{"name":"range to text","value":2}],"maxDataPoints":100,"nullPointMode":"connected","nullText":null,"postfix":"","postfixFontSize":"50%","prefix":"","prefixFontSize":"50%","rangeMaps":[{"from":"null","text":"N/A","to":"null"}],"sparkline":{"fillColor":"rgba(31, 118, 189, 0.18)","full":false,"lineColor":"rgb(31, 120, 193)","show":true},"tableColumn":"","targets":[{"expr":"max(pilot_k8s_cfg_events{type=\"AuthorizationPolicy\", event=\"add\"}) - (max(pilot_k8s_cfg_events{type=\"AuthorizationPolicy\", event=\"delete\"}) or max(up * 0))","format":"time_series","intervalFactor":1,"refId":"A"}],"thresholds":"","timeFrom":null,"timeShift":null,"title":"Authorization Policies","type":"singlestat","valueFontSize":"80%","valueMaps":[{"op":"=","text":"N/A","value":"null"}],"valueName":"current"},{"columns":[],"datasource":"Prometheus","fontSize":"100%","gridPos":{"h":21,"w":24,"x":0,"y":9},"hideTimeOverride":false,"id":73,"links":[],"pageSize":null,"repeat":null,"repeatDirection":"v","scroll":true,"showHeader":true,"sort":{"col":5,"desc":true},"styles":[{"alias":"Workload","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"link":false,"linkTargetBlank":false,"linkTooltip":"Workload dashboard","linkUrl":"/dashboard/db/istio-workload-dashboard?var-namespace=${__cell_3:raw}&var-workload=${__cell_2:raw}","pattern":"destination_workload","preserveFormat":false,"sanitize":false,"thresholds":[],"type":"hidden","unit":"short"},{"alias":"","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"pattern":"Time","thresholds":[],"type":"hidden","unit":"short"},{"alias":"Requests","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"pattern":"Value #A","thresholds":[],"type":"number","unit":"ops"},{"alias":"P50 Latency","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"pattern":"Value #B","thresholds":[],"type":"number","unit":"s"},{"alias":"P90 Latency","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"pattern":"Value #C","thresholds":[],"type":"number","unit":"s"},{"alias":"P99 Latency","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"pattern":"Value #D","thresholds":[],"type":"number","unit":"s"},{"alias":"Success Rate","colorMode":"cell","colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"pattern":"Value #E","thresholds":[".95"," 1.00"],"type":"number","unit":"percentunit"},{"alias":"Workload","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"link":true,"linkTooltip":"$__cell dashboard","linkUrl":"/dashboard/db/istio-workload-dashboard?var-workload=${__cell_2:raw}&var-namespace=${__cell_3:raw}","pattern":"destination_workload_var","thresholds":[],"type":"number","unit":"short"},{"alias":"Service","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"link":true,"linkTooltip":"$__cell dashboard","linkUrl":"/dashboard/db/istio-service-dashboard?var-service=${__cell_1:raw}","pattern":"destination_service","thresholds":[],"type":"string","unit":"short"},{"alias":"","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"pattern":"destination_workload_namespace","thresholds":[],"type":"hidden","unit":"short"}],"targets":[{"expr":"label_join(sum(rate(istio_requests_total{reporter=\"source\", response_code=\"200\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")","format":"table","hide":false,"instant":true,"intervalFactor":1,"legendFormat":"{{ destination_workload}}.{{ destination_workload_namespace }}","refId":"A"},{"expr":"label_join((histogram_quantile(0.50, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"source\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.50, sum(rate(istio_request_duration_seconds_bucket{reporter=\"source\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")","format":"table","hide":false,"instant":true,"intervalFactor":1,"legendFormat":"{{ destination_workload}}.{{ destination_workload_namespace }}","refId":"B"},{"expr":"label_join((histogram_quantile(0.90, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"source\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.90, sum(rate(istio_request_duration_seconds_bucket{reporter=\"source\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")","format":"table","hide":false,"instant":true,"intervalFactor":1,"legendFormat":"{{ destination_workload }}.{{ destination_workload_namespace }}","refId":"C"},{"expr":"label_join((histogram_quantile(0.99, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"source\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.99, sum(rate(istio_request_duration_seconds_bucket{reporter=\"source\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")","format":"table","hide":false,"instant":true,"intervalFactor":1,"legendFormat":"{{ destination_workload }}.{{ destination_workload_namespace }}","refId":"D"},{"expr":"label_join((sum(rate(istio_requests_total{reporter=\"source\", response_code!~\"5.*\"}[1m])) by (destination_workload, destination_workload_namespace) / sum(rate(istio_requests_total{reporter=\"source\"}[1m])) by (destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")","format":"table","hide":false,"instant":true,"interval":"","intervalFactor":1,"legendFormat":"{{ destination_workload }}.{{ destination_workload_namespace }}","refId":"E"}],"timeFrom":null,"title":"HTTP/GRPC Workloads","transform":"table","type":"table"},{"columns":[],"datasource":"Prometheus","fontSize":"100%","gridPos":{"h":18,"w":24,"x":0,"y":30},"hideTimeOverride":false,"id":109,"links":[],"pageSize":null,"repeatDirection":"v","scroll":true,"showHeader":true,"sort":{"col":5,"desc":true},"styles":[{"alias":"Workload","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"link":false,"linkTargetBlank":false,"linkTooltip":"$__cell dashboard","linkUrl":"/dashboard/db/istio-workload-dashboard?var-namespace=${__cell_3:raw}&var-workload=${__cell_2:raw}","pattern":"destination_workload","preserveFormat":false,"sanitize":false,"thresholds":[],"type":"hidden","unit":"short"},{"alias":"Bytes Sent","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"pattern":"Value #A","thresholds":[""],"type":"number","unit":"Bps"},{"alias":"Bytes Received","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"pattern":"Value #B","thresholds":[],"type":"number","unit":"Bps"},{"alias":"","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"pattern":"Time","thresholds":[],"type":"hidden","unit":"short"},{"alias":"Workload","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"link":true,"linkTooltip":"$__cell dashboard","linkUrl":"/dashboard/db/istio-workload-dashboard?var-namespace=${__cell_3:raw}&var-workload=${__cell_2:raw}","pattern":"destination_workload_var","thresholds":[],"type":"string","unit":"short"},{"alias":"","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"pattern":"destination_workload_namespace","thresholds":[],"type":"hidden","unit":"short"},{"alias":"Service","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"link":true,"linkTooltip":"$__cell dashboard","linkUrl":"/dashboard/db/istio-service-dashboard?var-service=${__cell_1:raw}","pattern":"destination_service","thresholds":[],"type":"number","unit":"short"}],"targets":[{"expr":"label_join(sum(rate(istio_tcp_received_bytes_total{reporter=\"source\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")","format":"table","hide":false,"instant":true,"intervalFactor":1,"legendFormat":"{{ destination_workload }}","refId":"A"},{"expr":"label_join(sum(rate(istio_tcp_sent_bytes_total{reporter=\"source\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")","format":"table","hide":false,"instant":true,"intervalFactor":1,"legendFormat":"{{ destination_workload }}","refId":"B"}],"timeFrom":null,"title":"TCP Workloads","transform":"table","type":"table"},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":9,"w":24,"x":0,"y":48},"id":111,"legend":{"alignAsTable":false,"avg":false,"current":false,"max":false,"min":false,"rightSide":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(istio_build) by (component, tag)","format":"time_series","intervalFactor":1,"legendFormat":"{{ component }}: {{ tag }}","refId":"A"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Istio Components by Version","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":false}],"yaxis":{"align":false,"alignLevel":null}}],"refresh":"5s","schemaVersion":18,"style":"dark","tags":[],"templating":{"list":[{"current":{"selected":true,"text":"default","value":"default"},"hide":0,"includeAll":false,"label":null,"multi":false,"name":"datasource","options":[],"query":"prometheus","queryValue":"","refresh":1,"regex":"","skipUrlSync":false,"type":"datasource"}]},"time":{"from":"now-5m","to":"now"},"timepicker":{"refresh_intervals":["5s","10s","30s","1m","5m","15m","30m","1h","2h","1d"],"time_options":["5m","15m","1h","6h","12h","24h","2d","7d","30d"]},"timezone":"browser","title":"Istio Mesh Dashboard","uid":"G8wLrJIZk","version":5}
+  istio-service-dashboard.json: "{\"annotations\":{\"list\":[{\"builtIn\":1,\"datasource\":\"--
+    Grafana --\",\"enable\":true,\"hide\":true,\"iconColor\":\"rgba(0, 211, 255, 1)\",\"name\":\"Annotations
+    & Alerts\",\"type\":\"dashboard\"}]},\"editable\":false,\"gnetId\":null,\"graphTooltip\":0,\"iteration\":1595591291797,\"links\":[],\"panels\":[{\"collapsed\":true,\"gridPos\":{\"h\":1,\"w\":24,\"x\":0,\"y\":0},\"id\":106,\"panels\":[{\"content\":\"<div
+    class=\\\"dashboard-header text-center\\\">\\n<span>SERVICE: $service</span>\\n</div>\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"gridPos\":{\"h\":3,\"w\":24,\"x\":0,\"y\":1},\"id\":89,\"links\":[],\"mode\":\"html\",\"options\":{\"content\":\"<div
+    class=\\\"dashboard-header text-center\\\">\\n<span>SERVICE: $service</span>\\n</div>\",\"mode\":\"html\"},\"pluginVersion\":\"7.1.0\",\"title\":\"\",\"transparent\":true,\"type\":\"text\"},{\"cacheTimeout\":null,\"colorBackground\":false,\"colorValue\":false,\"colors\":[\"rgba(245,
+    54, 54, 0.9)\",\"rgba(237, 129, 40, 0.89)\",\"rgba(50, 172, 45, 0.97)\"],\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"format\":\"ops\",\"gauge\":{\"maxValue\":100,\"minValue\":0,\"show\":false,\"thresholdLabels\":false,\"thresholdMarkers\":true},\"gridPos\":{\"h\":4,\"w\":6,\"x\":0,\"y\":4},\"id\":12,\"interval\":null,\"links\":[],\"options\":{\"colorMode\":\"value\",\"graphMode\":\"area\",\"justifyMode\":\"auto\",\"orientation\":\"horizontal\",\"reduceOptions\":{\"calcs\":[\"lastNotNull\"],\"fields\":\"\",\"values\":false},\"textMode\":\"auto\"},\"mappingType\":1,\"mappingTypes\":[{\"name\":\"value
+    to text\",\"value\":1},{\"name\":\"range to text\",\"value\":2}],\"maxDataPoints\":100,\"nullPointMode\":\"connected\",\"nullText\":null,\"postfix\":\"\",\"postfixFontSize\":\"50%\",\"prefix\":\"\",\"prefixFontSize\":\"50%\",\"rangeMaps\":[{\"from\":\"null\",\"text\":\"N/A\",\"to\":\"null\"}],\"sparkline\":{\"fillColor\":\"rgba(31,
+    118, 189, 0.18)\",\"full\":true,\"lineColor\":\"rgb(31, 120, 193)\",\"show\":true},\"tableColumn\":\"\",\"targets\":[{\"expr\":\"round(sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\",destination_service=~\\\"$service\\\"}[5m])),
+    0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"refId\":\"A\",\"step\":4}],\"thresholds\":\"\",\"title\":\"Client
+    Request Volume\",\"type\":\"singlestat\",\"valueFontSize\":\"80%\",\"valueMaps\":[{\"op\":\"=\",\"text\":\"N/A\",\"value\":\"null\"}],\"valueName\":\"current\"},{\"cacheTimeout\":null,\"colorBackground\":false,\"colorValue\":false,\"colors\":[\"rgba(50,
+    172, 45, 0.97)\",\"rgba(237, 129, 40, 0.89)\",\"rgba(245, 54, 54, 0.9)\"],\"datasource\":\"Prometheus\",\"decimals\":null,\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"format\":\"percentunit\",\"gauge\":{\"maxValue\":100,\"minValue\":80,\"show\":false,\"thresholdLabels\":false,\"thresholdMarkers\":false},\"gridPos\":{\"h\":4,\"w\":6,\"x\":6,\"y\":4},\"id\":14,\"interval\":null,\"links\":[],\"options\":{\"colorMode\":\"value\",\"graphMode\":\"area\",\"justifyMode\":\"auto\",\"orientation\":\"horizontal\",\"reduceOptions\":{\"calcs\":[\"lastNotNull\"],\"fields\":\"\",\"values\":false},\"textMode\":\"auto\"},\"mappingType\":1,\"mappingTypes\":[{\"name\":\"value
+    to text\",\"value\":1},{\"name\":\"range to text\",\"value\":2}],\"maxDataPoints\":100,\"nullPointMode\":\"connected\",\"nullText\":null,\"postfix\":\"\",\"postfixFontSize\":\"50%\",\"prefix\":\"\",\"prefixFontSize\":\"50%\",\"rangeMaps\":[{\"from\":\"null\",\"text\":\"N/A\",\"to\":\"null\"}],\"sparkline\":{\"fillColor\":\"rgba(31,
+    118, 189, 0.18)\",\"full\":true,\"lineColor\":\"rgb(31, 120, 193)\",\"show\":true},\"tableColumn\":\"\",\"targets\":[{\"expr\":\"sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\",destination_service=~\\\"$service\\\",response_code!~\\\"5.*\\\"}[5m]))
+    / sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\",destination_service=~\\\"$service\\\"}[5m]))\",\"format\":\"time_series\",\"intervalFactor\":1,\"refId\":\"A\"}],\"thresholds\":\"95,
+    99, 99.5\",\"title\":\"Client Success Rate (non-5xx responses)\",\"type\":\"singlestat\",\"valueFontSize\":\"80%\",\"valueMaps\":[{\"op\":\"=\",\"text\":\"N/A\",\"value\":\"null\"}],\"valueName\":\"avg\"},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":4,\"w\":6,\"x\":12,\"y\":4},\"hiddenSeries\":false,\"id\":87,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":false,\"hideZero\":false,\"max\":false,\"min\":false,\"rightSide\":true,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"(histogram_quantile(0.50,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",destination_service=~\\\"$service\\\"}[1m]))
+    by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",destination_service=~\\\"$service\\\"}[1m]))
+    by (le))\",\"format\":\"time_series\",\"interval\":\"\",\"intervalFactor\":1,\"legendFormat\":\"P50\",\"refId\":\"A\"},{\"expr\":\"(histogram_quantile(0.90,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",destination_service=~\\\"$service\\\"}[1m]))
+    by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",destination_service=~\\\"$service\\\"}[1m]))
+    by (le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"P90\",\"refId\":\"B\"},{\"expr\":\"(histogram_quantile(0.99,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",destination_service=~\\\"$service\\\"}[1m]))
+    by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",destination_service=~\\\"$service\\\"}[1m]))
+    by (le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"P99\",\"refId\":\"C\"}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Client
+    Request Duration\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"s\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"cacheTimeout\":null,\"colorBackground\":false,\"colorValue\":false,\"colors\":[\"#299c46\",\"rgba(237,
+    129, 40, 0.89)\",\"#d44a3a\"],\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"format\":\"Bps\",\"gauge\":{\"maxValue\":100,\"minValue\":0,\"show\":false,\"thresholdLabels\":false,\"thresholdMarkers\":true},\"gridPos\":{\"h\":4,\"w\":6,\"x\":18,\"y\":4},\"id\":84,\"interval\":null,\"links\":[],\"options\":{\"colorMode\":\"value\",\"graphMode\":\"area\",\"justifyMode\":\"auto\",\"orientation\":\"horizontal\",\"reduceOptions\":{\"calcs\":[\"lastNotNull\"],\"fields\":\"\",\"values\":false},\"textMode\":\"auto\"},\"mappingType\":1,\"mappingTypes\":[{\"name\":\"value
+    to text\",\"value\":1},{\"name\":\"range to text\",\"value\":2}],\"maxDataPoints\":100,\"nullPointMode\":\"connected\",\"nullText\":null,\"postfix\":\"\",\"postfixFontSize\":\"50%\",\"prefix\":\"\",\"prefixFontSize\":\"50%\",\"rangeMaps\":[{\"from\":\"null\",\"text\":\"N/A\",\"to\":\"null\"}],\"sparkline\":{\"fillColor\":\"rgba(31,
+    118, 189, 0.18)\",\"full\":true,\"lineColor\":\"rgb(31, 120, 193)\",\"show\":true},\"tableColumn\":\"\",\"targets\":[{\"expr\":\"sum(irate(istio_tcp_received_bytes_total{reporter=~\\\"$qrep\\\",
+    destination_service=~\\\"$service\\\"}[1m]))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"\",\"refId\":\"A\"}],\"thresholds\":\"\",\"title\":\"TCP
+    Received Bytes\",\"type\":\"singlestat\",\"valueFontSize\":\"80%\",\"valueMaps\":[{\"op\":\"=\",\"text\":\"N/A\",\"value\":\"null\"}],\"valueName\":\"avg\"},{\"cacheTimeout\":null,\"colorBackground\":false,\"colorValue\":false,\"colors\":[\"rgba(245,
+    54, 54, 0.9)\",\"rgba(237, 129, 40, 0.89)\",\"rgba(50, 172, 45, 0.97)\"],\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"format\":\"ops\",\"gauge\":{\"maxValue\":100,\"minValue\":0,\"show\":false,\"thresholdLabels\":false,\"thresholdMarkers\":true},\"gridPos\":{\"h\":4,\"w\":6,\"x\":0,\"y\":8},\"id\":97,\"interval\":null,\"links\":[],\"options\":{\"colorMode\":\"value\",\"graphMode\":\"area\",\"justifyMode\":\"auto\",\"orientation\":\"horizontal\",\"reduceOptions\":{\"calcs\":[\"lastNotNull\"],\"fields\":\"\",\"values\":false},\"textMode\":\"auto\"},\"mappingType\":1,\"mappingTypes\":[{\"name\":\"value
+    to text\",\"value\":1},{\"name\":\"range to text\",\"value\":2}],\"maxDataPoints\":100,\"nullPointMode\":\"connected\",\"nullText\":null,\"postfix\":\"\",\"postfixFontSize\":\"50%\",\"prefix\":\"\",\"prefixFontSize\":\"50%\",\"rangeMaps\":[{\"from\":\"null\",\"text\":\"N/A\",\"to\":\"null\"}],\"sparkline\":{\"fillColor\":\"rgba(31,
+    118, 189, 0.18)\",\"full\":true,\"lineColor\":\"rgb(31, 120, 193)\",\"show\":true},\"tableColumn\":\"\",\"targets\":[{\"expr\":\"round(sum(irate(istio_requests_total{reporter=\\\"destination\\\",destination_service=~\\\"$service\\\"}[5m])),
+    0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"refId\":\"A\",\"step\":4}],\"thresholds\":\"\",\"title\":\"Server
+    Request Volume\",\"type\":\"singlestat\",\"valueFontSize\":\"80%\",\"valueMaps\":[{\"op\":\"=\",\"text\":\"N/A\",\"value\":\"null\"}],\"valueName\":\"current\"},{\"cacheTimeout\":null,\"colorBackground\":false,\"colorValue\":false,\"colors\":[\"rgba(50,
+    172, 45, 0.97)\",\"rgba(237, 129, 40, 0.89)\",\"rgba(245, 54, 54, 0.9)\"],\"datasource\":\"Prometheus\",\"decimals\":null,\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"format\":\"percentunit\",\"gauge\":{\"maxValue\":100,\"minValue\":80,\"show\":false,\"thresholdLabels\":false,\"thresholdMarkers\":false},\"gridPos\":{\"h\":4,\"w\":6,\"x\":6,\"y\":8},\"id\":98,\"interval\":null,\"links\":[],\"options\":{\"colorMode\":\"value\",\"graphMode\":\"area\",\"justifyMode\":\"auto\",\"orientation\":\"horizontal\",\"reduceOptions\":{\"calcs\":[\"lastNotNull\"],\"fields\":\"\",\"values\":false},\"textMode\":\"auto\"},\"mappingType\":1,\"mappingTypes\":[{\"name\":\"value
+    to text\",\"value\":1},{\"name\":\"range to text\",\"value\":2}],\"maxDataPoints\":100,\"nullPointMode\":\"connected\",\"nullText\":null,\"postfix\":\"\",\"postfixFontSize\":\"50%\",\"prefix\":\"\",\"prefixFontSize\":\"50%\",\"rangeMaps\":[{\"from\":\"null\",\"text\":\"N/A\",\"to\":\"null\"}],\"sparkline\":{\"fillColor\":\"rgba(31,
+    118, 189, 0.18)\",\"full\":true,\"lineColor\":\"rgb(31, 120, 193)\",\"show\":true},\"tableColumn\":\"\",\"targets\":[{\"expr\":\"sum(irate(istio_requests_total{reporter=\\\"destination\\\",destination_service=~\\\"$service\\\",response_code!~\\\"5.*\\\"}[5m]))
+    / sum(irate(istio_requests_total{reporter=\\\"destination\\\",destination_service=~\\\"$service\\\"}[5m]))\",\"format\":\"time_series\",\"intervalFactor\":1,\"refId\":\"A\"}],\"thresholds\":\"95,
+    99, 99.5\",\"title\":\"Server Success Rate (non-5xx responses)\",\"type\":\"singlestat\",\"valueFontSize\":\"80%\",\"valueMaps\":[{\"op\":\"=\",\"text\":\"N/A\",\"value\":\"null\"}],\"valueName\":\"avg\"},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":4,\"w\":6,\"x\":12,\"y\":8},\"hiddenSeries\":false,\"id\":99,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":false,\"hideZero\":false,\"max\":false,\"min\":false,\"rightSide\":true,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"(histogram_quantile(0.50,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"destination\\\",destination_service=~\\\"$service\\\"}[1m]))
+    by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"destination\\\",destination_service=~\\\"$service\\\"}[1m]))
+    by (le))\",\"format\":\"time_series\",\"interval\":\"\",\"intervalFactor\":1,\"legendFormat\":\"P50\",\"refId\":\"A\"},{\"expr\":\"(histogram_quantile(0.90,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"destination\\\",destination_service=~\\\"$service\\\"}[1m]))
+    by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"destination\\\",destination_service=~\\\"$service\\\"}[1m]))
+    by (le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"P90\",\"refId\":\"B\"},{\"expr\":\"(histogram_quantile(0.99,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"destination\\\",destination_service=~\\\"$service\\\"}[1m]))
+    by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"destination\\\",destination_service=~\\\"$service\\\"}[1m]))
+    by (le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"P99\",\"refId\":\"C\"}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Server
+    Request Duration\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"s\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"cacheTimeout\":null,\"colorBackground\":false,\"colorValue\":false,\"colors\":[\"#299c46\",\"rgba(237,
+    129, 40, 0.89)\",\"#d44a3a\"],\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"format\":\"Bps\",\"gauge\":{\"maxValue\":100,\"minValue\":0,\"show\":false,\"thresholdLabels\":false,\"thresholdMarkers\":true},\"gridPos\":{\"h\":4,\"w\":6,\"x\":18,\"y\":8},\"id\":100,\"interval\":null,\"links\":[],\"options\":{\"colorMode\":\"value\",\"graphMode\":\"area\",\"justifyMode\":\"auto\",\"orientation\":\"horizontal\",\"reduceOptions\":{\"calcs\":[\"lastNotNull\"],\"fields\":\"\",\"values\":false},\"textMode\":\"auto\"},\"mappingType\":1,\"mappingTypes\":[{\"name\":\"value
+    to text\",\"value\":1},{\"name\":\"range to text\",\"value\":2}],\"maxDataPoints\":100,\"nullPointMode\":\"connected\",\"nullText\":null,\"postfix\":\"\",\"postfixFontSize\":\"50%\",\"prefix\":\"\",\"prefixFontSize\":\"50%\",\"rangeMaps\":[{\"from\":\"null\",\"text\":\"N/A\",\"to\":\"null\"}],\"sparkline\":{\"fillColor\":\"rgba(31,
+    118, 189, 0.18)\",\"full\":true,\"lineColor\":\"rgb(31, 120, 193)\",\"show\":true},\"tableColumn\":\"\",\"targets\":[{\"expr\":\"sum(irate(istio_tcp_sent_bytes_total{reporter=~\\\"$qrep\\\",
+    destination_service=~\\\"$service\\\"}[1m]))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"\",\"refId\":\"A\"}],\"thresholds\":\"\",\"title\":\"TCP
+    Sent Bytes\",\"type\":\"singlestat\",\"valueFontSize\":\"80%\",\"valueMaps\":[{\"op\":\"=\",\"text\":\"N/A\",\"value\":\"null\"}],\"valueName\":\"avg\"}],\"title\":\"General\",\"type\":\"row\"},{\"collapsed\":true,\"gridPos\":{\"h\":1,\"w\":24,\"x\":0,\"y\":1},\"id\":104,\"panels\":[{\"content\":\"<div
+    class=\\\"dashboard-header text-center\\\">\\n<span>CLIENT WORKLOADS</span>\\n</div>\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"gridPos\":{\"h\":3,\"w\":24,\"x\":0,\"y\":2},\"id\":45,\"links\":[],\"mode\":\"html\",\"options\":{\"content\":\"<div
+    class=\\\"dashboard-header text-center\\\">\\n<span>CLIENT WORKLOADS</span>\\n</div>\",\"mode\":\"html\"},\"pluginVersion\":\"7.1.0\",\"title\":\"\",\"transparent\":true,\"type\":\"text\"},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":0,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":0,\"y\":5},\"hiddenSeries\":false,\"id\":25,\"legend\":{\"avg\":false,\"current\":false,\"hideEmpty\":true,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null
+    as zero\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"round(sum(irate(istio_requests_total{connection_security_policy=\\\"mutual_tls\\\",destination_service=~\\\"$service\\\",reporter=~\\\"$qrep\\\",source_workload=~\\\"$srcwl\\\",source_workload_namespace=~\\\"$srcns\\\"}[5m]))
+    by (source_workload, source_workload_namespace, response_code), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+    source_workload }}.{{ source_workload_namespace }} : {{ response_code }} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"round(sum(irate(istio_requests_total{connection_security_policy!=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", reporter=~\\\"$qrep\\\", source_workload=~\\\"$srcwl\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}[5m])) by (source_workload, source_workload_namespace,
+    response_code), 0.001)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    source_workload }}.{{ source_workload_namespace }} : {{ response_code }}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Incoming
+    Requests By Source And Response Code\",\"tooltip\":{\"shared\":false,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[\"total\"]},\"yaxes\":[{\"format\":\"ops\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":12,\"y\":5},\"hiddenSeries\":false,\"id\":26,\"legend\":{\"avg\":false,\"current\":false,\"hideEmpty\":true,\"hideZero\":false,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",response_code!~\\\"5.*\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[5m]))
+    by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[5m]))
+    by (source_workload, source_workload_namespace)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    source_workload }}.{{ source_workload_namespace }} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",response_code!~\\\"5.*\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[5m]))
+    by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[5m]))
+    by (source_workload, source_workload_namespace)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    source_workload }}.{{ source_workload_namespace }}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Incoming
+    Success Rate (non-5xx responses) By Source\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"percentunit\",\"label\":null,\"logBase\":1,\"max\":\"1.01\",\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"description\":\"\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":8,\"x\":0,\"y\":11},\"hiddenSeries\":false,\"id\":27,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":true,\"hideZero\":false,\"max\":false,\"min\":false,\"rightSide\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"(histogram_quantile(0.50,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50,
+    sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P50 (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"(histogram_quantile(0.90,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90,
+    sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P90 (\U0001F510mTLS)\",\"refId\":\"B\",\"step\":2},{\"expr\":\"(histogram_quantile(0.95,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95,
+    sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P95 (\U0001F510mTLS)\",\"refId\":\"C\",\"step\":2},{\"expr\":\"(histogram_quantile(0.99,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99,
+    sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P99 (\U0001F510mTLS)\",\"refId\":\"D\",\"step\":2},{\"expr\":\"(histogram_quantile(0.50,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50,
+    sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\", connection_security_policy!=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P50\",\"refId\":\"E\",\"step\":2},{\"expr\":\"(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90,
+    sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\", connection_security_policy!=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P90\",\"refId\":\"F\",\"step\":2},{\"expr\":\"(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95,
+    sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\", connection_security_policy!=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P95\",\"refId\":\"G\",\"step\":2},{\"expr\":\"(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99,
+    sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\", connection_security_policy!=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P99\",\"refId\":\"H\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Incoming
+    Request Duration By Source\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"s\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":8,\"x\":8,\"y\":11},\"hiddenSeries\":false,\"id\":28,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":true,\"max\":false,\"min\":false,\"rightSide\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"histogram_quantile(0.50,
+    sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P50 (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"histogram_quantile(0.90,
+    sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    \ P90 (\U0001F510mTLS)\",\"refId\":\"B\",\"step\":2},{\"expr\":\"histogram_quantile(0.95,
+    sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P95 (\U0001F510mTLS)\",\"refId\":\"C\",\"step\":2},{\"expr\":\"histogram_quantile(0.99,
+    sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    \ P99 (\U0001F510mTLS)\",\"refId\":\"D\",\"step\":2},{\"expr\":\"histogram_quantile(0.50,
+    sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy!=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P50\",\"refId\":\"E\",\"step\":2},{\"expr\":\"histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P90\",\"refId\":\"F\",\"step\":2},{\"expr\":\"histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P95\",\"refId\":\"G\",\"step\":2},{\"expr\":\"histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P99\",\"refId\":\"H\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Incoming
+    Request Size By Source\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"decbytes\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":8,\"x\":16,\"y\":11},\"hiddenSeries\":false,\"id\":68,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":true,\"max\":false,\"min\":false,\"rightSide\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"histogram_quantile(0.50,
+    sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P50 (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"histogram_quantile(0.90,
+    sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    \ P90 (\U0001F510mTLS)\",\"refId\":\"B\",\"step\":2},{\"expr\":\"histogram_quantile(0.95,
+    sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P95 (\U0001F510mTLS)\",\"refId\":\"C\",\"step\":2},{\"expr\":\"histogram_quantile(0.99,
+    sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    \ P99 (\U0001F510mTLS)\",\"refId\":\"D\",\"step\":2},{\"expr\":\"histogram_quantile(0.50,
+    sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy!=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P50\",\"refId\":\"E\",\"step\":2},{\"expr\":\"histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P90\",\"refId\":\"F\",\"step\":2},{\"expr\":\"histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P95\",\"refId\":\"G\",\"step\":2},{\"expr\":\"histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P99\",\"refId\":\"H\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Response
+    Size By Source\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"decbytes\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":0,\"y\":17},\"hiddenSeries\":false,\"id\":80,\"legend\":{\"avg\":false,\"current\":false,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"round(sum(irate(istio_tcp_received_bytes_total{reporter=~\\\"$qrep\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace), 0.001)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    source_workload }}.{{ source_workload_namespace}} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"round(sum(irate(istio_tcp_received_bytes_total{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+    source_workload }}.{{ source_workload_namespace}}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Bytes
+    Received from Incoming TCP Connection\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"Bps\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":true}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":12,\"y\":17},\"hiddenSeries\":false,\"id\":82,\"legend\":{\"avg\":false,\"current\":false,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\\\"mutual_tls\\\",
+    reporter=~\\\"$qrep\\\", destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace),
+    0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+    source_workload }}.{{ source_workload_namespace}} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\\\"mutual_tls\\\",
+    reporter=~\\\"$qrep\\\", destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace),
+    0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+    source_workload }}.{{ source_workload_namespace}}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Bytes
+    Sent to Incoming TCP Connection\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"Bps\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":true}],\"yaxis\":{\"align\":false,\"alignLevel\":null}}],\"title\":\"Client
+    Workloads\",\"type\":\"row\"},{\"collapsed\":true,\"gridPos\":{\"h\":1,\"w\":24,\"x\":0,\"y\":2},\"id\":102,\"panels\":[{\"content\":\"<div
+    class=\\\"dashboard-header text-center\\\">\\n<span>SERVICE WORKLOADS</span>\\n</div>\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"gridPos\":{\"h\":3,\"w\":24,\"x\":0,\"y\":3},\"id\":69,\"links\":[],\"mode\":\"html\",\"options\":{\"content\":\"<div
+    class=\\\"dashboard-header text-center\\\">\\n<span>SERVICE WORKLOADS</span>\\n</div>\",\"mode\":\"html\"},\"pluginVersion\":\"7.1.0\",\"title\":\"\",\"transparent\":true,\"type\":\"text\"},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":0,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":0,\"y\":6},\"hiddenSeries\":false,\"id\":90,\"legend\":{\"avg\":false,\"current\":false,\"hideEmpty\":true,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null
+    as zero\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"round(sum(irate(istio_requests_total{connection_security_policy=\\\"mutual_tls\\\",destination_service=~\\\"$service\\\",reporter=\\\"destination\\\",destination_workload=~\\\"$dstwl\\\",destination_workload_namespace=~\\\"$dstns\\\"}[5m]))
+    by (destination_workload, destination_workload_namespace, response_code), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }} : {{ response_code
+    }} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"round(sum(irate(istio_requests_total{connection_security_policy!=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", reporter=\\\"destination\\\", destination_workload=~\\\"$dstwl\\\",
+    destination_workload_namespace=~\\\"$dstns\\\"}[5m])) by (destination_workload,
+    destination_workload_namespace, response_code), 0.001)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }} : {{ response_code
+    }}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Incoming
+    Requests By Destination Workload And Response Code\",\"tooltip\":{\"shared\":false,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[\"total\"]},\"yaxes\":[{\"format\":\"ops\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":12,\"y\":6},\"hiddenSeries\":false,\"id\":91,\"legend\":{\"avg\":false,\"current\":false,\"hideEmpty\":true,\"hideZero\":false,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"sum(irate(istio_requests_total{reporter=\\\"destination\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",response_code!~\\\"5.*\\\",
+    destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[5m]))
+    by (destination_workload, destination_workload_namespace) / sum(irate(istio_requests_total{reporter=\\\"destination\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[5m]))
+    by (destination_workload, destination_workload_namespace)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"sum(irate(istio_requests_total{reporter=\\\"destination\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",response_code!~\\\"5.*\\\",
+    destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[5m]))
+    by (destination_workload, destination_workload_namespace) / sum(irate(istio_requests_total{reporter=\\\"destination\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[5m]))
+    by (destination_workload, destination_workload_namespace)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Incoming
+    Success Rate (non-5xx responses) By Destination Workload\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"percentunit\",\"label\":null,\"logBase\":1,\"max\":\"1.01\",\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"description\":\"\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":8,\"x\":0,\"y\":12},\"hiddenSeries\":false,\"id\":94,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":true,\"hideZero\":false,\"max\":false,\"min\":false,\"rightSide\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"(histogram_quantile(0.50,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"destination\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.50,
+    sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"destination\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }} P50 (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"(histogram_quantile(0.90,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"destination\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.90,
+    sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"destination\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }} P90 (\U0001F510mTLS)\",\"refId\":\"B\",\"step\":2},{\"expr\":\"(histogram_quantile(0.95,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"destination\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.95,
+    sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"destination\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }} P95 (\U0001F510mTLS)\",\"refId\":\"C\",\"step\":2},{\"expr\":\"(histogram_quantile(0.99,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"destination\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.99,
+    sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"destination\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }} P99 (\U0001F510mTLS)\",\"refId\":\"D\",\"step\":2},{\"expr\":\"(histogram_quantile(0.50,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"destination\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.50,
+    sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"destination\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }} P50\",\"refId\":\"E\",\"step\":2},{\"expr\":\"(histogram_quantile(0.90,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"destination\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.90,
+    sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"destination\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }} P90\",\"refId\":\"F\",\"step\":2},{\"expr\":\"(histogram_quantile(0.95,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"destination\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.95,
+    sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"destination\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }} P95\",\"refId\":\"G\",\"step\":2},{\"expr\":\"(histogram_quantile(0.99,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"destination\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.99,
+    sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"destination\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }} P99\",\"refId\":\"H\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Incoming
+    Request Duration By Service Workload\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"s\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":8,\"x\":8,\"y\":12},\"hiddenSeries\":false,\"id\":95,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":true,\"max\":false,\"min\":false,\"rightSide\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"histogram_quantile(0.50,
+    sum(irate(istio_request_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }} P50 (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"histogram_quantile(0.90,
+    sum(irate(istio_request_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }}  P90 (\U0001F510mTLS)\",\"refId\":\"B\",\"step\":2},{\"expr\":\"histogram_quantile(0.95,
+    sum(irate(istio_request_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }} P95 (\U0001F510mTLS)\",\"refId\":\"C\",\"step\":2},{\"expr\":\"histogram_quantile(0.99,
+    sum(irate(istio_request_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }}  P99 (\U0001F510mTLS)\",\"refId\":\"D\",\"step\":2},{\"expr\":\"histogram_quantile(0.50,
+    sum(irate(istio_request_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy!=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }} P50\",\"refId\":\"E\",\"step\":2},{\"expr\":\"histogram_quantile(0.90,
+    sum(irate(istio_request_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy!=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }} P90\",\"refId\":\"F\",\"step\":2},{\"expr\":\"histogram_quantile(0.95,
+    sum(irate(istio_request_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy!=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }} P95\",\"refId\":\"G\",\"step\":2},{\"expr\":\"histogram_quantile(0.99,
+    sum(irate(istio_request_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy!=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }} P99\",\"refId\":\"H\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Incoming
+    Request Size By Service Workload\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"decbytes\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":8,\"x\":16,\"y\":12},\"hiddenSeries\":false,\"id\":96,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":true,\"max\":false,\"min\":false,\"rightSide\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"histogram_quantile(0.50,
+    sum(irate(istio_response_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }} P50 (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"histogram_quantile(0.90,
+    sum(irate(istio_response_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }}  P90 (\U0001F510mTLS)\",\"refId\":\"B\",\"step\":2},{\"expr\":\"histogram_quantile(0.95,
+    sum(irate(istio_response_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }} P95 (\U0001F510mTLS)\",\"refId\":\"C\",\"step\":2},{\"expr\":\"histogram_quantile(0.99,
+    sum(irate(istio_response_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }}  P99 (\U0001F510mTLS)\",\"refId\":\"D\",\"step\":2},{\"expr\":\"histogram_quantile(0.50,
+    sum(irate(istio_response_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy!=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }} P50\",\"refId\":\"E\",\"step\":2},{\"expr\":\"histogram_quantile(0.90,
+    sum(irate(istio_response_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy!=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }} P90\",\"refId\":\"F\",\"step\":2},{\"expr\":\"histogram_quantile(0.95,
+    sum(irate(istio_response_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy!=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }} P95\",\"refId\":\"G\",\"step\":2},{\"expr\":\"histogram_quantile(0.99,
+    sum(irate(istio_response_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy!=\\\"mutual_tls\\\",
+    destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace }} P99\",\"refId\":\"H\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Response
+    Size By Service Workload\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"decbytes\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":0,\"y\":18},\"hiddenSeries\":false,\"id\":92,\"legend\":{\"avg\":false,\"current\":false,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"round(sum(irate(istio_tcp_received_bytes_total{reporter=\\\"destination\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace), 0.001)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace}} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"round(sum(irate(istio_tcp_received_bytes_total{reporter=\\\"destination\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+    destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+    by (destination_workload, destination_workload_namespace), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{ destination_workload_namespace}}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Bytes
+    Received from Incoming TCP Connection\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"Bps\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":true}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":12,\"y\":18},\"hiddenSeries\":false,\"id\":93,\"legend\":{\"avg\":false,\"current\":false,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\\\"mutual_tls\\\",
+    reporter=\\\"destination\\\", destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\",
+    destination_workload_namespace=~\\\"$dstns\\\"}[1m])) by (destination_workload,
+    destination_workload_namespace), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{destination_workload_namespace }} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\\\"mutual_tls\\\",
+    reporter=\\\"destination\\\", destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\",
+    destination_workload_namespace=~\\\"$dstns\\\"}[1m])) by (destination_workload,
+    destination_workload_namespace), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_workload }}.{{destination_workload_namespace }}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Bytes
+    Sent to Incoming TCP Connection\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"Bps\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":true}],\"yaxis\":{\"align\":false,\"alignLevel\":null}}],\"title\":\"Service
+    Workloads\",\"type\":\"row\"}],\"refresh\":\"1m\",\"schemaVersion\":26,\"style\":\"dark\",\"tags\":[],\"templating\":{\"list\":[{\"current\":{\"selected\":true,\"text\":\"default\",\"value\":\"default\"},\"hide\":0,\"includeAll\":false,\"label\":null,\"multi\":false,\"name\":\"datasource\",\"options\":[],\"query\":\"prometheus\",\"queryValue\":\"\",\"refresh\":1,\"regex\":\"\",\"skipUrlSync\":false,\"type\":\"datasource\"},{\"allValue\":null,\"current\":{},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":false,\"label\":\"Service\",\"multi\":false,\"name\":\"service\",\"options\":[],\"query\":\"query_result(sum(istio_requests_total{})
+    by (destination_service) or sum(istio_tcp_sent_bytes_total{}) by (destination_service))\",\"refresh\":1,\"regex\":\"/.*destination_service=\\\"([^\\\"]*).*/\",\"skipUrlSync\":false,\"sort\":0,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"query\",\"useTags\":false},{\"allValue\":null,\"current\":{\"selected\":true,\"text\":\"destination\",\"value\":\"destination\"},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":false,\"label\":\"Reporter\",\"multi\":true,\"name\":\"qrep\",\"query\":\"source,destination\",\"refresh\":1,\"regex\":\"\",\"skipUrlSync\":false,\"sort\":1,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"custom\",\"useTags\":false},{\"allValue\":null,\"current\":{},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":true,\"label\":\"Client
+    Cluster\",\"multi\":true,\"name\":\"srccluster\",\"options\":[],\"query\":\"query_result(sum(istio_requests_total{reporter=~\\\"$qrep\\\",
+    destination_service=\\\"$service\\\"}) by (source_cluster) or sum(istio_tcp_sent_bytes_total{reporter=~\\\"$qrep\\\",
+    destination_service=~\\\"$service\\\"}) by (source_cluster))\",\"refresh\":1,\"regex\":\"/.*cluster=\\\"([^\\\"]*).*/\",\"skipUrlSync\":false,\"sort\":2,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"query\",\"useTags\":false},{\"allValue\":null,\"current\":{},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":true,\"label\":\"Client
+    Workload Namespace\",\"multi\":true,\"name\":\"srcns\",\"options\":[],\"query\":\"query_result(sum(istio_requests_total{reporter=~\\\"$qrep\\\",
+    destination_service=\\\"$service\\\"}) by (source_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=~\\\"$qrep\\\",
+    destination_service=~\\\"$service\\\"}) by (source_workload_namespace))\",\"refresh\":1,\"regex\":\"/.*namespace=\\\"([^\\\"]*).*/\",\"skipUrlSync\":false,\"sort\":3,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"query\",\"useTags\":false},{\"allValue\":null,\"current\":{},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":true,\"label\":\"Client
+    Workload\",\"multi\":true,\"name\":\"srcwl\",\"options\":[],\"query\":\"query_result(sum(istio_requests_total{reporter=~\\\"$qrep\\\",
+    destination_service=~\\\"$service\\\", source_workload_namespace=~\\\"$srcns\\\"})
+    by (source_workload) or sum(istio_tcp_sent_bytes_total{reporter=~\\\"$qrep\\\",
+    destination_service=~\\\"$service\\\", source_workload_namespace=~\\\"$srcns\\\"})
+    by (source_workload))\",\"refresh\":1,\"regex\":\"/.*workload=\\\"([^\\\"]*).*/\",\"skipUrlSync\":false,\"sort\":4,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"query\",\"useTags\":false},{\"allValue\":null,\"current\":{},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":true,\"label\":\"Service
+    Workload Cluster\",\"multi\":true,\"name\":\"dstcluster\",\"options\":[],\"query\":\"query_result(sum(istio_requests_total{reporter=\\\"destination\\\",
+    destination_service=\\\"$service\\\"}) by (destination_cluster) or sum(istio_tcp_sent_bytes_total{reporter=\\\"destination\\\",
+    destination_service=~\\\"$service\\\"}) by (destination_cluster))\",\"refresh\":1,\"regex\":\"/.*cluster=\\\"([^\\\"]*).*/\",\"skipUrlSync\":false,\"sort\":2,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"query\",\"useTags\":false},{\"allValue\":null,\"current\":{},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":true,\"label\":\"Service
+    Workload Namespace\",\"multi\":true,\"name\":\"dstns\",\"options\":[],\"query\":\"query_result(sum(istio_requests_total{reporter=\\\"destination\\\",
+    destination_service=\\\"$service\\\"}) by (destination_workload_namespace) or
+    sum(istio_tcp_sent_bytes_total{reporter=\\\"destination\\\", destination_service=~\\\"$service\\\"})
+    by (destination_workload_namespace))\",\"refresh\":1,\"regex\":\"/.*namespace=\\\"([^\\\"]*).*/\",\"skipUrlSync\":false,\"sort\":3,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"query\",\"useTags\":false},{\"allValue\":null,\"current\":{},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":true,\"label\":\"Service
+    Workload\",\"multi\":true,\"name\":\"dstwl\",\"options\":[],\"query\":\"query_result(
+    sum(istio_requests_total{reporter=\\\"destination\\\", destination_service=~\\\"$service\\\",
+    destination_cluster=~\\\"$dstcluster\\\", destination_workload_namespace=~\\\"$dstns\\\"})
+    by (destination_workload) or sum(istio_tcp_sent_bytes_total{reporter=\\\"destination\\\",
+    destination_service=~\\\"$service\\\", destination_cluster=~\\\"$dstcluster\\\",
+    destination_workload_namespace=~\\\"$dstns\\\"}) by (destination_workload))\",\"refresh\":1,\"regex\":\"/.*workload=\\\"([^\\\"]*).*/\",\"skipUrlSync\":false,\"sort\":4,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"query\",\"useTags\":false}]},\"time\":{\"from\":\"now-5m\",\"to\":\"now\"},\"timepicker\":{\"refresh_intervals\":[\"5m\",\"15m\",\"30m\",\"1h\",\"2h\",\"1d\"],\"time_options\":[\"5m\",\"15m\",\"1h\",\"6h\",\"12h\",\"24h\",\"2d\",\"7d\",\"30d\"]},\"timezone\":\"\",\"title\":\"Istio
+    Service Dashboard\",\"uid\":\"LJ_uJAvmk\",\"version\":1}\n"
+  istio-workload-dashboard.json: "{\"annotations\":{\"list\":[{\"builtIn\":1,\"datasource\":\"--
+    Grafana --\",\"enable\":true,\"hide\":true,\"iconColor\":\"rgba(0, 211, 255, 1)\",\"name\":\"Annotations
+    & Alerts\",\"type\":\"dashboard\"}]},\"editable\":false,\"gnetId\":null,\"graphTooltip\":0,\"iteration\":1531345461465,\"links\":[],\"panels\":[{\"collapsed\":true,\"gridPos\":{\"h\":1,\"w\":24,\"x\":0,\"y\":0},\"id\":95,\"panels\":[{\"content\":\"<div
+    class=\\\"dashboard-header text-center\\\">\\n<span>WORKLOAD: $workload.$namespace</span>\\n</div>\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"gridPos\":{\"h\":3,\"w\":24,\"x\":0,\"y\":1},\"id\":89,\"links\":[],\"mode\":\"html\",\"options\":{\"content\":\"<div
+    class=\\\"dashboard-header text-center\\\">\\n<span>WORKLOAD: $workload.$namespace</span>\\n</div>\",\"mode\":\"html\"},\"pluginVersion\":\"7.1.0\",\"title\":\"\",\"transparent\":true,\"type\":\"text\"},{\"cacheTimeout\":null,\"colorBackground\":false,\"colorValue\":false,\"colors\":[\"rgba(245,
+    54, 54, 0.9)\",\"rgba(237, 129, 40, 0.89)\",\"rgba(50, 172, 45, 0.97)\"],\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"format\":\"ops\",\"gauge\":{\"maxValue\":100,\"minValue\":0,\"show\":false,\"thresholdLabels\":false,\"thresholdMarkers\":true},\"gridPos\":{\"h\":4,\"w\":8,\"x\":0,\"y\":4},\"id\":12,\"interval\":null,\"links\":[],\"options\":{\"colorMode\":\"value\",\"graphMode\":\"area\",\"justifyMode\":\"auto\",\"orientation\":\"horizontal\",\"reduceOptions\":{\"calcs\":[\"lastNotNull\"],\"fields\":\"\",\"values\":false},\"textMode\":\"auto\"},\"mappingType\":1,\"mappingTypes\":[{\"name\":\"value
+    to text\",\"value\":1},{\"name\":\"range to text\",\"value\":2}],\"maxDataPoints\":100,\"nullPointMode\":\"connected\",\"nullText\":null,\"postfix\":\"\",\"postfixFontSize\":\"50%\",\"prefix\":\"\",\"prefixFontSize\":\"50%\",\"rangeMaps\":[{\"from\":\"null\",\"text\":\"N/A\",\"to\":\"null\"}],\"sparkline\":{\"fillColor\":\"rgba(31,
+    118, 189, 0.18)\",\"full\":true,\"lineColor\":\"rgb(31, 120, 193)\",\"show\":true},\"tableColumn\":\"\",\"targets\":[{\"expr\":\"round(sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\",destination_workload_namespace=~\\\"$namespace\\\",destination_workload=~\\\"$workload\\\"}[5m])),
+    0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"refId\":\"A\",\"step\":4}],\"thresholds\":\"\",\"title\":\"Incoming
+    Request Volume\",\"type\":\"singlestat\",\"valueFontSize\":\"80%\",\"valueMaps\":[{\"op\":\"=\",\"text\":\"N/A\",\"value\":\"null\"}],\"valueName\":\"current\"},{\"cacheTimeout\":null,\"colorBackground\":false,\"colorValue\":false,\"colors\":[\"rgba(50,
+    172, 45, 0.97)\",\"rgba(237, 129, 40, 0.89)\",\"rgba(245, 54, 54, 0.9)\"],\"datasource\":\"Prometheus\",\"decimals\":null,\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"format\":\"percentunit\",\"gauge\":{\"maxValue\":100,\"minValue\":80,\"show\":false,\"thresholdLabels\":false,\"thresholdMarkers\":false},\"gridPos\":{\"h\":4,\"w\":8,\"x\":8,\"y\":4},\"id\":14,\"interval\":null,\"links\":[],\"options\":{\"colorMode\":\"value\",\"graphMode\":\"area\",\"justifyMode\":\"auto\",\"orientation\":\"horizontal\",\"reduceOptions\":{\"calcs\":[\"lastNotNull\"],\"fields\":\"\",\"values\":false},\"textMode\":\"auto\"},\"mappingType\":1,\"mappingTypes\":[{\"name\":\"value
+    to text\",\"value\":1},{\"name\":\"range to text\",\"value\":2}],\"maxDataPoints\":100,\"nullPointMode\":\"connected\",\"nullText\":null,\"postfix\":\"\",\"postfixFontSize\":\"50%\",\"prefix\":\"\",\"prefixFontSize\":\"50%\",\"rangeMaps\":[{\"from\":\"null\",\"text\":\"N/A\",\"to\":\"null\"}],\"sparkline\":{\"fillColor\":\"rgba(31,
+    118, 189, 0.18)\",\"full\":true,\"lineColor\":\"rgb(31, 120, 193)\",\"show\":true},\"tableColumn\":\"\",\"targets\":[{\"expr\":\"sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\",destination_workload_namespace=~\\\"$namespace\\\",destination_workload=~\\\"$workload\\\",response_code!~\\\"5.*\\\"}[5m]))
+    / sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\",destination_workload_namespace=~\\\"$namespace\\\",destination_workload=~\\\"$workload\\\"}[5m]))\",\"format\":\"time_series\",\"intervalFactor\":1,\"refId\":\"A\"}],\"thresholds\":\"95,
+    99, 99.5\",\"title\":\"Incoming Success Rate (non-5xx responses)\",\"type\":\"singlestat\",\"valueFontSize\":\"80%\",\"valueMaps\":[{\"op\":\"=\",\"text\":\"N/A\",\"value\":\"null\"}],\"valueName\":\"avg\"},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":4,\"w\":8,\"x\":16,\"y\":4},\"hiddenSeries\":false,\"id\":87,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":false,\"hideZero\":false,\"max\":false,\"min\":false,\"rightSide\":true,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"(histogram_quantile(0.50,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\"}[1m])) by (le)) / 1000) or
+    histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\"}[1m])) by (le))\",\"format\":\"time_series\",\"interval\":\"\",\"intervalFactor\":1,\"legendFormat\":\"P50\",\"refId\":\"A\"},{\"expr\":\"(histogram_quantile(0.90,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\"}[1m])) by (le)) / 1000) or
+    histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\"}[1m])) by (le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"P90\",\"refId\":\"B\"},{\"expr\":\"(histogram_quantile(0.99,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\"}[1m])) by (le)) / 1000) or
+    histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\"}[1m])) by (le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"P99\",\"refId\":\"C\"}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Request
+    Duration\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"s\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"cacheTimeout\":null,\"colorBackground\":false,\"colorValue\":false,\"colors\":[\"#299c46\",\"rgba(237,
+    129, 40, 0.89)\",\"#d44a3a\"],\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"format\":\"Bps\",\"gauge\":{\"maxValue\":100,\"minValue\":0,\"show\":false,\"thresholdLabels\":false,\"thresholdMarkers\":true},\"gridPos\":{\"h\":4,\"w\":12,\"x\":0,\"y\":8},\"id\":84,\"interval\":null,\"links\":[],\"options\":{\"colorMode\":\"value\",\"graphMode\":\"area\",\"justifyMode\":\"auto\",\"orientation\":\"horizontal\",\"reduceOptions\":{\"calcs\":[\"lastNotNull\"],\"fields\":\"\",\"values\":false},\"textMode\":\"auto\"},\"mappingType\":1,\"mappingTypes\":[{\"name\":\"value
+    to text\",\"value\":1},{\"name\":\"range to text\",\"value\":2}],\"maxDataPoints\":100,\"nullPointMode\":\"connected\",\"nullText\":null,\"postfix\":\"\",\"postfixFontSize\":\"50%\",\"prefix\":\"\",\"prefixFontSize\":\"50%\",\"rangeMaps\":[{\"from\":\"null\",\"text\":\"N/A\",\"to\":\"null\"}],\"sparkline\":{\"fillColor\":\"rgba(31,
+    118, 189, 0.18)\",\"full\":true,\"lineColor\":\"rgb(31, 120, 193)\",\"show\":true},\"tableColumn\":\"\",\"targets\":[{\"expr\":\"sum(irate(istio_tcp_sent_bytes_total{reporter=~\\\"$qrep\\\",
+    destination_workload_namespace=~\\\"$namespace\\\", destination_workload=~\\\"$workload\\\"}[1m]))
+    + sum(irate(istio_tcp_received_bytes_total{reporter=~\\\"$qrep\\\", destination_workload_namespace=~\\\"$namespace\\\",
+    destination_workload=~\\\"$workload\\\"}[1m]))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"\",\"refId\":\"A\"}],\"thresholds\":\"\",\"title\":\"TCP
+    Server Traffic\",\"type\":\"singlestat\",\"valueFontSize\":\"80%\",\"valueMaps\":[{\"op\":\"=\",\"text\":\"N/A\",\"value\":\"null\"}],\"valueName\":\"avg\"},{\"cacheTimeout\":null,\"colorBackground\":false,\"colorValue\":false,\"colors\":[\"#299c46\",\"rgba(237,
+    129, 40, 0.89)\",\"#d44a3a\"],\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"format\":\"Bps\",\"gauge\":{\"maxValue\":100,\"minValue\":0,\"show\":false,\"thresholdLabels\":false,\"thresholdMarkers\":true},\"gridPos\":{\"h\":4,\"w\":12,\"x\":12,\"y\":8},\"id\":85,\"interval\":null,\"links\":[],\"options\":{\"colorMode\":\"value\",\"graphMode\":\"area\",\"justifyMode\":\"auto\",\"orientation\":\"horizontal\",\"reduceOptions\":{\"calcs\":[\"lastNotNull\"],\"fields\":\"\",\"values\":false},\"textMode\":\"auto\"},\"mappingType\":1,\"mappingTypes\":[{\"name\":\"value
+    to text\",\"value\":1},{\"name\":\"range to text\",\"value\":2}],\"maxDataPoints\":100,\"nullPointMode\":\"connected\",\"nullText\":null,\"postfix\":\"\",\"postfixFontSize\":\"50%\",\"prefix\":\"\",\"prefixFontSize\":\"50%\",\"rangeMaps\":[{\"from\":\"null\",\"text\":\"N/A\",\"to\":\"null\"}],\"sparkline\":{\"fillColor\":\"rgba(31,
+    118, 189, 0.18)\",\"full\":true,\"lineColor\":\"rgb(31, 120, 193)\",\"show\":true},\"tableColumn\":\"\",\"targets\":[{\"expr\":\"sum(irate(istio_tcp_sent_bytes_total{reporter=~\\\"$qrep\\\",
+    source_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$workload\\\"}[1m]))
+    + sum(irate(istio_tcp_received_bytes_total{reporter=~\\\"$qrep\\\", source_workload_namespace=~\\\"$namespace\\\",
+    source_workload=~\\\"$workload\\\"}[1m]))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"\",\"refId\":\"A\"}],\"thresholds\":\"\",\"title\":\"TCP
+    Client Traffic\",\"type\":\"singlestat\",\"valueFontSize\":\"80%\",\"valueMaps\":[{\"op\":\"=\",\"text\":\"N/A\",\"value\":\"null\"}],\"valueName\":\"avg\"}],\"title\":\"General\",\"type\":\"row\"},{\"collapsed\":true,\"gridPos\":{\"h\":1,\"w\":24,\"x\":0,\"y\":1},\"id\":93,\"panels\":[{\"content\":\"<div
+    class=\\\"dashboard-header text-center\\\">\\n<span>INBOUND WORKLOADS</span>\\n</div>\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"gridPos\":{\"h\":3,\"w\":24,\"x\":0,\"y\":13},\"id\":45,\"links\":[],\"mode\":\"html\",\"options\":{\"content\":\"<div
+    class=\\\"dashboard-header text-center\\\">\\n<span>INBOUND WORKLOADS</span>\\n</div>\",\"mode\":\"html\"},\"pluginVersion\":\"7.1.0\",\"title\":\"\",\"transparent\":true,\"type\":\"text\"},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":0,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":0,\"y\":16},\"hiddenSeries\":false,\"id\":25,\"legend\":{\"avg\":false,\"current\":false,\"hideEmpty\":true,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null
+    as zero\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"round(sum(irate(istio_requests_total{connection_security_policy=\\\"mutual_tls\\\",
+    destination_workload_namespace=~\\\"$namespace\\\", destination_workload=~\\\"$workload\\\",
+    reporter=~\\\"$qrep\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[5m]))
+    by (source_workload, source_workload_namespace, response_code), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+    source_workload }}.{{ source_workload_namespace }} : {{ response_code }} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"round(sum(irate(istio_requests_total{connection_security_policy!=\\\"mutual_tls\\\",
+    destination_workload_namespace=~\\\"$namespace\\\", destination_workload=~\\\"$workload\\\",
+    reporter=~\\\"$qrep\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[5m]))
+    by (source_workload, source_workload_namespace, response_code), 0.001)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    source_workload }}.{{ source_workload_namespace }} : {{ response_code }}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Incoming
+    Requests By Source And Response Code\",\"tooltip\":{\"shared\":false,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[\"total\"]},\"yaxes\":[{\"format\":\"ops\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":12,\"y\":16},\"hiddenSeries\":false,\"id\":26,\"legend\":{\"avg\":false,\"current\":false,\"hideEmpty\":true,\"hideZero\":false,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_workload_namespace=~\\\"$namespace\\\",
+    destination_workload=~\\\"$workload\\\",response_code!~\\\"5.*\\\", source_workload=~\\\"$srcwl\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}[5m])) by (source_workload, source_workload_namespace)
+    / sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_workload_namespace=~\\\"$namespace\\\", destination_workload=~\\\"$workload\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[5m]))
+    by (source_workload, source_workload_namespace)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    source_workload }}.{{ source_workload_namespace }} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_workload_namespace=~\\\"$namespace\\\",
+    destination_workload=~\\\"$workload\\\",response_code!~\\\"5.*\\\", source_workload=~\\\"$srcwl\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}[5m])) by (source_workload, source_workload_namespace)
+    / sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\", connection_security_policy!=\\\"mutual_tls\\\",
+    destination_workload_namespace=~\\\"$namespace\\\", destination_workload=~\\\"$workload\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[5m]))
+    by (source_workload, source_workload_namespace)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    source_workload }}.{{ source_workload_namespace }}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Incoming
+    Success Rate (non-5xx responses) By Source\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"percentunit\",\"label\":null,\"logBase\":1,\"max\":\"1.01\",\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"description\":\"\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":8,\"x\":0,\"y\":22},\"hiddenSeries\":false,\"id\":27,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":true,\"hideZero\":false,\"max\":false,\"min\":false,\"rightSide\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"(histogram_quantile(0.50,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+    le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+    le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P50 (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"(histogram_quantile(0.90,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+    le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+    le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P90 (\U0001F510mTLS)\",\"refId\":\"B\",\"step\":2},{\"expr\":\"(histogram_quantile(0.95,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+    le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+    le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P95 (\U0001F510mTLS)\",\"refId\":\"C\",\"step\":2},{\"expr\":\"(histogram_quantile(0.99,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+    le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+    le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P99 (\U0001F510mTLS)\",\"refId\":\"D\",\"step\":2},{\"expr\":\"(histogram_quantile(0.50,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+    le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+    le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P50\",\"refId\":\"E\",\"step\":2},{\"expr\":\"(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+    le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+    le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P90\",\"refId\":\"F\",\"step\":2},{\"expr\":\"(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+    le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+    le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P95\",\"refId\":\"G\",\"step\":2},{\"expr\":\"(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+    le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+    le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P99\",\"refId\":\"H\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Incoming
+    Request Duration By Source\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"s\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":8,\"x\":8,\"y\":22},\"hiddenSeries\":false,\"id\":28,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":true,\"max\":false,\"min\":false,\"rightSide\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"histogram_quantile(0.50,
+    sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_workload=~\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P50 (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"histogram_quantile(0.90,
+    sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_workload=~\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    \ P90 (\U0001F510mTLS)\",\"refId\":\"B\",\"step\":2},{\"expr\":\"histogram_quantile(0.95,
+    sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_workload=~\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P95 (\U0001F510mTLS)\",\"refId\":\"C\",\"step\":2},{\"expr\":\"histogram_quantile(0.99,
+    sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_workload=~\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    \ P99 (\U0001F510mTLS)\",\"refId\":\"D\",\"step\":2},{\"expr\":\"histogram_quantile(0.50,
+    sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy!=\\\"mutual_tls\\\",
+    destination_workload=~\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P50\",\"refId\":\"E\",\"step\":2},{\"expr\":\"histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+    le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P90\",\"refId\":\"F\",\"step\":2},{\"expr\":\"histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+    le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P95\",\"refId\":\"G\",\"step\":2},{\"expr\":\"histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+    le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P99\",\"refId\":\"H\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Incoming
+    Request Size By Source\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"decbytes\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":8,\"x\":16,\"y\":22},\"hiddenSeries\":false,\"id\":68,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":true,\"max\":false,\"min\":false,\"rightSide\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"histogram_quantile(0.50,
+    sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_workload=~\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P50 (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"histogram_quantile(0.90,
+    sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_workload=~\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    \ P90 (\U0001F510mTLS)\",\"refId\":\"B\",\"step\":2},{\"expr\":\"histogram_quantile(0.95,
+    sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_workload=~\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P95 (\U0001F510mTLS)\",\"refId\":\"C\",\"step\":2},{\"expr\":\"histogram_quantile(0.99,
+    sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+    destination_workload=~\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    \ P99 (\U0001F510mTLS)\",\"refId\":\"D\",\"step\":2},{\"expr\":\"histogram_quantile(0.50,
+    sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy!=\\\"mutual_tls\\\",
+    destination_workload=~\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P50\",\"refId\":\"E\",\"step\":2},{\"expr\":\"histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+    le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P90\",\"refId\":\"F\",\"step\":2},{\"expr\":\"histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+    le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P95\",\"refId\":\"G\",\"step\":2},{\"expr\":\"histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+    destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+    le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+    P99\",\"refId\":\"H\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Response
+    Size By Source\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"decbytes\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":0,\"y\":28},\"hiddenSeries\":false,\"id\":80,\"legend\":{\"avg\":false,\"current\":false,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"round(sum(irate(istio_tcp_received_bytes_total{reporter=~\\\"$qrep\\\",
+    connection_security_policy=\\\"mutual_tls\\\", destination_workload_namespace=~\\\"$namespace\\\",
+    destination_workload=~\\\"$workload\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace), 0.001)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    source_workload }}.{{ source_workload_namespace}} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"round(sum(irate(istio_tcp_received_bytes_total{reporter=~\\\"$qrep\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", destination_workload_namespace=~\\\"$namespace\\\",
+    destination_workload=~\\\"$workload\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+    source_workload }}.{{ source_workload_namespace}}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Bytes
+    Received from Incoming TCP Connection\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"Bps\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":true}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":12,\"y\":28},\"hiddenSeries\":false,\"id\":82,\"legend\":{\"avg\":false,\"current\":false,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\\\"mutual_tls\\\",
+    reporter=~\\\"$qrep\\\", destination_workload_namespace=~\\\"$namespace\\\", destination_workload=~\\\"$workload\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+    source_workload }}.{{ source_workload_namespace}} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\\\"mutual_tls\\\",
+    reporter=~\\\"$qrep\\\", destination_workload_namespace=~\\\"$namespace\\\", destination_workload=~\\\"$workload\\\",
+    source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+    by (source_workload, source_workload_namespace), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+    source_workload }}.{{ source_workload_namespace}}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Bytes
+    Sent to Incoming TCP Connection\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"Bps\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":true}],\"yaxis\":{\"align\":false,\"alignLevel\":null}}],\"title\":\"Inbound
+    Workloads\",\"type\":\"row\"},{\"collapsed\":true,\"gridPos\":{\"h\":1,\"w\":24,\"x\":0,\"y\":2},\"id\":91,\"panels\":[{\"content\":\"<div
+    class=\\\"dashboard-header text-center\\\">\\n<span>OUTBOUND SERVICES</span>\\n</div>\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"gridPos\":{\"h\":3,\"w\":24,\"x\":0,\"y\":14},\"id\":69,\"links\":[],\"mode\":\"html\",\"options\":{\"content\":\"<div
+    class=\\\"dashboard-header text-center\\\">\\n<span>OUTBOUND SERVICES</span>\\n</div>\",\"mode\":\"html\"},\"pluginVersion\":\"7.1.0\",\"title\":\"\",\"transparent\":true,\"type\":\"text\"},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":0,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":0,\"y\":17},\"hiddenSeries\":false,\"id\":70,\"legend\":{\"avg\":false,\"current\":false,\"hideEmpty\":true,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null
+    as zero\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"round(sum(irate(istio_requests_total{destination_principal=~\\\"spiffe.*\\\",
+    source_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$workload\\\",
+    reporter=\\\"source\\\", destination_service=~\\\"$dstsvc\\\"}[5m])) by (destination_service,
+    response_code), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} : {{ response_code }} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"round(sum(irate(istio_requests_total{destination_principal!~\\\"spiffe.*\\\",
+    source_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$workload\\\",
+    reporter=\\\"source\\\", destination_service=~\\\"$dstsvc\\\"}[5m])) by (destination_service,
+    response_code), 0.001)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} : {{ response_code }}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Outgoing
+    Requests By Destination And Response Code\",\"tooltip\":{\"shared\":false,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[\"total\"]},\"yaxes\":[{\"format\":\"ops\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":12,\"y\":17},\"hiddenSeries\":false,\"id\":71,\"legend\":{\"avg\":false,\"current\":false,\"hideEmpty\":true,\"hideZero\":false,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"sum(irate(istio_requests_total{reporter=\\\"source\\\",
+    connection_security_policy=\\\"mutual_tls\\\", source_workload_namespace=~\\\"$namespace\\\",
+    source_workload=~\\\"$workload\\\",response_code!~\\\"5.*\\\", destination_service=~\\\"$dstsvc\\\"}[5m]))
+    by (destination_service) / sum(irate(istio_requests_total{reporter=\\\"source\\\",
+    connection_security_policy=\\\"mutual_tls\\\", source_workload_namespace=~\\\"$namespace\\\",
+    source_workload=~\\\"$workload\\\", destination_service=~\\\"$dstsvc\\\"}[5m]))
+    by (destination_service)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"sum(irate(istio_requests_total{reporter=\\\"source\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", source_workload_namespace=~\\\"$namespace\\\",
+    source_workload=~\\\"$workload\\\",response_code!~\\\"5.*\\\", destination_service=~\\\"$dstsvc\\\"}[5m]))
+    by (destination_service) / sum(irate(istio_requests_total{reporter=\\\"source\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", source_workload_namespace=~\\\"$namespace\\\",
+    source_workload=~\\\"$workload\\\", destination_service=~\\\"$dstsvc\\\"}[5m]))
+    by (destination_service)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Outgoing
+    Success Rate (non-5xx responses) By Destination\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"percentunit\",\"label\":null,\"logBase\":1,\"max\":\"1.01\",\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"description\":\"\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":8,\"x\":0,\"y\":23},\"hiddenSeries\":false,\"id\":72,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":true,\"hideZero\":false,\"max\":false,\"min\":false,\"rightSide\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"(histogram_quantile(0.50,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"source\\\",
+    connection_security_policy=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+    source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+    by (destination_service, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"source\\\",
+    connection_security_policy=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+    source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+    by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} P50 (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"(histogram_quantile(0.90,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"source\\\",
+    connection_security_policy=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+    source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+    by (destination_service, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"source\\\",
+    connection_security_policy=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+    source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+    by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} P90 (\U0001F510mTLS)\",\"refId\":\"B\",\"step\":2},{\"expr\":\"(histogram_quantile(0.95,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"source\\\",
+    connection_security_policy=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+    source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+    by (destination_service, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"source\\\",
+    connection_security_policy=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+    source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+    by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} P95 (\U0001F510mTLS)\",\"refId\":\"C\",\"step\":2},{\"expr\":\"(histogram_quantile(0.99,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"source\\\",
+    connection_security_policy=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+    source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+    by (destination_service, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"source\\\",
+    connection_security_policy=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+    source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+    by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} P99 (\U0001F510mTLS)\",\"refId\":\"D\",\"step\":2},{\"expr\":\"(histogram_quantile(0.50,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"source\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+    source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+    by (destination_service, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"source\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+    source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+    by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} P50\",\"refId\":\"E\",\"step\":2},{\"expr\":\"(histogram_quantile(0.90,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"source\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+    source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+    by (destination_service, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"source\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+    source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+    by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} P90\",\"refId\":\"F\",\"step\":2},{\"expr\":\"(histogram_quantile(0.95,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"source\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+    source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+    by (destination_service, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"source\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+    source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+    by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} P95\",\"refId\":\"G\",\"step\":2},{\"expr\":\"(histogram_quantile(0.99,
+    sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"source\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+    source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+    by (destination_service, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"source\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+    source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+    by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} P99\",\"refId\":\"H\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Outgoing
+    Request Duration By Destination\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"s\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":8,\"x\":8,\"y\":23},\"hiddenSeries\":false,\"id\":73,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":true,\"max\":false,\"min\":false,\"rightSide\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"histogram_quantile(0.50,
+    sum(irate(istio_request_bytes_bucket{reporter=\\\"source\\\", connection_security_policy=\\\"mutual_tls\\\",
+    source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+    destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} P50 (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"histogram_quantile(0.90,
+    sum(irate(istio_request_bytes_bucket{reporter=\\\"source\\\", connection_security_policy=\\\"mutual_tls\\\",
+    source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+    destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} P90 (\U0001F510mTLS)\",\"refId\":\"B\",\"step\":2},{\"expr\":\"histogram_quantile(0.95,
+    sum(irate(istio_request_bytes_bucket{reporter=\\\"source\\\", connection_security_policy=\\\"mutual_tls\\\",
+    source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+    destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} P95 (\U0001F510mTLS)\",\"refId\":\"C\",\"step\":2},{\"expr\":\"histogram_quantile(0.99,
+    sum(irate(istio_request_bytes_bucket{reporter=\\\"source\\\", connection_security_policy=\\\"mutual_tls\\\",
+    source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+    destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} P99 (\U0001F510mTLS)\",\"refId\":\"D\",\"step\":2},{\"expr\":\"histogram_quantile(0.50,
+    sum(irate(istio_request_bytes_bucket{reporter=\\\"source\\\", connection_security_policy!=\\\"mutual_tls\\\",
+    source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+    destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} P50\",\"refId\":\"E\",\"step\":2},{\"expr\":\"histogram_quantile(0.90,
+    sum(irate(istio_request_bytes_bucket{reporter=\\\"source\\\", connection_security_policy!=\\\"mutual_tls\\\",
+    source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+    destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} P90\",\"refId\":\"F\",\"step\":2},{\"expr\":\"histogram_quantile(0.95,
+    sum(irate(istio_request_bytes_bucket{reporter=\\\"source\\\", connection_security_policy!=\\\"mutual_tls\\\",
+    source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+    destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} P95\",\"refId\":\"G\",\"step\":2},{\"expr\":\"histogram_quantile(0.99,
+    sum(irate(istio_request_bytes_bucket{reporter=\\\"source\\\", connection_security_policy!=\\\"mutual_tls\\\",
+    source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+    destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} P99\",\"refId\":\"H\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Outgoing
+    Request Size By Destination\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"decbytes\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":8,\"x\":16,\"y\":23},\"hiddenSeries\":false,\"id\":74,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":true,\"max\":false,\"min\":false,\"rightSide\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"histogram_quantile(0.50,
+    sum(irate(istio_response_bytes_bucket{reporter=\\\"source\\\", connection_security_policy=\\\"mutual_tls\\\",
+    source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+    destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} P50 (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"histogram_quantile(0.90,
+    sum(irate(istio_response_bytes_bucket{reporter=\\\"source\\\", connection_security_policy=\\\"mutual_tls\\\",
+    source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+    destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} P90 (\U0001F510mTLS)\",\"refId\":\"B\",\"step\":2},{\"expr\":\"histogram_quantile(0.95,
+    sum(irate(istio_response_bytes_bucket{reporter=\\\"source\\\", connection_security_policy=\\\"mutual_tls\\\",
+    source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+    destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} P95 (\U0001F510mTLS)\",\"refId\":\"C\",\"step\":2},{\"expr\":\"histogram_quantile(0.99,
+    sum(irate(istio_response_bytes_bucket{reporter=\\\"source\\\", connection_security_policy=\\\"mutual_tls\\\",
+    source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+    destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }}  P99 (\U0001F510mTLS)\",\"refId\":\"D\",\"step\":2},{\"expr\":\"histogram_quantile(0.50,
+    sum(irate(istio_response_bytes_bucket{reporter=\\\"source\\\", connection_security_policy!=\\\"mutual_tls\\\",
+    source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+    destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} P50\",\"refId\":\"E\",\"step\":2},{\"expr\":\"histogram_quantile(0.90,
+    sum(irate(istio_response_bytes_bucket{reporter=\\\"source\\\", connection_security_policy!=\\\"mutual_tls\\\",
+    source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+    destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} P90\",\"refId\":\"F\",\"step\":2},{\"expr\":\"histogram_quantile(0.95,
+    sum(irate(istio_response_bytes_bucket{reporter=\\\"source\\\", connection_security_policy!=\\\"mutual_tls\\\",
+    source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+    destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} P95\",\"refId\":\"G\",\"step\":2},{\"expr\":\"histogram_quantile(0.99,
+    sum(irate(istio_response_bytes_bucket{reporter=\\\"source\\\", connection_security_policy!=\\\"mutual_tls\\\",
+    source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+    destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} P99\",\"refId\":\"H\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Response
+    Size By Destination\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"decbytes\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":0,\"y\":29},\"hiddenSeries\":false,\"id\":76,\"legend\":{\"avg\":false,\"current\":false,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"round(sum(irate(istio_tcp_received_bytes_total{connection_security_policy=\\\"mutual_tls\\\",
+    reporter=\\\"source\\\", source_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$workload\\\",
+    destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"round(sum(irate(istio_tcp_received_bytes_total{connection_security_policy!=\\\"mutual_tls\\\",
+    reporter=\\\"source\\\", source_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$workload\\\",
+    destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Bytes
+    Sent on Outgoing TCP Connection\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"Bps\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":true}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":12,\"y\":29},\"hiddenSeries\":false,\"id\":78,\"legend\":{\"avg\":false,\"current\":false,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"round(sum(irate(istio_tcp_sent_bytes_total{reporter=\\\"source\\\",
+    connection_security_policy=\\\"mutual_tls\\\", source_workload_namespace=~\\\"$namespace\\\",
+    source_workload=~\\\"$workload\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+    by (destination_service), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"round(sum(irate(istio_tcp_sent_bytes_total{reporter=\\\"source\\\",
+    connection_security_policy!=\\\"mutual_tls\\\", source_workload_namespace=~\\\"$namespace\\\",
+    source_workload=~\\\"$workload\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+    by (destination_service), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+    destination_service }}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Bytes
+    Received from Outgoing TCP Connection\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"Bps\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":true}],\"yaxis\":{\"align\":false,\"alignLevel\":null}}],\"title\":\"Outbound
+    Services\",\"type\":\"row\"}],\"refresh\":\"1m\",\"schemaVersion\":26,\"style\":\"dark\",\"tags\":[],\"templating\":{\"list\":[{\"current\":{\"selected\":true,\"text\":\"default\",\"value\":\"default\"},\"hide\":0,\"includeAll\":false,\"label\":null,\"multi\":false,\"name\":\"datasource\",\"options\":[],\"query\":\"prometheus\",\"queryValue\":\"\",\"refresh\":1,\"regex\":\"\",\"skipUrlSync\":false,\"type\":\"datasource\"},{\"allValue\":null,\"current\":{},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":false,\"label\":\"Namespace\",\"multi\":false,\"name\":\"namespace\",\"options\":[],\"query\":\"query_result(sum(istio_requests_total)
+    by (destination_workload_namespace) or sum(istio_tcp_sent_bytes_total) by (destination_workload_namespace))\",\"refresh\":1,\"regex\":\"/.*_namespace=\\\"([^\\\"]*).*/\",\"skipUrlSync\":false,\"sort\":0,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"query\",\"useTags\":false},{\"allValue\":null,\"current\":{},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":false,\"label\":\"Workload\",\"multi\":false,\"name\":\"workload\",\"options\":[],\"query\":\"query_result((sum(istio_requests_total{destination_workload_namespace=~\\\"$namespace\\\"})
+    by (destination_workload) or sum(istio_requests_total{source_workload_namespace=~\\\"$namespace\\\"})
+    by (source_workload)) or (sum(istio_tcp_sent_bytes_total{destination_workload_namespace=~\\\"$namespace\\\"})
+    by (destination_workload) or sum(istio_tcp_sent_bytes_total{source_workload_namespace=~\\\"$namespace\\\"})
+    by (source_workload)))\",\"refresh\":1,\"regex\":\"/.*workload=\\\"([^\\\"]*).*/\",\"skipUrlSync\":false,\"sort\":1,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"query\",\"useTags\":false},{\"allValue\":null,\"current\":{\"selected\":true,\"text\":\"destination\",\"value\":\"destination\"},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":false,\"label\":\"Reporter\",\"multi\":true,\"name\":\"qrep\",\"query\":\"source,destination\",\"refresh\":1,\"regex\":\"\",\"skipUrlSync\":false,\"sort\":2,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"custom\",\"useTags\":false},{\"allValue\":null,\"current\":{},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":true,\"label\":\"Inbound
+    Workload Namespace\",\"multi\":true,\"name\":\"srcns\",\"options\":[],\"query\":\"query_result(sum(istio_requests_total{reporter=~\\\"$qrep\\\",
+    destination_workload=\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\"})
+    by (source_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=~\\\"$qrep\\\",
+    destination_workload=\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\"})
+    by (source_workload_namespace))\",\"refresh\":1,\"regex\":\"/.*namespace=\\\"([^\\\"]*).*/\",\"skipUrlSync\":false,\"sort\":2,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"query\",\"useTags\":false},{\"allValue\":null,\"current\":{},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":true,\"label\":\"Inbound
+    Workload\",\"multi\":true,\"name\":\"srcwl\",\"options\":[],\"query\":\"query_result(sum(istio_requests_total{reporter=~\\\"$qrep\\\",
+    destination_workload=\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}) by (source_workload) or sum(istio_tcp_sent_bytes_total{reporter=~\\\"$qrep\\\",
+    destination_workload=\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\",
+    source_workload_namespace=~\\\"$srcns\\\"}) by (source_workload))\",\"refresh\":1,\"regex\":\"/.*workload=\\\"([^\\\"]*).*/\",\"skipUrlSync\":false,\"sort\":3,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"query\",\"useTags\":false},{\"allValue\":null,\"current\":{},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":true,\"label\":\"Destination
+    Service\",\"multi\":true,\"name\":\"dstsvc\",\"options\":[],\"query\":\"query_result(sum(istio_requests_total{reporter=\\\"source\\\",
+    source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\"})
+    by (destination_service) or sum(istio_tcp_sent_bytes_total{reporter=\\\"source\\\",
+    source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\"})
+    by (destination_service))\",\"refresh\":1,\"regex\":\"/.*destination_service=\\\"([^\\\"]*).*/\",\"skipUrlSync\":false,\"sort\":4,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"query\",\"useTags\":false}]},\"time\":{\"from\":\"now-5m\",\"to\":\"now\"},\"timepicker\":{\"refresh_intervals\":[\"5m\",\"15m\",\"30m\",\"1h\",\"2h\",\"1d\"],\"time_options\":[\"5m\",\"15m\",\"1h\",\"6h\",\"12h\",\"24h\",\"2d\",\"7d\",\"30d\"]},\"timezone\":\"\",\"title\":\"Istio
+    Workload Dashboard\",\"uid\":\"UbsSZTDik\",\"version\":1}\n"
+kind: ConfigMap
+metadata:
+  creationTimestamp: null
+  name: istio-services-grafana-dashboards
+  namespace: istio-system
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/manifests/addons/jaeger.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/manifests/addons/jaeger.yaml
new file mode 100644 (file)
index 0000000..b752e68
--- /dev/null
@@ -0,0 +1,138 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: jaeger
+  namespace: istio-system
+  labels:
+    app: jaeger
+spec:
+  selector:
+    matchLabels:
+      app: jaeger
+  template:
+    metadata:
+      labels:
+        app: jaeger
+        sidecar.istio.io/inject: "false"
+      annotations:
+        prometheus.io/scrape: "true"
+        prometheus.io/port: "14269"
+    spec:
+      containers:
+        - name: jaeger
+          image: "docker.io/jaegertracing/all-in-one:1.46"
+          env:
+            - name: BADGER_EPHEMERAL
+              value: "false"
+            - name: SPAN_STORAGE_TYPE
+              value: "badger"
+            - name: BADGER_DIRECTORY_VALUE
+              value: "/badger/data"
+            - name: BADGER_DIRECTORY_KEY
+              value: "/badger/key"
+            - name: COLLECTOR_ZIPKIN_HOST_PORT
+              value: ":9411"
+            - name: MEMORY_MAX_TRACES
+              value: "50000"
+            - name: QUERY_BASE_PATH
+              value: /jaeger
+          livenessProbe:
+            httpGet:
+              path: /
+              port: 14269
+          readinessProbe:
+            httpGet:
+              path: /
+              port: 14269
+          volumeMounts:
+            - name: data
+              mountPath: /badger
+          resources:
+            requests:
+              cpu: 10m
+      volumes:
+        - name: data
+          emptyDir: {}
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: tracing
+  namespace: istio-system
+  labels:
+    app: jaeger
+spec:
+  type: ClusterIP
+  ports:
+    - name: http-query
+      port: 80
+      protocol: TCP
+      targetPort: 16686
+    # Note: Change port name if you add '--query.grpc.tls.enabled=true'
+    - name: grpc-query
+      port: 16685
+      protocol: TCP
+      targetPort: 16685
+  selector:
+    app: jaeger
+---
+# Jaeger implements the Zipkin API. To support swapping out the tracing backend, we use a Service named Zipkin.
+apiVersion: v1
+kind: Service
+metadata:
+  labels:
+    name: zipkin
+  name: zipkin
+  namespace: istio-system
+spec:
+  ports:
+    - port: 9411
+      targetPort: 9411
+      name: http-query
+  selector:
+    app: jaeger
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: jaeger-collector
+  namespace: istio-system
+  labels:
+    app: jaeger
+spec:
+  type: ClusterIP
+  ports:
+  - name: jaeger-collector-http
+    port: 14268
+    targetPort: 14268
+    protocol: TCP
+  - name: jaeger-collector-grpc
+    port: 14250
+    targetPort: 14250
+    protocol: TCP
+  - port: 9411
+    targetPort: 9411
+    name: http-zipkin
+  - port: 4317
+    name: grpc-otel
+  - port: 4318
+    name: http-otel
+  selector:
+    app: jaeger
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/manifests/addons/kiali.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/manifests/addons/kiali.yaml
new file mode 100644 (file)
index 0000000..1e74f84
--- /dev/null
@@ -0,0 +1,568 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# Source: kiali-server/templates/serviceaccount.yaml
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: kiali
+  namespace: istio-system
+  labels:
+    helm.sh/chart: kiali-server-1.76.0
+    app: kiali
+    app.kubernetes.io/name: kiali
+    app.kubernetes.io/instance: kiali
+    version: "v1.76.0"
+    app.kubernetes.io/version: "v1.76.0"
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/part-of: "kiali"
+...
+---
+# Source: kiali-server/templates/configmap.yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: kiali
+  namespace: istio-system
+  labels:
+    helm.sh/chart: kiali-server-1.76.0
+    app: kiali
+    app.kubernetes.io/name: kiali
+    app.kubernetes.io/instance: kiali
+    version: "v1.76.0"
+    app.kubernetes.io/version: "v1.76.0"
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/part-of: "kiali"
+data:
+  config.yaml: |
+    auth:
+      openid: {}
+      openshift:
+        client_id_prefix: kiali
+      strategy: anonymous
+    deployment:
+      accessible_namespaces:
+      - '**'
+      additional_service_yaml: {}
+      affinity:
+        node: {}
+        pod: {}
+        pod_anti: {}
+      configmap_annotations: {}
+      custom_secrets: []
+      host_aliases: []
+      hpa:
+        api_version: autoscaling/v2beta2
+        spec: {}
+      image_digest: ""
+      image_name: quay.io/kiali/kiali
+      image_pull_policy: Always
+      image_pull_secrets: []
+      image_version: v1.76
+      ingress:
+        additional_labels: {}
+        class_name: nginx
+        override_yaml:
+          metadata: {}
+      ingress_enabled: false
+      instance_name: kiali
+      logger:
+        log_format: text
+        log_level: info
+        sampler_rate: "1"
+        time_field_format: 2006-01-02T15:04:05Z07:00
+      namespace: istio-system
+      node_selector: {}
+      pod_annotations: {}
+      pod_labels:
+        sidecar.istio.io/inject: "false"
+      priority_class_name: ""
+      replicas: 1
+      resources:
+        limits:
+          memory: 1Gi
+        requests:
+          cpu: 10m
+          memory: 64Mi
+      secret_name: kiali
+      security_context: {}
+      service_annotations: {}
+      service_type: ""
+      tolerations: []
+      version_label: v1.76.0
+      view_only_mode: false
+    external_services:
+      custom_dashboards:
+        enabled: true
+      istio:
+        root_namespace: istio-system
+    identity:
+      cert_file: ""
+      private_key_file: ""
+    istio_namespace: istio-system
+    kiali_feature_flags:
+      certificates_information_indicators:
+        enabled: true
+        secrets:
+        - cacerts
+        - istio-ca-secret
+      clustering:
+        autodetect_secrets:
+          enabled: true
+          label: kiali.io/multiCluster=true
+        clusters: []
+      disabled_features: []
+      validations:
+        ignore:
+        - KIA1301
+    login_token:
+      signing_key: CHANGEME00000000
+    server:
+      metrics_enabled: true
+      metrics_port: 9090
+      port: 20001
+      web_root: /kiali
+...
+---
+# Source: kiali-server/templates/role-viewer.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  name: kiali-viewer
+  labels:
+    helm.sh/chart: kiali-server-1.76.0
+    app: kiali
+    app.kubernetes.io/name: kiali
+    app.kubernetes.io/instance: kiali
+    version: "v1.76.0"
+    app.kubernetes.io/version: "v1.76.0"
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/part-of: "kiali"
+rules:
+- apiGroups: [""]
+  resources:
+  - configmaps
+  - endpoints
+  - pods/log
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups: [""]
+  resources:
+  - namespaces
+  - pods
+  - replicationcontrollers
+  - services
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups: [""]
+  resources:
+  - pods/portforward
+  verbs:
+  - create
+  - post
+- apiGroups: ["extensions", "apps"]
+  resources:
+  - daemonsets
+  - deployments
+  - replicasets
+  - statefulsets
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups: ["batch"]
+  resources:
+  - cronjobs
+  - jobs
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - networking.istio.io
+  - security.istio.io
+  - extensions.istio.io
+  - telemetry.istio.io
+  - gateway.networking.k8s.io
+  resources: ["*"]
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups: ["apps.openshift.io"]
+  resources:
+  - deploymentconfigs
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups: ["project.openshift.io"]
+  resources:
+  - projects
+  verbs:
+  - get
+- apiGroups: ["route.openshift.io"]
+  resources:
+  - routes
+  verbs:
+  - get
+- apiGroups: ["authentication.k8s.io"]
+  resources:
+  - tokenreviews
+  verbs:
+  - create
+...
+---
+# Source: kiali-server/templates/role.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  name: kiali
+  labels:
+    helm.sh/chart: kiali-server-1.76.0
+    app: kiali
+    app.kubernetes.io/name: kiali
+    app.kubernetes.io/instance: kiali
+    version: "v1.76.0"
+    app.kubernetes.io/version: "v1.76.0"
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/part-of: "kiali"
+rules:
+- apiGroups: [""]
+  resources:
+  - configmaps
+  - endpoints
+  - pods/log
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups: [""]
+  resources:
+  - namespaces
+  - pods
+  - replicationcontrollers
+  - services
+  verbs:
+  - get
+  - list
+  - watch
+  - patch
+- apiGroups: [""]
+  resources:
+  - pods/portforward
+  verbs:
+  - create
+  - post
+- apiGroups: ["extensions", "apps"]
+  resources:
+  - daemonsets
+  - deployments
+  - replicasets
+  - statefulsets
+  verbs:
+  - get
+  - list
+  - watch
+  - patch
+- apiGroups: ["batch"]
+  resources:
+  - cronjobs
+  - jobs
+  verbs:
+  - get
+  - list
+  - watch
+  - patch
+- apiGroups:
+  - networking.istio.io
+  - security.istio.io
+  - extensions.istio.io
+  - telemetry.istio.io
+  - gateway.networking.k8s.io 
+  resources: ["*"]
+  verbs:
+  - get
+  - list
+  - watch
+  - create
+  - delete
+  - patch
+- apiGroups: ["apps.openshift.io"]
+  resources:
+  - deploymentconfigs
+  verbs:
+  - get
+  - list
+  - watch
+  - patch
+- apiGroups: ["project.openshift.io"]
+  resources:
+  - projects
+  verbs:
+  - get
+- apiGroups: ["route.openshift.io"]
+  resources:
+  - routes
+  verbs:
+  - get
+- apiGroups: ["authentication.k8s.io"]
+  resources:
+  - tokenreviews
+  verbs:
+  - create
+...
+---
+# Source: kiali-server/templates/rolebinding.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: kiali
+  labels:
+    helm.sh/chart: kiali-server-1.76.0
+    app: kiali
+    app.kubernetes.io/name: kiali
+    app.kubernetes.io/instance: kiali
+    version: "v1.76.0"
+    app.kubernetes.io/version: "v1.76.0"
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/part-of: "kiali"
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: kiali
+subjects:
+- kind: ServiceAccount
+  name: kiali
+  namespace: istio-system
+...
+---
+# Source: kiali-server/templates/role-controlplane.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: kiali-controlplane
+  namespace: istio-system
+  labels:
+    helm.sh/chart: kiali-server-1.76.0
+    app: kiali
+    app.kubernetes.io/name: kiali
+    app.kubernetes.io/instance: kiali
+    version: "v1.76.0"
+    app.kubernetes.io/version: "v1.76.0"
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/part-of: "kiali"
+rules:
+- apiGroups: [""]
+  resourceNames:
+  - cacerts
+  - istio-ca-secret
+  resources:
+  - secrets
+  verbs:
+  - get
+  - list
+  - watch
+...
+---
+# Source: kiali-server/templates/rolebinding-controlplane.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: kiali-controlplane
+  namespace: istio-system
+  labels:
+    helm.sh/chart: kiali-server-1.76.0
+    app: kiali
+    app.kubernetes.io/name: kiali
+    app.kubernetes.io/instance: kiali
+    version: "v1.76.0"
+    app.kubernetes.io/version: "v1.76.0"
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/part-of: "kiali"
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: kiali-controlplane
+subjects:
+- kind: ServiceAccount
+  name: kiali
+  namespace: istio-system
+...
+---
+# Source: kiali-server/templates/service.yaml
+apiVersion: v1
+kind: Service
+metadata:
+  name: kiali
+  namespace: istio-system
+  labels:
+    helm.sh/chart: kiali-server-1.76.0
+    app: kiali
+    app.kubernetes.io/name: kiali
+    app.kubernetes.io/instance: kiali
+    version: "v1.76.0"
+    app.kubernetes.io/version: "v1.76.0"
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/part-of: "kiali"
+  annotations:
+spec:
+  ports:
+  - name: http
+    appProtocol: http
+    protocol: TCP
+    port: 20001
+  - name: http-metrics
+    appProtocol: http
+    protocol: TCP
+    port: 9090
+  selector:
+    app.kubernetes.io/name: kiali
+    app.kubernetes.io/instance: kiali
+...
+---
+# Source: kiali-server/templates/deployment.yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: kiali
+  namespace: istio-system
+  labels:
+    helm.sh/chart: kiali-server-1.76.0
+    app: kiali
+    app.kubernetes.io/name: kiali
+    app.kubernetes.io/instance: kiali
+    version: "v1.76.0"
+    app.kubernetes.io/version: "v1.76.0"
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/part-of: "kiali"
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app.kubernetes.io/name: kiali
+      app.kubernetes.io/instance: kiali
+  strategy:
+    rollingUpdate:
+      maxSurge: 1
+      maxUnavailable: 1
+    type: RollingUpdate
+  template:
+    metadata:
+      name: kiali
+      labels:
+        helm.sh/chart: kiali-server-1.76.0
+        app: kiali
+        app.kubernetes.io/name: kiali
+        app.kubernetes.io/instance: kiali
+        version: "v1.76.0"
+        app.kubernetes.io/version: "v1.76.0"
+        app.kubernetes.io/managed-by: Helm
+        app.kubernetes.io/part-of: "kiali"
+        sidecar.istio.io/inject: "false"
+      annotations:
+        checksum/config: aebd819b94172ef9b148702b7bb438ac35bd1eb284bbb9b13769d8576374fbda
+        prometheus.io/scrape: "true"
+        prometheus.io/port: "9090"
+        kiali.io/dashboards: go,kiali
+    spec:
+      serviceAccountName: kiali
+      containers:
+      - image: "quay.io/kiali/kiali:v1.76"
+        imagePullPolicy: Always
+        name: kiali
+        command:
+        - "/opt/kiali/kiali"
+        - "-config"
+        - "/kiali-configuration/config.yaml"
+        securityContext:
+          allowPrivilegeEscalation: false
+          privileged: false
+          readOnlyRootFilesystem: true
+          runAsNonRoot: true
+          capabilities:
+            drop:
+            - ALL
+        ports:
+        - name: api-port
+          containerPort: 20001
+        - name: http-metrics
+          containerPort: 9090
+        readinessProbe:
+          httpGet:
+            path: /kiali/healthz
+            port: api-port
+            scheme: HTTP
+          initialDelaySeconds: 5
+          periodSeconds: 30
+        livenessProbe:
+          httpGet:
+            path: /kiali/healthz
+            port: api-port
+            scheme: HTTP
+          initialDelaySeconds: 5
+          periodSeconds: 30
+        env:
+        - name: ACTIVE_NAMESPACE
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.namespace
+        - name: LOG_LEVEL
+          value: "info"
+        - name: LOG_FORMAT
+          value: "text"
+        - name: LOG_TIME_FIELD_FORMAT
+          value: "2006-01-02T15:04:05Z07:00"
+        - name: LOG_SAMPLER_RATE
+          value: "1"
+        volumeMounts:
+        - name: kiali-configuration
+          mountPath: "/kiali-configuration"
+        - name: kiali-cert
+          mountPath: "/kiali-cert"
+        - name: kiali-secret
+          mountPath: "/kiali-secret"
+        - name: kiali-cabundle
+          mountPath: "/kiali-cabundle"
+        resources:
+          limits:
+            memory: 1Gi
+          requests:
+            cpu: 10m
+            memory: 64Mi
+      volumes:
+      - name: kiali-configuration
+        configMap:
+          name: kiali
+      - name: kiali-cert
+        secret:
+          secretName: istio.kiali-service-account
+          optional: true
+      - name: kiali-secret
+        secret:
+          secretName: kiali
+          optional: true
+      - name: kiali-cabundle
+        configMap:
+          name: kiali-cabundle
+          optional: true
+...
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/manifests/addons/loki.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/manifests/addons/loki.yaml
new file mode 100644 (file)
index 0000000..234581d
--- /dev/null
@@ -0,0 +1,302 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# Source: loki/templates/serviceaccount.yaml
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: loki
+  namespace: istio-system
+  labels:
+    helm.sh/chart: loki-4.8.0
+    app.kubernetes.io/name: loki
+    app.kubernetes.io/instance: loki
+    app.kubernetes.io/version: "2.7.3"
+    app.kubernetes.io/managed-by: Helm
+automountServiceAccountToken: true
+---
+# Source: loki/templates/configmap.yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: loki
+  namespace: istio-system
+  labels:
+    helm.sh/chart: loki-4.8.0
+    app.kubernetes.io/name: loki
+    app.kubernetes.io/instance: loki
+    app.kubernetes.io/version: "2.7.3"
+    app.kubernetes.io/managed-by: Helm
+data:
+  config.yaml: |
+    auth_enabled: false
+    common:
+      compactor_address: 'loki'
+      path_prefix: /var/loki
+      replication_factor: 1
+      storage:
+        filesystem:
+          chunks_directory: /var/loki/chunks
+          rules_directory: /var/loki/rules
+    limits_config:
+      enforce_metric_name: false
+      max_cache_freshness_per_query: 10m
+      reject_old_samples: true
+      reject_old_samples_max_age: 168h
+      split_queries_by_interval: 15m
+    memberlist:
+      join_members:
+      - loki-memberlist
+    query_range:
+      align_queries_with_step: true
+    ruler:
+      storage:
+        type: local
+    runtime_config:
+      file: /etc/loki/runtime-config/runtime-config.yaml
+    schema_config:
+      configs:
+      - from: "2022-01-11"
+        index:
+          period: 24h
+          prefix: loki_index_
+        object_store: filesystem
+        schema: v12
+        store: boltdb-shipper
+    server:
+      grpc_listen_port: 9095
+      http_listen_port: 3100
+    storage_config:
+      hedging:
+        at: 250ms
+        max_per_second: 20
+        up_to: 3
+    table_manager:
+      retention_deletes_enabled: false
+      retention_period: 0
+---
+# Source: loki/templates/runtime-configmap.yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: loki-runtime
+  namespace: istio-system
+  labels:
+    helm.sh/chart: loki-4.8.0
+    app.kubernetes.io/name: loki
+    app.kubernetes.io/instance: loki
+    app.kubernetes.io/version: "2.7.3"
+    app.kubernetes.io/managed-by: Helm
+data:
+  runtime-config.yaml: |
+    {}
+---
+# Source: loki/templates/service-memberlist.yaml
+apiVersion: v1
+kind: Service
+metadata:
+  name: loki-memberlist
+  namespace: istio-system
+  labels:
+    helm.sh/chart: loki-4.8.0
+    app.kubernetes.io/name: loki
+    app.kubernetes.io/instance: loki
+    app.kubernetes.io/version: "2.7.3"
+    app.kubernetes.io/managed-by: Helm
+spec:
+  type: ClusterIP
+  clusterIP: None
+  ports:
+    - name: tcp
+      port: 7946
+      targetPort: http-memberlist
+      protocol: TCP
+  selector:
+    app.kubernetes.io/name: loki
+    app.kubernetes.io/instance: loki
+    app.kubernetes.io/part-of: memberlist
+---
+# Source: loki/templates/single-binary/service-headless.yaml
+apiVersion: v1
+kind: Service
+metadata:
+  name: loki-headless
+  namespace: istio-system
+  labels:
+    helm.sh/chart: loki-4.8.0
+    app.kubernetes.io/name: loki
+    app.kubernetes.io/instance: loki
+    app.kubernetes.io/version: "2.7.3"
+    app.kubernetes.io/managed-by: Helm
+    variant: headless
+    prometheus.io/service-monitor: "false"
+spec:
+  clusterIP: None
+  ports:
+    - name: http-metrics
+      port: 3100
+      targetPort: http-metrics
+      protocol: TCP
+  selector:
+    app.kubernetes.io/name: loki
+    app.kubernetes.io/instance: loki
+---
+# Source: loki/templates/single-binary/service.yaml
+apiVersion: v1
+kind: Service
+metadata:
+  name: loki
+  namespace: istio-system
+  labels:
+    helm.sh/chart: loki-4.8.0
+    app.kubernetes.io/name: loki
+    app.kubernetes.io/instance: loki
+    app.kubernetes.io/version: "2.7.3"
+    app.kubernetes.io/managed-by: Helm
+spec:
+  type: ClusterIP
+  ports:
+    - name: http-metrics
+      port: 3100
+      targetPort: http-metrics
+      protocol: TCP
+    - name: grpc
+      port: 9095
+      targetPort: grpc
+      protocol: TCP
+  selector:
+    app.kubernetes.io/name: loki
+    app.kubernetes.io/instance: loki
+    app.kubernetes.io/component: single-binary
+---
+# Source: loki/templates/single-binary/statefulset.yaml
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+  name: loki
+  namespace: istio-system
+  labels:
+    helm.sh/chart: loki-4.8.0
+    app.kubernetes.io/name: loki
+    app.kubernetes.io/instance: loki
+    app.kubernetes.io/version: "2.7.3"
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/component: single-binary
+    app.kubernetes.io/part-of: memberlist
+spec:
+  replicas: 1
+  podManagementPolicy: Parallel
+  updateStrategy:
+    rollingUpdate:
+      partition: 0
+  serviceName: loki-headless
+  revisionHistoryLimit: 10
+  persistentVolumeClaimRetentionPolicy:
+    whenDeleted: Delete
+    whenScaled: Delete
+  selector:
+    matchLabels:
+      app.kubernetes.io/name: loki
+      app.kubernetes.io/instance: loki
+      app.kubernetes.io/component: single-binary
+  template:
+    metadata:
+      annotations:
+        checksum/config: a9239b6352e34bbfc748669ed46cb24211fc3491ee7f2c6381af805f8f08fe29
+      labels:
+        app.kubernetes.io/name: loki
+        app.kubernetes.io/instance: loki
+        app.kubernetes.io/component: single-binary
+        app.kubernetes.io/part-of: memberlist
+    spec:
+      serviceAccountName: loki
+      automountServiceAccountToken: true
+      enableServiceLinks: true
+      securityContext:
+        fsGroup: 10001
+        runAsGroup: 10001
+        runAsNonRoot: true
+        runAsUser: 10001
+      terminationGracePeriodSeconds: 30
+      containers:
+        - name: loki
+          image: docker.io/grafana/loki:2.7.3
+          imagePullPolicy: IfNotPresent
+          args:
+            - -config.file=/etc/loki/config/config.yaml
+            - -target=all
+          ports:
+            - name: http-metrics
+              containerPort: 3100
+              protocol: TCP
+            - name: grpc
+              containerPort: 9095
+              protocol: TCP
+            - name: http-memberlist
+              containerPort: 7946
+              protocol: TCP
+          securityContext:
+            allowPrivilegeEscalation: false
+            capabilities:
+              drop:
+              - ALL
+            readOnlyRootFilesystem: true
+          readinessProbe:
+            httpGet:
+              path: /ready
+              port: http-metrics
+            initialDelaySeconds: 30
+            timeoutSeconds: 1
+          volumeMounts:
+            - name: tmp
+              mountPath: /tmp
+            - name: config
+              mountPath: /etc/loki/config
+            - name: runtime-config
+              mountPath: /etc/loki/runtime-config
+            - name: storage
+              mountPath: /var/loki
+          resources:
+            {}
+      affinity:
+        podAntiAffinity:
+          requiredDuringSchedulingIgnoredDuringExecution:
+            - labelSelector:
+                matchLabels:
+                  app.kubernetes.io/name: loki
+                  app.kubernetes.io/instance: loki
+                  app.kubernetes.io/component: single-binary
+              topologyKey: kubernetes.io/hostname
+      volumes:
+        - name: tmp
+          emptyDir: {}
+        - name: config
+          configMap:
+            name: loki
+        - name: runtime-config
+          configMap:
+            name: loki-runtime
+  volumeClaimTemplates:
+    - metadata:
+        name: storage
+      spec:
+        accessModes:
+          - ReadWriteOnce
+        resources:
+          requests:
+            storage: "10Gi"
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/manifests/addons/prometheus.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/manifests/addons/prometheus.yaml
new file mode 100644 (file)
index 0000000..63ee77b
--- /dev/null
@@ -0,0 +1,548 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# Source: prometheus/templates/serviceaccount.yaml
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  labels:
+    component: "server"
+    app: prometheus
+    release: prometheus
+    chart: prometheus-19.6.1
+    heritage: Helm
+  name: prometheus
+  namespace: istio-system
+  annotations:
+    {}
+---
+# Source: prometheus/templates/cm.yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  labels:
+    component: "server"
+    app: prometheus
+    release: prometheus
+    chart: prometheus-19.6.1
+    heritage: Helm
+  name: prometheus
+  namespace: istio-system
+data:
+  allow-snippet-annotations: "false"
+  alerting_rules.yml: |
+    {}
+  alerts: |
+    {}
+  prometheus.yml: |
+    global:
+      evaluation_interval: 1m
+      scrape_interval: 15s
+      scrape_timeout: 10s
+    rule_files:
+    - /etc/config/recording_rules.yml
+    - /etc/config/alerting_rules.yml
+    - /etc/config/rules
+    - /etc/config/alerts
+    scrape_configs:
+    - job_name: prometheus
+      static_configs:
+      - targets:
+        - localhost:9090
+    - bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
+      job_name: kubernetes-apiservers
+      kubernetes_sd_configs:
+      - role: endpoints
+      relabel_configs:
+      - action: keep
+        regex: default;kubernetes;https
+        source_labels:
+        - __meta_kubernetes_namespace
+        - __meta_kubernetes_service_name
+        - __meta_kubernetes_endpoint_port_name
+      scheme: https
+      tls_config:
+        ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
+        insecure_skip_verify: true
+    - bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
+      job_name: kubernetes-nodes
+      kubernetes_sd_configs:
+      - role: node
+      relabel_configs:
+      - action: labelmap
+        regex: __meta_kubernetes_node_label_(.+)
+      - replacement: kubernetes.default.svc:443
+        target_label: __address__
+      - regex: (.+)
+        replacement: /api/v1/nodes/$1/proxy/metrics
+        source_labels:
+        - __meta_kubernetes_node_name
+        target_label: __metrics_path__
+      scheme: https
+      tls_config:
+        ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
+        insecure_skip_verify: true
+    - bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
+      job_name: kubernetes-nodes-cadvisor
+      kubernetes_sd_configs:
+      - role: node
+      relabel_configs:
+      - action: labelmap
+        regex: __meta_kubernetes_node_label_(.+)
+      - replacement: kubernetes.default.svc:443
+        target_label: __address__
+      - regex: (.+)
+        replacement: /api/v1/nodes/$1/proxy/metrics/cadvisor
+        source_labels:
+        - __meta_kubernetes_node_name
+        target_label: __metrics_path__
+      scheme: https
+      tls_config:
+        ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
+        insecure_skip_verify: true
+    - honor_labels: true
+      job_name: kubernetes-service-endpoints
+      kubernetes_sd_configs:
+      - role: endpoints
+      relabel_configs:
+      - action: keep
+        regex: true
+        source_labels:
+        - __meta_kubernetes_service_annotation_prometheus_io_scrape
+      - action: drop
+        regex: true
+        source_labels:
+        - __meta_kubernetes_service_annotation_prometheus_io_scrape_slow
+      - action: replace
+        regex: (https?)
+        source_labels:
+        - __meta_kubernetes_service_annotation_prometheus_io_scheme
+        target_label: __scheme__
+      - action: replace
+        regex: (.+)
+        source_labels:
+        - __meta_kubernetes_service_annotation_prometheus_io_path
+        target_label: __metrics_path__
+      - action: replace
+        regex: (.+?)(?::\d+)?;(\d+)
+        replacement: $1:$2
+        source_labels:
+        - __address__
+        - __meta_kubernetes_service_annotation_prometheus_io_port
+        target_label: __address__
+      - action: labelmap
+        regex: __meta_kubernetes_service_annotation_prometheus_io_param_(.+)
+        replacement: __param_$1
+      - action: labelmap
+        regex: __meta_kubernetes_service_label_(.+)
+      - action: replace
+        source_labels:
+        - __meta_kubernetes_namespace
+        target_label: namespace
+      - action: replace
+        source_labels:
+        - __meta_kubernetes_service_name
+        target_label: service
+      - action: replace
+        source_labels:
+        - __meta_kubernetes_pod_node_name
+        target_label: node
+    - honor_labels: true
+      job_name: kubernetes-service-endpoints-slow
+      kubernetes_sd_configs:
+      - role: endpoints
+      relabel_configs:
+      - action: keep
+        regex: true
+        source_labels:
+        - __meta_kubernetes_service_annotation_prometheus_io_scrape_slow
+      - action: replace
+        regex: (https?)
+        source_labels:
+        - __meta_kubernetes_service_annotation_prometheus_io_scheme
+        target_label: __scheme__
+      - action: replace
+        regex: (.+)
+        source_labels:
+        - __meta_kubernetes_service_annotation_prometheus_io_path
+        target_label: __metrics_path__
+      - action: replace
+        regex: (.+?)(?::\d+)?;(\d+)
+        replacement: $1:$2
+        source_labels:
+        - __address__
+        - __meta_kubernetes_service_annotation_prometheus_io_port
+        target_label: __address__
+      - action: labelmap
+        regex: __meta_kubernetes_service_annotation_prometheus_io_param_(.+)
+        replacement: __param_$1
+      - action: labelmap
+        regex: __meta_kubernetes_service_label_(.+)
+      - action: replace
+        source_labels:
+        - __meta_kubernetes_namespace
+        target_label: namespace
+      - action: replace
+        source_labels:
+        - __meta_kubernetes_service_name
+        target_label: service
+      - action: replace
+        source_labels:
+        - __meta_kubernetes_pod_node_name
+        target_label: node
+      scrape_interval: 5m
+      scrape_timeout: 30s
+    - honor_labels: true
+      job_name: prometheus-pushgateway
+      kubernetes_sd_configs:
+      - role: service
+      relabel_configs:
+      - action: keep
+        regex: pushgateway
+        source_labels:
+        - __meta_kubernetes_service_annotation_prometheus_io_probe
+    - honor_labels: true
+      job_name: kubernetes-services
+      kubernetes_sd_configs:
+      - role: service
+      metrics_path: /probe
+      params:
+        module:
+        - http_2xx
+      relabel_configs:
+      - action: keep
+        regex: true
+        source_labels:
+        - __meta_kubernetes_service_annotation_prometheus_io_probe
+      - source_labels:
+        - __address__
+        target_label: __param_target
+      - replacement: blackbox
+        target_label: __address__
+      - source_labels:
+        - __param_target
+        target_label: instance
+      - action: labelmap
+        regex: __meta_kubernetes_service_label_(.+)
+      - source_labels:
+        - __meta_kubernetes_namespace
+        target_label: namespace
+      - source_labels:
+        - __meta_kubernetes_service_name
+        target_label: service
+    - honor_labels: true
+      job_name: kubernetes-pods
+      kubernetes_sd_configs:
+      - role: pod
+      relabel_configs:
+      - action: keep
+        regex: true
+        source_labels:
+        - __meta_kubernetes_pod_annotation_prometheus_io_scrape
+      - action: drop
+        regex: true
+        source_labels:
+        - __meta_kubernetes_pod_annotation_prometheus_io_scrape_slow
+      - action: replace
+        regex: (https?)
+        source_labels:
+        - __meta_kubernetes_pod_annotation_prometheus_io_scheme
+        target_label: __scheme__
+      - action: replace
+        regex: (.+)
+        source_labels:
+        - __meta_kubernetes_pod_annotation_prometheus_io_path
+        target_label: __metrics_path__
+      - action: replace
+        regex: (\d+);(([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})
+        replacement: '[$2]:$1'
+        source_labels:
+        - __meta_kubernetes_pod_annotation_prometheus_io_port
+        - __meta_kubernetes_pod_ip
+        target_label: __address__
+      - action: replace
+        regex: (\d+);((([0-9]+?)(\.|$)){4})
+        replacement: $2:$1
+        source_labels:
+        - __meta_kubernetes_pod_annotation_prometheus_io_port
+        - __meta_kubernetes_pod_ip
+        target_label: __address__
+      - action: labelmap
+        regex: __meta_kubernetes_pod_annotation_prometheus_io_param_(.+)
+        replacement: __param_$1
+      - action: labelmap
+        regex: __meta_kubernetes_pod_label_(.+)
+      - action: replace
+        source_labels:
+        - __meta_kubernetes_namespace
+        target_label: namespace
+      - action: replace
+        source_labels:
+        - __meta_kubernetes_pod_name
+        target_label: pod
+      - action: drop
+        regex: Pending|Succeeded|Failed|Completed
+        source_labels:
+        - __meta_kubernetes_pod_phase
+    - honor_labels: true
+      job_name: kubernetes-pods-slow
+      kubernetes_sd_configs:
+      - role: pod
+      relabel_configs:
+      - action: keep
+        regex: true
+        source_labels:
+        - __meta_kubernetes_pod_annotation_prometheus_io_scrape_slow
+      - action: replace
+        regex: (https?)
+        source_labels:
+        - __meta_kubernetes_pod_annotation_prometheus_io_scheme
+        target_label: __scheme__
+      - action: replace
+        regex: (.+)
+        source_labels:
+        - __meta_kubernetes_pod_annotation_prometheus_io_path
+        target_label: __metrics_path__
+      - action: replace
+        regex: (\d+);(([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})
+        replacement: '[$2]:$1'
+        source_labels:
+        - __meta_kubernetes_pod_annotation_prometheus_io_port
+        - __meta_kubernetes_pod_ip
+        target_label: __address__
+      - action: replace
+        regex: (\d+);((([0-9]+?)(\.|$)){4})
+        replacement: $2:$1
+        source_labels:
+        - __meta_kubernetes_pod_annotation_prometheus_io_port
+        - __meta_kubernetes_pod_ip
+        target_label: __address__
+      - action: labelmap
+        regex: __meta_kubernetes_pod_annotation_prometheus_io_param_(.+)
+        replacement: __param_$1
+      - action: labelmap
+        regex: __meta_kubernetes_pod_label_(.+)
+      - action: replace
+        source_labels:
+        - __meta_kubernetes_namespace
+        target_label: namespace
+      - action: replace
+        source_labels:
+        - __meta_kubernetes_pod_name
+        target_label: pod
+      - action: drop
+        regex: Pending|Succeeded|Failed|Completed
+        source_labels:
+        - __meta_kubernetes_pod_phase
+      scrape_interval: 5m
+      scrape_timeout: 30s
+  recording_rules.yml: |
+    {}
+  rules: |
+    {}
+---
+# Source: prometheus/templates/clusterrole.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  labels:
+    component: "server"
+    app: prometheus
+    release: prometheus
+    chart: prometheus-19.6.1
+    heritage: Helm
+  name: prometheus
+rules:
+  - apiGroups:
+      - ""
+    resources:
+      - nodes
+      - nodes/proxy
+      - nodes/metrics
+      - services
+      - endpoints
+      - pods
+      - ingresses
+      - configmaps
+    verbs:
+      - get
+      - list
+      - watch
+  - apiGroups:
+      - "extensions"
+      - "networking.k8s.io"
+    resources:
+      - ingresses/status
+      - ingresses
+    verbs:
+      - get
+      - list
+      - watch
+  - nonResourceURLs:
+      - "/metrics"
+    verbs:
+      - get
+---
+# Source: prometheus/templates/clusterrolebinding.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  labels:
+    component: "server"
+    app: prometheus
+    release: prometheus
+    chart: prometheus-19.6.1
+    heritage: Helm
+  name: prometheus
+subjects:
+  - kind: ServiceAccount
+    name: prometheus
+    namespace: istio-system
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: prometheus
+---
+# Source: prometheus/templates/service.yaml
+apiVersion: v1
+kind: Service
+metadata:
+  labels:
+    component: "server"
+    app: prometheus
+    release: prometheus
+    chart: prometheus-19.6.1
+    heritage: Helm
+  name: prometheus
+  namespace: istio-system
+spec:
+  ports:
+    - name: http
+      port: 9090
+      protocol: TCP
+      targetPort: 9090
+  selector:
+    component: "server"
+    app: prometheus
+    release: prometheus
+  sessionAffinity: None
+  type: "ClusterIP"
+---
+# Source: prometheus/templates/deploy.yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  labels:
+    component: "server"
+    app: prometheus
+    release: prometheus
+    chart: prometheus-19.6.1
+    heritage: Helm
+  name: prometheus
+  namespace: istio-system
+spec:
+  selector:
+    matchLabels:
+      component: "server"
+      app: prometheus
+      release: prometheus
+  replicas: 1
+  strategy:
+    type: Recreate
+    rollingUpdate: null
+  template:
+    metadata:
+      labels:
+        component: "server"
+        app: prometheus
+        release: prometheus
+        chart: prometheus-19.6.1
+        heritage: Helm
+        
+        sidecar.istio.io/inject: "false"
+    spec:
+      enableServiceLinks: true
+      serviceAccountName: prometheus
+      containers:
+        - name: prometheus-server-configmap-reload
+          image: "jimmidyson/configmap-reload:v0.8.0"
+          imagePullPolicy: "IfNotPresent"
+          args:
+            - --volume-dir=/etc/config
+            - --webhook-url=http://127.0.0.1:9090/-/reload
+          resources:
+            {}
+          volumeMounts:
+            - name: config-volume
+              mountPath: /etc/config
+              readOnly: true
+
+        - name: prometheus-server
+          image: "prom/prometheus:v2.41.0"
+          imagePullPolicy: "IfNotPresent"
+          args:
+            - --storage.tsdb.retention.time=15d
+            - --config.file=/etc/config/prometheus.yml
+            - --storage.tsdb.path=/data
+            - --web.console.libraries=/etc/prometheus/console_libraries
+            - --web.console.templates=/etc/prometheus/consoles
+            - --web.enable-lifecycle
+          ports:
+            - containerPort: 9090
+          readinessProbe:
+            httpGet:
+              path: /-/ready
+              port: 9090
+              scheme: HTTP
+            initialDelaySeconds: 0
+            periodSeconds: 5
+            timeoutSeconds: 4
+            failureThreshold: 3
+            successThreshold: 1
+          livenessProbe:
+            httpGet:
+              path: /-/healthy
+              port: 9090
+              scheme: HTTP
+            initialDelaySeconds: 30
+            periodSeconds: 15
+            timeoutSeconds: 10
+            failureThreshold: 3
+            successThreshold: 1
+          resources:
+            {}
+          volumeMounts:
+            - name: config-volume
+              mountPath: /etc/config
+            - name: storage-volume
+              mountPath: /data
+              subPath: ""
+      dnsPolicy: ClusterFirst
+      securityContext:
+        fsGroup: 65534
+        runAsGroup: 65534
+        runAsNonRoot: true
+        runAsUser: 65534
+      terminationGracePeriodSeconds: 300
+      volumes:
+        - name: config-volume
+          configMap:
+            name: prometheus
+        - name: storage-volume
+          emptyDir:
+            {}
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/manifests/core/istio-hr.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/manifests/core/istio-hr.yaml
new file mode 100644 (file)
index 0000000..384cc25
--- /dev/null
@@ -0,0 +1,61 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# Istio base: CRDs:
+# helm install istio-base istio/base -n istio-system --set defaultRevision=default
+apiVersion: helm.toolkit.fluxcd.io/v2beta1
+kind: HelmRelease
+metadata:
+  name: istio-base
+  namespace: istio-system
+spec:
+  chart:
+    spec:
+      chart: base
+      reconcileStrategy: ChartVersion
+      sourceRef:
+        kind: HelmRepository
+        name: istio
+        namespace: istio-system
+  values:
+    defaultRevision: default
+  interval: 30s
+
+---
+# Istio discovery:
+# helm install istiod istio/istiod -n istio-system --wait
+apiVersion: helm.toolkit.fluxcd.io/v2beta1
+kind: HelmRelease
+metadata:
+  name: istiod
+  namespace: istio-system
+spec:
+  targetNamespace: istio-system
+  dependsOn:
+    - name: istio-base
+  chart:
+    spec:
+      chart: istiod
+      reconcileStrategy: ChartVersion
+      sourceRef:
+        kind: HelmRepository
+        name: istio
+        namespace: istio-system
+  values:
+    defaultRevision: default
+  interval: 30s
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/manifests/core/istio-namespace.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/manifests/core/istio-namespace.yaml
new file mode 100644 (file)
index 0000000..d458626
--- /dev/null
@@ -0,0 +1,23 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# Namespace
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: istio-system
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/manifests/core/istio-repo.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/manifests/core/istio-repo.yaml
new file mode 100644 (file)
index 0000000..1b99e5f
--- /dev/null
@@ -0,0 +1,27 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+# helm repo add istio https://istio-release.storage.googleapis.com/charts
+apiVersion: source.toolkit.fluxcd.io/v1beta2
+kind: HelmRepository
+metadata:
+  name: istio
+  namespace: istio-system
+spec:
+  interval: 30s
+  url: https://istio-release.storage.googleapis.com/charts
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/templates/istio-addons-ks.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/templates/istio-addons-ks.yaml
new file mode 100644 (file)
index 0000000..2704381
--- /dev/null
@@ -0,0 +1,33 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: istio-addons
+  namespace: flux-system
+spec:
+  dependsOn:
+  - name: istio-core
+  interval: 1h0m0s
+  path: ./infra-controllers/istio/manifests/addons
+  prune: true
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/templates/istio-core-ks.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/istio/templates/istio-core-ks.yaml
new file mode 100644 (file)
index 0000000..20afba8
--- /dev/null
@@ -0,0 +1,31 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: istio-core
+  namespace: flux-system
+spec:
+  interval: 1h0m0s
+  path: ./infra-controllers/istio/manifests/core
+  prune: true
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/komoplane/manifests/komodorio-repo.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/komoplane/manifests/komodorio-repo.yaml
new file mode 100644 (file)
index 0000000..42bd4f8
--- /dev/null
@@ -0,0 +1,26 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: source.toolkit.fluxcd.io/v1beta2
+kind: HelmRepository
+metadata:
+  name: komodorio
+  namespace: crossplane-system
+spec:
+  interval: 30s
+  url: https://helm-charts.komodor.io
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/komoplane/manifests/komoplane-hr.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/komoplane/manifests/komoplane-hr.yaml
new file mode 100644 (file)
index 0000000..8ad8ddf
--- /dev/null
@@ -0,0 +1,33 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: helm.toolkit.fluxcd.io/v2beta1
+kind: HelmRelease
+metadata:
+  name: komoplane
+  namespace: crossplane-system
+spec:
+  chart:
+    spec:
+      chart: komoplane
+      reconcileStrategy: ChartVersion
+      sourceRef:
+        kind: HelmRepository
+        name: komodorio
+        namespace: crossplane-system
+  interval: 30s
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/komoplane/templates/komoplane-ks.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/komoplane/templates/komoplane-ks.yaml
new file mode 100644 (file)
index 0000000..674bf84
--- /dev/null
@@ -0,0 +1,31 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: komoplane
+  namespace: flux-system
+spec:
+  interval: 1h0m0s
+  path: ./infra-controllers/komoplane/manifests
+  prune: true
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/kubernetes-dashboard/manifests/kubernetes-dashboard-hr.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/kubernetes-dashboard/manifests/kubernetes-dashboard-hr.yaml
new file mode 100644 (file)
index 0000000..7a82e5d
--- /dev/null
@@ -0,0 +1,37 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: helm.toolkit.fluxcd.io/v2beta1
+kind: HelmRelease
+metadata:
+  name: kubernetes-dashboard
+  namespace: flux-system
+spec:
+  chart:
+    spec:
+      chart: kubernetes-dashboard
+      reconcileStrategy: ChartVersion
+      sourceRef:
+        kind: HelmRepository
+        name: kubernetes-dashboard
+        namespace: flux-system
+  install:
+    createNamespace: true
+  interval: 10m0s
+  targetNamespace: kubernetes-dashboard
+  values: {}
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/kubernetes-dashboard/manifests/kubernetes-dashboard-repo.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/kubernetes-dashboard/manifests/kubernetes-dashboard-repo.yaml
new file mode 100644 (file)
index 0000000..b07a4e9
--- /dev/null
@@ -0,0 +1,26 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: source.toolkit.fluxcd.io/v1beta2
+kind: HelmRepository
+metadata:
+  name: kubernetes-dashboard
+  namespace: flux-system
+spec:
+  interval: 10m0s
+  url: https://kubernetes.github.io/dashboard/
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/kubernetes-dashboard/templates/kubernetes-dashboard-ks.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/kubernetes-dashboard/templates/kubernetes-dashboard-ks.yaml
new file mode 100644 (file)
index 0000000..087252b
--- /dev/null
@@ -0,0 +1,31 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: kubernetes-dashboard
+  namespace: flux-system
+spec:
+  interval: 1h0m0s
+  path: ./infra-controllers/kubernetes-dashboard/manifests
+  prune: true
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/weave-gitops/manifests/weave-gitops-dashboard.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/weave-gitops/manifests/weave-gitops-dashboard.yaml
new file mode 100644 (file)
index 0000000..abbdc2f
--- /dev/null
@@ -0,0 +1,58 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: source.toolkit.fluxcd.io/v1beta2
+kind: HelmRepository
+metadata:
+  annotations:
+    metadata.weave.works/description: This is the source location for the Weave GitOps
+      Dashboard's helm chart.
+  labels:
+    app.kubernetes.io/component: ui
+    app.kubernetes.io/created-by: weave-gitops-cli
+    app.kubernetes.io/name: weave-gitops-dashboard
+    app.kubernetes.io/part-of: weave-gitops
+  name: ww-gitops
+  namespace: flux-system
+spec:
+  interval: 1h0m0s
+  type: oci
+  url: oci://ghcr.io/weaveworks/charts
+---
+apiVersion: helm.toolkit.fluxcd.io/v2beta1
+kind: HelmRelease
+metadata:
+  annotations:
+    metadata.weave.works/description: This is the Weave GitOps Dashboard.  It provides
+      a simple way to get insights into your GitOps workloads.
+  name: ww-gitops
+  namespace: flux-system
+spec:
+  chart:
+    spec:
+      chart: weave-gitops
+      sourceRef:
+        kind: HelmRepository
+        name: ww-gitops
+  interval: 1h0m0s
+  values:
+    adminUser:
+      create: true
+      passwordHash: $2a$10$M5y6e9EzHvYOykBF7SqxEeI1Hm.yCTaZfaLJMdD5RXZNDRGBeETEG
+      username: admin
+
diff --git a/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/weave-gitops/templates/weave-gitops-ks.yaml b/installers/mgmt-cluster/flux/templates/sw-catalogs/infra-controllers/weave-gitops/templates/weave-gitops-ks.yaml
new file mode 100644 (file)
index 0000000..0f5f135
--- /dev/null
@@ -0,0 +1,31 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+---
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: weave-gitops
+  namespace: flux-system
+spec:
+  interval: 1h0m0s
+  path: ./infra-controllers/weave-gitops/manifests
+  prune: true
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
diff --git a/installers/mgmt-cluster/gitea/00-custom-config.rc b/installers/mgmt-cluster/gitea/00-custom-config.rc
new file mode 100644 (file)
index 0000000..e5b0c6b
--- /dev/null
@@ -0,0 +1,28 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+# Transitent file to be sourced to bootstrap some key variables
+
+# Random passwords
+export GITEA_ADMINISTRATOR_PASSWORD=$(apg -a 1 -M sncl -n 1 -m 12 -x 12 -E \\\*\'\"\`\$\<\{\})
+export GITEA_STD_USER_PASS=$(apg -a 1 -M sncl -n 1 -m 10 -x 10 -E \\\*\'\"\`\$\<\{\})
+
+# Uncomment to deploy Gitea only as ClusterIP service (i.e., no LoadBalancer)
+# export GITEA_CHART_VALUES_FILE=values-all.yaml
+#
+# Uncomment to deploy Gitea using an Ingress for web services
+# export GITEA_CHART_VALUES_FILE=values-all.yaml
diff --git a/installers/mgmt-cluster/gitea/01-base-config.rc b/installers/mgmt-cluster/gitea/01-base-config.rc
new file mode 100644 (file)
index 0000000..c682a7a
--- /dev/null
@@ -0,0 +1,42 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+# Base inputs, unlikely to change
+export GITEA_ENV_NAME=${GITEA_ENV_NAME:-gitea-at-osm}
+
+# Chart values, selecting the mode of deployment
+export GITEA_CHART_VALUES_FILE=${GITEA_CHART_VALUES_FILE:-values-standalone.yaml}
+
+# Location where credentials should be saved
+export CREDENTIALS_DIR=${CREDENTIALS_DIR:-../../../.credentials}; export CREDENTIALS_DIR=$(readlink -f "${CREDENTIALS_DIR}")
+
+# Admin user
+export GITEA_ADMINISTRATOR_USERNAME=${GITEA_ADMINISTRATOR_USERNAME:-osm-admin}
+#--------- CHANGE DEFAULT:
+export GITEA_ADMINISTRATOR_PASSWORD=${GITEA_ADMINISTRATOR_PASSWORD:-PleaseChange123%}
+#------------------------
+export GITEA_ADMINISTRATOR_TOKEN_NAME=${GITEA_ADMINISTRATOR_TOKEN_NAME:-admin-token}
+
+# Regular user
+export GITEA_STD_USERNAME=${GITEA_STD_USERNAME:-osm-developer}
+#--------- CHANGE DEFAULT:
+export GITEA_STD_USER_PASS=${GITEA_STD_USER_PASS:-PleaseChange123!}
+#------------------------
+export GITEA_STD_TOKEN_NAME=${GITEA_STD_TOKEN_NAME:-developer-token}
+
+# (optional) Organization name
+export GITEA_EXTRA_ORGANIZATION=${GITEA_EXTRA_ORGANIZATION:-OSM}
diff --git a/installers/mgmt-cluster/gitea/02-deploy-gitea.sh b/installers/mgmt-cluster/gitea/02-deploy-gitea.sh
new file mode 100755 (executable)
index 0000000..67a22d9
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e
+
+export HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+source "${HERE}/library/functions.sh"
+source "${HERE}/library/trap.sh"
+
+if [[ -z "${GITEA_ENV_NAME}" ]]; then
+    m "No target environment was loaded. Please source one of the .rc environment files first. $DURATION" "$RED"
+    exit 1
+fi
+
+# Deploy Helm chart with required values
+helm repo add gitea-charts https://dl.gitea.io/charts/
+m "Deploying Gitea's Helm chart..."
+helm install gitea gitea-charts/gitea \
+    --version=7.0.4 \
+    --namespace=gitea \
+    --values "${HERE}/${GITEA_CHART_VALUES_FILE}" \
+    --set=gitea.admin.username="${GITEA_ADMINISTRATOR_USERNAME}" \
+    --set=gitea.admin.password="${GITEA_ADMINISTRATOR_PASSWORD@Q}" \
+    --create-namespace \
+    --wait
+
+m "Waiting for Gitea to start..."
+# See: https://github.com/kubernetes/kubernetes/issues/79606
+kubectl rollout status statefulset/gitea --namespace=gitea --watch --timeout=1h
diff --git a/installers/mgmt-cluster/gitea/03-get-gitea-connection-info.rc b/installers/mgmt-cluster/gitea/03-get-gitea-connection-info.rc
new file mode 100644 (file)
index 0000000..fed055b
--- /dev/null
@@ -0,0 +1,120 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+# Retrieves Gitea connection info data
+
+# Helper function to monitor progress of a condition
+function monitor_condition() {
+    local CONDITION="$1"        # Function with the condition
+    local MESSAGE="${2:-}"      # Message during each check
+    local TIMEOUT="${3:-300}"   # Timeout, in seconds (default: 5 minutes)
+    local STEP="${4:-2}"        # Polling period (default: 2 seconds)
+
+    until "${CONDITION}" || [ ${TIMEOUT} -le 0 ]
+    do
+        echo -en "${MESSAGE}"
+
+        ((TIMEOUT-=${STEP}))
+
+        sleep "${STEP}"
+    done
+
+    "${CONDITION}"
+}
+
+# Check that the IP associated to the Ingress service is available
+function ingress_service_ip_available() {
+    kubectl get svc/ingress-nginx-controller -n ingress-nginx -o jsonpath='{.status.loadBalancer.ingress[0].ip}' > /dev/null
+}
+
+# Wait until the IP associated to the Ingress service is available
+function wait_until_ingress_service_ip_available() {
+    monitor_condition ingress_service_ip_available "External IP address for Ingress not ready yet...\n" 300 5
+    if [[ $? -ne 0 ]]
+    then
+        echo -e "\nFATAL: Timeout waiting for external IP address for Ingress to be ready. ABORTED.\n"
+        exit 1
+    fi
+}
+
+# Internal services and ports
+export GITEA_INTERNAL_HTTP_IP=gitea-http.gitea
+export GITEA_INTERNAL_SSH_IP=gitea-ssh.gitea
+export GITEA_HTTP_PORT=$(kubectl get svc/gitea-http -n gitea -o jsonpath='{.spec.ports[0].port}')
+export GITEA_SSH_PORT=$(kubectl get svc/gitea-ssh -n gitea -o jsonpath='{.spec.ports[0].port}')
+
+# If applicable, gets recommended service IP addresses
+## SSH service
+if [[ -n $(kubectl get svc/gitea-ssh -n gitea -o jsonpath='{.status.loadBalancer.ingress[0].ip}') ]]
+then
+    # Retrieves the external IP address
+    export GITEA_SSH_IP=$(kubectl get svc/gitea-ssh -n gitea -o jsonpath='{.status.loadBalancer.ingress[0].ip}') || true
+else
+    # Otherwise just uses the internal service name
+    export GITEA_SSH_IP=${GITEA_INTERNAL_SSH_IP}
+fi
+## HTTP service
+if [[ -n $(kubectl get svc/gitea-http -n gitea -o jsonpath='{.status.loadBalancer.ingress[0].ip}') ]]
+then
+    # Retrieves the external IP addresses (if it exists)
+    export GITEA_HTTP_IP=$(kubectl get svc/gitea-http -n gitea -o jsonpath='{.status.loadBalancer.ingress[0].ip}') || true
+# In case it is behind an Ingress
+elif  [[ -n $(kubectl get ingress/gitea -n gitea 2> /dev/null) ]]
+then
+    # Waits until the external IP address is available
+    echo "Waiting until the Ingress service IP address is available..."
+    wait_until_ingress_service_ip_available
+
+    # Retrieves the external IP address of the Ingress service
+    export GITEA_HTTP_IP=$(kubectl get svc/ingress-nginx-controller -n ingress-nginx -o jsonpath='{.status.loadBalancer.ingress[0].ip}') || true
+    echo "Got it: ${GITEA_HTTP_IP}"
+else
+    # Otherwise just uses the internal service name
+    export GITEA_HTTP_IP=${GITEA_INTERNAL_HTTP_IP}
+fi
+
+# Applicable URLs
+export GITEA_HTTP_HOST_DOMAIN="git.${GITEA_HTTP_IP}.nip.io"
+export GITEA_HTTP_URL="http://git.${GITEA_HTTP_IP}.nip.io"
+export GITEA_SSH_URL="git.${GITEA_SSH_IP}.nip.io"
+export GITEA_INTERNAL_HTTP_URL="http://${GITEA_INTERNAL_HTTP_IP}"
+export GITEA_INTERNAL_SSH_URL="${GITEA_INTERNAL_SSH_IP}"
+
+# Add explicit ports if required
+if [[ "${GITEA_HTTP_PORT}" != 80 ]]
+then
+    export GITEA_INTERNAL_HTTP_URL="${GITEA_INTERNAL_HTTP_URL}:${GITEA_HTTP_PORT}"
+
+    # If it is not behind an Ingress, the port will be the original one, not necessarily 80
+    if [[ -z $(kubectl get ingress/gitea -n gitea 2> /dev/null) ]]
+    then
+        export GITEA_HTTP_URL="${GITEA_HTTP_URL}:${GITEA_HTTP_PORT}"
+    fi
+fi
+
+# Add port to SSH URL if needed
+export GITEA_SSH_SERVER="${GITEA_SSH_URL}"
+export GITEA_INTERNAL_SSH_SERVER="${GITEA_INTERNAL_SSH_URL}"
+if [[ "${GITEA_SSH_PORT}" != 22 ]]
+then
+    export GITEA_SSH_URL="${GITEA_SSH_URL}:${GITEA_SSH_PORT}"
+    export GITEA_INTERNAL_SSH_URL="${GITEA_INTERNAL_SSH_URL}:${GITEA_SSH_PORT}"
+fi
+
+# Complete the SSH URLs to avoid ambiguity
+export GITEA_SSH_URL="ssh://git@${GITEA_SSH_URL}"
+export GITEA_INTERNAL_SSH_URL="ssh://git@${GITEA_INTERNAL_SSH_URL}"
diff --git a/installers/mgmt-cluster/gitea/04-fix-and-use-external-gitea-urls.sh b/installers/mgmt-cluster/gitea/04-fix-and-use-external-gitea-urls.sh
new file mode 100755 (executable)
index 0000000..cb4ba81
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e
+
+export HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+source "${HERE}/library/functions.sh"
+source "${HERE}/library/trap.sh"
+
+# If there are no external IP addresses, exits
+# [[ -z $(kubectl get svc/gitea-http -n gitea -o jsonpath='{.status.loadBalancer.ingress[0].ip}') ]] && exit 0
+
+# Update the server base URLs, based on the exposed IP address(es)
+m "Updating base URLs in the server to use external IP address(es)..."
+helm upgrade --install gitea gitea-charts/gitea \
+    --version=7.0.4 \
+    --namespace=gitea \
+    --values "${HERE}/${GITEA_CHART_VALUES_FILE}" \
+    --set=gitea.admin.username="${GITEA_ADMINISTRATOR_USERNAME}" \
+    --set=gitea.admin.password="${GITEA_ADMINISTRATOR_PASSWORD}" \
+    --set=gitea.config.server.DOMAIN="${GITEA_SSH_SERVER}" \
+    --set=gitea.config.server.ROOT_URL="${GITEA_HTTP_URL}" \
+    --set=ingress.hosts[0].host="${GITEA_HTTP_HOST_DOMAIN}" \
+    --wait
diff --git a/installers/mgmt-cluster/gitea/05-export-connection-info.sh b/installers/mgmt-cluster/gitea/05-export-connection-info.sh
new file mode 100755 (executable)
index 0000000..8e903c0
--- /dev/null
@@ -0,0 +1,81 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e
+
+export HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+source "${HERE}/library/functions.sh"
+source "${HERE}/library/trap.sh"
+
+# Prints URLs for HTTP access
+m "HTTP URL: ${GITEA_HTTP_URL}"
+m "SSH URL: ${GITEA_SSH_URL}"
+m "HTTP Host Domain: ${GITEA_HTTP_HOST_DOMAIN}"
+m "Internal HTTP URL: ${GITEA_INTERNAL_HTTP_URL}"
+m "Internal SSH URL: ${GITEA_INTERNAL_SSH_URL}"
+echo
+
+# Saves locally to local environment at credentials folder
+m "Saving local enviroment to credentials folder..."
+
+cat << EOF > "${CREDENTIALS_DIR}/gitea_environment.rc"
+export GITEA_HTTP_URL=${GITEA_HTTP_URL}
+export GITEA_SSH_URL=${GITEA_SSH_URL}
+export GITEA_SSH_SERVER=${GITEA_SSH_SERVER}
+export GITEA_HTTP_HOST_DOMAIN=${GITEA_HTTP_HOST_DOMAIN}
+export GITEA_INTERNAL_HTTP_URL=${GITEA_INTERNAL_HTTP_URL}
+export GITEA_INTERNAL_SSH_URL=${GITEA_INTERNAL_SSH_URL}
+export GITEA_INTERNAL_SSH_SERVER=${GITEA_INTERNAL_SSH_SERVER}
+export GITEA_INTERNAL_HTTP_IP=${GITEA_INTERNAL_HTTP_IP}
+export GITEA_INTERNAL_SSH_IP=${GITEA_INTERNAL_SSH_IP}
+export GITEA_HTTP_PORT=${GITEA_HTTP_PORT}
+export GITEA_SSH_PORT=${GITEA_SSH_PORT}
+export GITEA_ADMINISTRATOR_USERNAME=${GITEA_ADMINISTRATOR_USERNAME}
+export GITEA_ADMINISTRATOR_PASSWORD='${GITEA_ADMINISTRATOR_PASSWORD}'
+export GITEA_STD_USERNAME=${GITEA_STD_USERNAME}
+export GITEA_STD_USER_PASS='${GITEA_STD_USER_PASS}'
+EOF
+
+m "Done."
+echo
+
+# Saves into K8s cluster as a secret
+m "Saving enviroment to secret into K8s cluster..."
+
+kubectl delete secret gitea-environment -n gitea 2> /dev/null || true
+kubectl create secret generic gitea-environment -n gitea \
+    --from-literal=GITEA_HTTP_URL=${GITEA_HTTP_URL} \
+    --from-literal=GITEA_SSH_URL=${GITEA_SSH_URL} \
+    --from-literal=GITEA_HTTP_HOST_DOMAIN=${GITEA_HTTP_HOST_DOMAIN} \
+    --from-literal=GITEA_INTERNAL_HTTP_URL=${GITEA_INTERNAL_HTTP_URL} \
+    --from-literal=GITEA_INTERNAL_SSH_URL=${GITEA_INTERNAL_SSH_URL} \
+    --from-literal=GITEA_INTERNAL_SSH_SERVER=${GITEA_INTERNAL_SSH_SERVER} \
+    --from-literal=GITEA_INTERNAL_HTTP_IP=${GITEA_INTERNAL_HTTP_IP} \
+    --from-literal=GITEA_INTERNAL_SSH_IP=${GITEA_INTERNAL_SSH_IP} \
+    --from-literal=GITEA_HTTP_PORT=${GITEA_HTTP_PORT} \
+    --from-literal=GITEA_SSH_PORT=${GITEA_SSH_PORT} \
+    --from-literal=GITEA_ADMINISTRATOR_USERNAME=${GITEA_ADMINISTRATOR_USERNAME} \
+    --from-literal=GITEA_ADMINISTRATOR_PASSWORD=${GITEA_ADMINISTRATOR_PASSWORD} \
+    --from-literal=GITEA_STD_USERNAME=${GITEA_STD_USERNAME} \
+    --from-literal=GITEA_STD_USER_PASS=${GITEA_STD_USER_PASS}
+
+m "Done."
+echo
+m "Example: To retrieve Gitea's HTTP URL:"
+m "kubectl get secret gitea-environment -n gitea -o jsonpath='{.data.GITEA_HTTP_URL}' | base64 -d" ${CYAN}
+echo
diff --git a/installers/mgmt-cluster/gitea/90-provision-gitea-for-osm.sh b/installers/mgmt-cluster/gitea/90-provision-gitea-for-osm.sh
new file mode 100755 (executable)
index 0000000..f2ada07
--- /dev/null
@@ -0,0 +1,154 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e -o pipefail
+
+export HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+source "${HERE}/library/functions.sh"
+source "${HERE}/library/trap.sh"
+
+
+#####################################################################
+# Step 1: Create regular user and obtain tokens
+#####################################################################
+
+# Creates an aditional regular user
+# ---------------------------------
+m "Creating new user \"${GITEA_STD_USERNAME}\"..."
+"${HERE}/admin/create-user.sh" "${GITEA_STD_USERNAME}" "${GITEA_STD_USER_PASS}" "${GITEA_STD_USERNAME}@gitea"
+# "${HERE}/admin/create-user.sh" "${GITEA_STD_USERNAME}" "${GITEA_STD_USER_PASS}" "${GITEA_STD_USERNAME}@gitea" --admin
+
+m "New username: ${GITEA_STD_USERNAME}" "$CYAN"
+#m "New user's password: ${GITEA_STD_USER_PASS}" "$CYAN"
+
+# Creates access token for the admin
+# ----------------------------------
+export GITEA_ADMINISTRATOR_TOKEN=$( \
+    "${HERE}/admin/create-cmd-access-token.sh" "${GITEA_ADMINISTRATOR_USERNAME}" "${GITEA_ADMINISTRATOR_TOKEN_NAME}" | \
+    grep 'Access token was successfully created' | \
+    cut -d ' ' -f 6 \
+)
+m "Admin token name: ${GITEA_ADMINISTRATOR_TOKEN_NAME}"
+m "Admin token: ${GITEA_ADMINISTRATOR_TOKEN}"
+
+# Creates access token for the user
+# ---------------------------------
+export GITEA_STD_TOKEN=$( \
+    "${HERE}/admin/create-cmd-access-token.sh" "${GITEA_STD_USERNAME}" "${GITEA_STD_TOKEN_NAME}" | \
+    grep 'Access token was successfully created' | \
+    cut -d ' ' -f 6 \
+)
+m "Standard user token name: ${GITEA_STD_TOKEN_NAME}"
+m "Standard user token: ${GITEA_STD_TOKEN}"
+
+# # Alternative method, via API
+# # ---------------------------
+# export GITEA_STD_TOKEN=$( \
+#     "${HERE}/admin/create-api-access-token.sh" "${GITEA_HTTP_URL}" "${GITEA_STD_USERNAME}" "${GITEA_STD_USER_PASS}" "${GITEA_STD_TOKEN_NAME}" \
+# )
+
+# Save tokens
+# ---------------------------------
+m "Saving tokens to credentials folder..."
+
+cat << EOF > "${CREDENTIALS_DIR}/gitea_tokens.rc"
+export GITEA_ADMINISTRATOR_TOKEN_NAME=${GITEA_ADMINISTRATOR_TOKEN_NAME}
+export GITEA_ADMINISTRATOR_TOKEN=${GITEA_ADMINISTRATOR_TOKEN}
+export GITEA_STD_TOKEN_NAME=${GITEA_STD_TOKEN_NAME}
+export GITEA_STD_TOKEN=${GITEA_STD_TOKEN}
+EOF
+
+m "Done."
+
+# Saves into K8s cluster as a secret
+m "Saving tokens to secret into K8s cluster..."
+
+kubectl delete secret gitea-tokens -n gitea 2> /dev/null || true
+kubectl create secret generic gitea-tokens -n gitea \
+    --from-literal=GITEA_ADMINISTRATOR_TOKEN_NAME=${GITEA_ADMINISTRATOR_TOKEN_NAME} \
+    --from-literal=GITEA_ADMINISTRATOR_TOKEN=${GITEA_ADMINISTRATOR_TOKEN} \
+    --from-literal=GITEA_STD_TOKEN_NAME=${GITEA_STD_TOKEN_NAME} \
+    --from-literal=GITEA_STD_TOKEN=${GITEA_STD_TOKEN}
+
+m "Done."
+echo
+m "Example: To retrieve token for standard user:"
+m "kubectl get secret gitea-tokens -n gitea -o jsonpath='{.data.GITEA_STD_TOKEN}' | base64 -d" ${CYAN}
+echo
+
+
+#####################################################################
+# Step 2: Create repositories
+#####################################################################
+
+# Loads tokens
+# ---------------------------------
+# m "Reloading tokens..."
+# source "${CREDENTIALS_DIR}/gitea_tokens.rc"
+# echo
+
+# Creates `fleet-osm` and `sw-catalogs-osm` repos in the space of the standard user
+# ----------------------------------------------------
+export REPO=fleet-osm
+m "Creating ${REPO} repo..."
+"${HERE}/admin/create-user-repository.sh" "${GITEA_HTTP_URL}" "${GITEA_STD_USERNAME}" "${GITEA_STD_TOKEN}" "${REPO}" false
+m "Done."
+echo
+
+export REPO=sw-catalogs-osm
+m "Creating ${REPO} repo..."
+"${HERE}/admin/create-user-repository.sh" "${GITEA_HTTP_URL}" "${GITEA_STD_USERNAME}" "${GITEA_STD_TOKEN}" "${REPO}" false
+m "Done."
+echo
+
+# Deletes a repo in the space of the standard user
+# ------------------------------------------------------
+# export REPO=name-of-repo-to-delete
+# "${HERE}/admin/delete-user-repository.sh" "${GITEA_HTTP_URL}" "${GITEA_STD_USERNAME}" "${GITEA_STD_TOKEN}" "${REPO}"
+
+
+
+# #####################################################################
+# # Other provisioning actions, for reference:
+# #####################################################################
+
+# # Creates new organization
+# # ------------------------
+# # "${HERE}/admin/create-org.sh" "${GITEA_HTTP_URL}" "${GITEA_ADMINISTRATOR_USERNAME}" "${GITEA_ADMINISTRATOR_TOKEN}" "${GITEA_EXTRA_ORGANIZATION}" private
+
+# # Creates a new repo in the organization
+# # --------------------------------------
+# # export REPO=test-repo
+# # "${HERE}/admin/create-org-repository.sh" "${GITEA_HTTP_URL}" "${GITEA_STD_USERNAME}" "${GITEA_ADMINISTRATOR_TOKEN}" "${GITEA_EXTRA_ORGANIZATION}" "${REPO}" true
+
+# # Deletes the repo in the space of the standard user
+# # --------------------------------------------------
+# # "${HERE}/admin/delete-org-repository.sh" "${GITEA_HTTP_URL}" "${GITEA_STD_USERNAME}" "${GITEA_ADMINISTRATOR_TOKEN}" "${GITEA_EXTRA_ORGANIZATION}" "${REPO}"
+
+# # Deletes organization
+# # --------------------
+# # "${HERE}/admin/delete-org.sh" "${GITEA_HTTP_URL}" "${GITEA_ADMINISTRATOR_USERNAME}" "${GITEA_ADMINISTRATOR_TOKEN}" "${GITEA_EXTRA_ORGANIZATION}"
+
+# # Creates a new repo in the space of the standard user
+# # ----------------------------------------------------
+# # export REPO=test-user-repo
+# # "${HERE}/admin/create-user-repository.sh" "${GITEA_HTTP_URL}" "${GITEA_STD_USERNAME}" "${GITEA_STD_TOKEN}" "${REPO}" false
+
+# # Deletes the new repo in the space of the standard user
+# # ------------------------------------------------------
+# # "${HERE}/admin/delete-user-repository.sh" "${GITEA_HTTP_URL}" "${GITEA_STD_USERNAME}" "${GITEA_STD_TOKEN}" "${REPO}"
diff --git a/installers/mgmt-cluster/gitea/91-provision-local-git-user.sh b/installers/mgmt-cluster/gitea/91-provision-local-git-user.sh
new file mode 100755 (executable)
index 0000000..27f9ffe
--- /dev/null
@@ -0,0 +1,74 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e -o pipefail
+
+export HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+source "${HERE}/library/functions.sh"
+source "${HERE}/library/trap.sh"
+
+
+# Create new user
+export USER_NAME=$(git config --get user.name)
+export USER_MAIL=$(git config --get user.email)
+export USER_PASS="${GITEA_STD_USER_PASS}" # Same as standard user
+"${HERE}/admin/create-user.sh" \
+  "${USER_NAME}" \
+  "${USER_PASS}" \
+  "${USER_MAIL}"
+
+# Create token
+export USER_TOKEN_NAME=user_token_name
+export USER_TOKEN=$( \
+    "${HERE}/admin/create-cmd-access-token.sh" \
+        "${USER_NAME}" \
+        "${USER_TOKEN_NAME}" | \
+    grep 'Access token was successfully created' | \
+    cut -d ' ' -f 6 \
+)
+
+# Add user's public SSH key
+"${HERE}/admin/create-user-ssh-key.sh" \
+  "${GITEA_HTTP_URL}" \
+  "${USER_NAME}" \
+  "${USER_TOKEN}" \
+  "$(<${HOME}/.ssh/id_rsa.pub)" \
+  "local_user_ssh_key" \
+  false
+
+# Add user as collaborator of the relevant repos
+## Fleet repo
+"${HERE}/admin/add-collaborator-to-user-repo.sh" \
+  "${GITEA_HTTP_URL}" \
+  "${GITEA_STD_USERNAME}" \
+  "${GITEA_STD_TOKEN}" \
+  "fleet-osm" \
+  "${USER_NAME}" \
+  "write"
+
+## SW-Catalogs repo
+"${HERE}/admin/add-collaborator-to-user-repo.sh" \
+  "${GITEA_HTTP_URL}" \
+  "${GITEA_STD_USERNAME}" \
+  "${GITEA_STD_TOKEN}" \
+  "sw-catalogs-osm" \
+  "${USER_NAME}" \
+  "write"
+
+# Prevents non-interactive recognition of the SSH host
+ssh-keyscan -p "${GITEA_SSH_PORT}" "${GITEA_SSH_SERVER}" >> ~/.ssh/known_hosts
diff --git a/installers/mgmt-cluster/gitea/ALL-IN-ONE-Gitea-install.sh b/installers/mgmt-cluster/gitea/ALL-IN-ONE-Gitea-install.sh
new file mode 100755 (executable)
index 0000000..b6bbffd
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e -o pipefail
+
+export HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+source "${HERE}/library/functions.sh"
+source "${HERE}/library/trap.sh"
+
+
+############################################
+# Main script starts here
+############################################
+
+source "${HERE}/00-custom-config.rc"
+source "${HERE}/01-base-config.rc"
+"${HERE}/02-deploy-gitea.sh"
+source "${HERE}/03-get-gitea-connection-info.rc"
+"${HERE}/04-fix-and-use-external-gitea-urls.sh"
+"${HERE}/05-export-connection-info.sh"
+
+# Uncomment to provision for use from OSM
+# "${HERE}/90-provision-gitea-for-osm.sh"
diff --git a/installers/mgmt-cluster/gitea/README.md b/installers/mgmt-cluster/gitea/README.md
new file mode 100644 (file)
index 0000000..4af5128
--- /dev/null
@@ -0,0 +1,115 @@
+<!--
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+implied.
+See the License for the specific language governing permissions and
+limitations under the License
+-->
+# Gitea
+
+[TOC]
+
+[Gitea](https://gitea.io/en-us/) hosts private git repositories.
+
+[Reference page on GitHub](https://github.com/go-gitea/gitea).
+
+## Installation
+
+### TL;DR
+
+First, select the desired K8s `kubeconfig` and default context where Gitea will be installed.
+
+Then, for an installation with default configuration run:
+
+```bash
+./ALL-IN-ONE-Gitea-install.sh
+```
+
+For use then you could do:
+
+```bash
+source "${CREDENTIALS_DIR}/gitea_environment.rc"
+```
+
+For Gitea provisioning for OSM usage (tokens, users and repos), you can just use this script:
+
+```bash
+source "${CREDENTIALS_DIR}/gitea_environment.rc"
+source "${CREDENTIALS_DIR}/gitea_tokens.rc"
+./90-provision-gitea-for-osm.sh"
+```
+
+Alternatively, in case you wanted to set up Gitea programmatically for other use cases without using the UI (which is always a possibility), including the setup of Gitea tokens, the creation of users, the creation of repos, etc., you should have a look at all the operations captured in `90-provision-gitea-for-osm.sh` (including the commented examples) and create a custom provisioning script that fits your needs.
+
+For your convenience (although it would not be strictly required), you may also enable the local Git user to interact with the significant repos:
+
+```bash
+source "${CREDENTIALS_DIR}/gitea_environment.rc"
+source "${CREDENTIALS_DIR}/gitea_tokens.rc"
+./91-provision-local-git-user.sh"
+```
+
+### Overview of the installation process
+
+This folder provides helper scripts to complete a full standalone installation of Gitea on Kubernetes using the current `kubeconfig` and the current context.
+
+**WARNING:** In case your current `kubeconfig` context does not point to your desired K8s cluster target, simply select it **before** applying any of the scripts:
+
+```bash
+export KUBECONFIG=/absolute/path/to/kubeconfig.yaml
+kubectl config use-context put-your-desired-context-here
+# Alternatively, you may use `kubectx` for interactive selection of your default context
+```
+
+Once selected the K8s target, the following environment files and scripts should be applied in the order indicated by their prefix number, noting that `*.rc` files should be sourced and `*.sh` files should be executed. Here is their utility:
+
+- `00-custom-config.rc`: (optional) Used to override selectively some environment variables that may condition the behaviour of the installer scripts. By default, just generates random values for Gitea passwords, but it may edited for further customizations if needed. If not sourced, the rest of scripts will work normally with sensible defaults (note that default passwords will be applied).
+- `01-base-config.rc`: Sets sensible defaults to environment variables for Gitea configuration in case they had not been set explicitly before, either via `00-custom-config.rc` or by other means.
+- `02-deploy-gitea.sh`: Makes a Gitea installation based on the config variables set in previous steps.
+  - It is deployed to the `gitea` namespace using the [published Helm chart](https://docs.gitea.io/en-us/install-on-kubernetes/).
+  - Default base Git URLs:
+    - The internal base git HTTP URL is `http://gitea-http.gitea:8080`.
+    - The internal base git SSH URL is `ssh://gitea-ssh.gitea:22`.
+    - If applicable, the exposed (external) base git HTTP URL takes the shape `http://git.${GITEA_HTTP_IP}.nip.io:${GITEA_HTTP_PORT}`, where `${GITEA_HTTP_PORT}` is 8080 by default.
+    - If applicable, the exposed (external) base git SSH URL takes the shape `ssh://git.${GITEA_SSH_IP}.nip.io:${GITEA_SSH_PORT}`, where `${GITEA_HTTP_PORT}` is 22 by default.
+- `03-get-gitea-connection-info.rc`
+- `04-fix-and-use-external-gitea-urls.sh`: (optional) Fixes the base domain of Gitea to point to a `nip.io` URL pointing to the **external** load balancer service IP.
+- `05-export-connection-info.sh`: Determines full connection URLs and exports data to `${CREDENTIALS_DIR}` folder and into a K8s secret.
+- (optional) `90-provision-gitea-for-osm.sh`: Run post-provisioning tasks in Gitea with scripted operations to support its use from OSM:
+  - Create access tokens for the admin and the new standard user.
+  - Create new standard user `${GITEA_STD_USERNAME}`.
+  - Export tokens to local file in `${CREDENTIALS_DIR}` folder and into a K8s secr
+  - Creates default repos for OSM: `fleet-osm` and `sw-catalogs-osm`.
+- (optional) `91-provision-local-git-user.sh`: Enable the local Git user to interact with the significant repos supporting its use from OSM:
+  - Add the local Git user to Gitea as a profile.
+  - Upload the public SSH key (to allow SSH operations).
+  - Add the user as _collaborator_ to both repos.
+
+For testing you can use `gitea` in the Gitea main pod via
+
+```bash
+./admin/shell.sh
+su git
+gitea <your_command_goes_here>
+```
+
+## Administration
+
+Admin operations on Gitea can be handled in two different ways:
+
+1. Using the `./admin/gitea.sh` script, which wraps the Gitea CLI in the main pod, or
+2. Using `./admin/api.sh` to call the [Swagger endpoints](https://try.gitea.io/api/swagger).
+   - For these operations you may need the tokens saved at `${CREDENTIALS_DIR}/gitea_tokens.rc` as environment variables ready to be sourced.
+
+In both cases, you will need to source the environment variables saved at `${CREDENTIALS_DIR}/gitea_environment.rc`.
+
+Some common helper scripts for common admin operations are also available in the `./admin/` folder.
+
+You can find many useful (commented) examples of admin operations in `90-provision-gitea-for-osm.sh`.
diff --git a/installers/mgmt-cluster/gitea/admin/add-collaborator-to-user-repo.sh b/installers/mgmt-cluster/gitea/admin/add-collaborator-to-user-repo.sh
new file mode 100755 (executable)
index 0000000..352685f
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e
+
+HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+. "$HERE/../library/functions.sh"
+. "$HERE/../library/trap.sh"
+
+SERVER_URL=$1
+USERNAME=$2
+TOKEN=$3
+REPO=$4
+COLLABORATOR=$5
+PERMISSION=${6:-"write"}
+
+"$HERE/api.sh" "${SERVER_URL}" "${TOKEN}" \
+       PUT \
+       "repos/${USERNAME}/${REPO}/collaborators/${COLLABORATOR}" \
+    "{\"permission\": \"${PERMISSION}\"}"
diff --git a/installers/mgmt-cluster/gitea/admin/api.sh b/installers/mgmt-cluster/gitea/admin/api.sh
new file mode 100755 (executable)
index 0000000..de5b345
--- /dev/null
@@ -0,0 +1,49 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e
+
+# Wrapper function for raw calls to Gitea API
+
+HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+. "$HERE/../library/functions.sh"
+. "$HERE/../library/trap.sh"
+
+SERVER_URL=$1
+TOKEN=$2
+VERB=$3
+URI=$4
+DATA=$5
+
+if [ -z "$DATA" ]; then
+    kubectl exec statefulset/gitea --container=gitea --namespace=gitea --quiet -- \
+    curl --silent --fail \
+        "${SERVER_URL}/api/v1/${URI}" \
+        --request "${VERB}" \
+        --header "Authorization: token ${TOKEN}" \
+        --header 'Accept: application/json'
+else
+    kubectl exec statefulset/gitea --container=gitea --namespace=gitea --quiet -- \
+    curl --silent --fail \
+        --request "$VERB" \
+        "${SERVER_URL}/api/v1/${URI}" \
+        --header "Authorization: token ${TOKEN}" \
+        --header 'Accept: application/json' \
+        --header 'Content-Type: application/json' \
+        --data "${DATA}"
+fi
diff --git a/installers/mgmt-cluster/gitea/admin/create-api-access-token.sh b/installers/mgmt-cluster/gitea/admin/create-api-access-token.sh
new file mode 100755 (executable)
index 0000000..f7679e6
--- /dev/null
@@ -0,0 +1,52 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e
+
+HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+. "$HERE/../library/functions.sh"
+. "$HERE/../library/trap.sh"
+
+SERVER_URL=$1
+USERNAME=$2
+PASSWORD=$3
+TOKEN_NAME=$4
+
+# Unfortunately this inconsistently spits out logs stdout, making it challenging to parse
+# "$HERE/gitea" admin user generate-access-token --username "$USERNAME" --raw | tail -1 > "$HERE/tokens/$USERNAME"
+
+# See: https://docs.gitea.io/en-us/api-usage/#generating-and-listing-api-tokens
+
+# Delete old "${TOKEN_NAME}" token (if existed)
+kubectl exec statefulset/gitea --container=gitea --namespace=gitea --quiet -- \
+curl --silent --fail \
+       "${SERVER_URL}/api/v1/users/$USERNAME/tokens/${TOKEN_NAME}" \
+       --user "$USERNAME:$PASSWORD" \
+       --request DELETE \
+       --header 'Accept: application/json' || true > /dev/null
+
+# Create new "${TOKEN_NAME}" token
+# (this is our only chance to retrieve the sha1)
+kubectl exec statefulset/gitea --container=gitea --namespace=gitea --quiet -- \
+curl --silent --fail \
+       "${SERVER_URL}/api/v1/users/$USERNAME/tokens" \
+       --user "$USERNAME:$PASSWORD" \
+       --request POST \
+       --header 'Accept: application/json' \
+       --header 'Content-Type: application/json' \
+       --data "{\"name\": \"${TOKEN_NAME}\"}" | jq --raw-output .sha1
diff --git a/installers/mgmt-cluster/gitea/admin/create-cmd-access-token.sh b/installers/mgmt-cluster/gitea/admin/create-cmd-access-token.sh
new file mode 100755 (executable)
index 0000000..222b899
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e
+
+HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+. "$HERE/../library/functions.sh"
+. "$HERE/../library/trap.sh"
+
+USERNAME=$1
+TOKEN_NAME=$2
+
+# gitea admin user generate-access-token --username myname --token-name mytoken
+"$HERE/gitea.sh" admin user generate-access-token \
+       --username "${USERNAME}" \
+       --token-name \'"${TOKEN_NAME}"\' \
+       "${@:4}"
diff --git a/installers/mgmt-cluster/gitea/admin/create-org-repository.sh b/installers/mgmt-cluster/gitea/admin/create-org-repository.sh
new file mode 100755 (executable)
index 0000000..6cb591c
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e
+
+HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+. "$HERE/../library/functions.sh"
+. "$HERE/../library/trap.sh"
+
+USERNAME=$1
+PASSWORD=$2
+ORG=$3
+
+SERVER_URL=$1
+USERNAME=$2
+TOKEN=$3
+ORG=$4
+REPO=$5
+PRIVATE=${6:-true}
+
+"$HERE/api.sh" "${SERVER_URL}" "${TOKEN}" \
+       POST \
+       "orgs/${ORG}/repos" \
+       "{\"name\": \"${REPO}\", \"default_branch\": \"main\", \"private\": ${PRIVATE}}"
diff --git a/installers/mgmt-cluster/gitea/admin/create-org.sh b/installers/mgmt-cluster/gitea/admin/create-org.sh
new file mode 100755 (executable)
index 0000000..02dfe7c
--- /dev/null
@@ -0,0 +1,43 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e
+
+HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+. "$HERE/../library/functions.sh"
+. "$HERE/../library/trap.sh"
+
+SERVER_URL=$1
+USERNAME=$2
+TOKEN=$3
+ORG=$4
+VISIBILITY=${5:-public}
+
+# Root organizations
+# ------------------
+"$HERE/api.sh" "${SERVER_URL}" "${TOKEN}" \
+       POST \
+       orgs \
+       "{\"username\": \"${ORG}\", \"visibility\": \"${VISIBILITY}\"}"
+
+# Organizations on user path
+# --------------------------
+# "$HERE/api.sh" "${SERVER_URL}" "${TOKEN}" \
+#      POST \
+#      admin/users/${USERNAME}/orgs \
+#      "{\"username\": \"${ORG}\"}"
diff --git a/installers/mgmt-cluster/gitea/admin/create-user-repository.sh b/installers/mgmt-cluster/gitea/admin/create-user-repository.sh
new file mode 100755 (executable)
index 0000000..686c1a9
--- /dev/null
@@ -0,0 +1,34 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e
+
+HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+. "$HERE/../library/functions.sh"
+. "$HERE/../library/trap.sh"
+
+SERVER_URL=$1
+USERNAME=$2
+TOKEN=$3
+REPO=$4
+PRIVATE=${5:-true}
+
+"$HERE/api.sh" "${SERVER_URL}" "${TOKEN}" \
+       POST \
+       user/repos \
+       "{\"name\": \"${REPO}\", \"default_branch\": \"main\", \"private\": ${PRIVATE}}"
diff --git a/installers/mgmt-cluster/gitea/admin/create-user-ssh-key.sh b/installers/mgmt-cluster/gitea/admin/create-user-ssh-key.sh
new file mode 100755 (executable)
index 0000000..7dc0661
--- /dev/null
@@ -0,0 +1,43 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e
+
+HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+. "$HERE/../library/functions.sh"
+. "$HERE/../library/trap.sh"
+
+# PARAMETERS:
+# ==========
+# 1) Server URL
+# 2) Username
+# 3) Token
+# 4) SSH key content
+# 5) SSH key name in Gitea's user profile
+# 6) Read only?
+SERVER_URL=$1
+USERNAME=$2
+TOKEN=$3
+SSH_KEY="${4}"
+KEY_NAME=$5
+READ_ONLY=${6:-false}
+
+"$HERE/api.sh" "${SERVER_URL}" "${TOKEN}" \
+       POST \
+       user/keys \
+       "{\"key\": \"${SSH_KEY}\", \"read_only\": ${READ_ONLY}, \"title\": \"${KEY_NAME}\"}"
diff --git a/installers/mgmt-cluster/gitea/admin/create-user.sh b/installers/mgmt-cluster/gitea/admin/create-user.sh
new file mode 100755 (executable)
index 0000000..6812427
--- /dev/null
@@ -0,0 +1,34 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e
+
+HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+source "${HERE}/../library/functions.sh"
+source "${HERE}/../library/trap.sh"
+
+USERNAME=$1
+PASSWORD="${2}"
+EMAIL=$3
+
+"$HERE/gitea.sh" admin user create \
+       --username "$USERNAME" \
+       --password \'"${PASSWORD}"\' \
+       --email "$EMAIL" \
+       --must-change-password=false \
+       "${@:4}"
diff --git a/installers/mgmt-cluster/gitea/admin/delete-org-repository.sh b/installers/mgmt-cluster/gitea/admin/delete-org-repository.sh
new file mode 100755 (executable)
index 0000000..ba3b796
--- /dev/null
@@ -0,0 +1,37 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e
+
+HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+. "$HERE/../library/functions.sh"
+. "$HERE/../library/trap.sh"
+
+USERNAME=$1
+PASSWORD=$2
+ORG=$3
+
+SERVER_URL=$1
+USERNAME=$2
+TOKEN=$3
+ORG=$4
+REPO=$5
+
+"$HERE/api.sh" "${SERVER_URL}" "${TOKEN}" \
+       DELETE \
+       repos/${ORG}/${REPO}
diff --git a/installers/mgmt-cluster/gitea/admin/delete-org.sh b/installers/mgmt-cluster/gitea/admin/delete-org.sh
new file mode 100755 (executable)
index 0000000..66a2eba
--- /dev/null
@@ -0,0 +1,34 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e
+
+HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+. "$HERE/../library/functions.sh"
+. "$HERE/../library/trap.sh"
+
+SERVER_URL=$1
+USERNAME=$2
+TOKEN=$3
+ORG=$4
+
+# Root organizations
+# ------------------
+"$HERE/api.sh" "${SERVER_URL}" "${TOKEN}" \
+       DELETE \
+       orgs/${ORG}
diff --git a/installers/mgmt-cluster/gitea/admin/delete-user-repository.sh b/installers/mgmt-cluster/gitea/admin/delete-user-repository.sh
new file mode 100755 (executable)
index 0000000..2c403a2
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e
+
+HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+. "$HERE/../library/functions.sh"
+. "$HERE/../library/trap.sh"
+
+SERVER_URL=$1
+USERNAME=$2
+TOKEN=$3
+REPO=$4
+
+"$HERE/api.sh" "${SERVER_URL}" "${TOKEN}" \
+       DELETE \
+       repos/${USERNAME}/${REPO}
diff --git a/installers/mgmt-cluster/gitea/admin/gitea.sh b/installers/mgmt-cluster/gitea/admin/gitea.sh
new file mode 100755 (executable)
index 0000000..697f303
--- /dev/null
@@ -0,0 +1,26 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e
+
+HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+. "$HERE/../library/functions.sh"
+
+# Note: we cannot run "gitea" as root
+kubectl exec statefulset/gitea --container=gitea --namespace=gitea --quiet -- \
+su git -c "gitea --quiet $*"
diff --git a/installers/mgmt-cluster/gitea/admin/shell.sh b/installers/mgmt-cluster/gitea/admin/shell.sh
new file mode 100755 (executable)
index 0000000..004b5fd
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e
+
+HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+. "$HERE/../library/functions.sh"
+
+kubectl exec statefulset/gitea --container=gitea --namespace=gitea --tty --stdin --quiet -- /bin/bash
diff --git a/installers/mgmt-cluster/gitea/library/functions.sh b/installers/mgmt-cluster/gitea/library/functions.sh
new file mode 100755 (executable)
index 0000000..638a1d2
--- /dev/null
@@ -0,0 +1,91 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+BLUE='\033[0;34m'
+CYAN='\033[0;36m'
+RESET='\033[0m'
+
+# Colored messages (blue is the default)
+# Examples:
+#   m "hello world"
+#   m "hello world" "$GREEN"
+function m() {
+  local COLOR=${2:-$BLUE}
+  echo -e "$COLOR$1$RESET"
+}
+
+function copy_function() {
+  local ORIG_FUNC=$(declare -f $1)
+  local NEWNAME_FUNC="$2${ORIG_FUNC#$1}"
+  eval "$NEWNAME_FUNC"
+}
+
+function replace_text() {
+  local FILE=$1
+  local START=$2
+  local END=$3
+  local NEW=$4
+  local T=$(mktemp)
+  head -n $((START-1)) "$FILE" > "$T"
+  echo "$NEW" >> "$T"
+  tail -n +$((END+1)) "$FILE" >> "$T"
+  mv "$T" "$FILE"
+}
+
+function insert_text() {
+  local FILE=$1
+  local START=$2
+  local NEW=$3
+  local T=$(mktemp)
+  head -n $((START-1)) "$FILE" > "$T"
+  echo "$NEW" >> "$T"
+  tail -n +$START "$FILE" >> "$T"
+  mv "$T" "$FILE"
+}
+
+function remove_text() {
+  local FILE=$1
+  local START=$2
+  local END=$3
+  local T=$(mktemp)
+  head -n $((START-1)) "$FILE" > "$T"
+  tail -n +$((END+1)) "$FILE" >> "$T"
+  mv "$T" "$FILE"
+}
+
+function envsubst_cp() {
+  local FROM_FILE=$1
+  local TO_FILE=$2
+  mkdir --parents "$(dirname "$TO_FILE")"
+  cat "$FROM_FILE" | envsubst > "$TO_FILE"
+}
+
+function envsubst_dir() {
+  local FROM_DIR=$1
+  local TO_DIR=$2
+  rm --recursive --force "$TO_DIR"
+  mkdir --parents "$TO_DIR"
+  pushd "$FROM_DIR" > /dev/null
+  local F
+  find . -type f | while read F; do
+    envsubst_cp "$F" "$TO_DIR/$F"
+  done
+  popd > /dev/null
+}
diff --git a/installers/mgmt-cluster/gitea/library/trap.sh b/installers/mgmt-cluster/gitea/library/trap.sh
new file mode 100755 (executable)
index 0000000..2a1156d
--- /dev/null
@@ -0,0 +1,48 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+function goodbye() {
+  local DURATION=$(date --date=@$(( "$(date +%s)" - "$TRAP_START_TIME" )) --utc +%T)
+  local CODE=$1
+  cd "$TRAP_DIR"
+  if [ "$CODE" == 0 ]; then
+    m "$(realpath --relative-to="$HERE" "$0") succeeded! $DURATION" "$GREEN"
+  elif [ "$CODE" == abort ]; then
+    m "Aborted $(realpath --relative-to="$HERE" "$0")! $DURATION" "$RED"
+  else
+    m "Oh no! $(realpath --relative-to="$HERE" "$0") failed! $DURATION" "$RED"
+  fi
+}
+
+function trap_EXIT() {
+  local ERR=$?
+  goodbye "$ERR"
+  exit "$ERR"
+}
+
+function trap_INT() {
+  goodbye abort
+  trap - EXIT
+  exit 1
+}
+
+TRAP_DIR=$PWD
+TRAP_START_TIME=$(date +%s)
+
+trap trap_INT INT
+
+trap trap_EXIT EXIT
diff --git a/installers/mgmt-cluster/gitea/values-all.yaml b/installers/mgmt-cluster/gitea/values-all.yaml
new file mode 100644 (file)
index 0000000..82be6fc
--- /dev/null
@@ -0,0 +1,505 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+# Default values for gitea.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+## @section Global
+#
+## @param global.imageRegistry global image registry override
+## @param global.imagePullSecrets global image pull secrets override; can be extended by `imagePullSecrets`
+## @param global.storageClass global storage class override
+## @param global.hostAliases global hostAliases which will be added to the pod's hosts files
+global:
+  imageRegistry: ""
+  ## E.g.
+  ## imagePullSecrets:
+  ##   - myRegistryKeySecretName
+  ##
+  imagePullSecrets: []
+  storageClass: ""
+  hostAliases: []
+  # - ip: 192.168.137.2
+  #   hostnames:
+  #   - example.com
+
+## @param replicaCount number of replicas for the statefulset
+replicaCount: 1
+
+## @param clusterDomain cluster domain
+clusterDomain: cluster.local
+
+## @section Image
+## @param image.registry image registry, e.g. gcr.io,docker.io
+## @param image.repository Image to start for this pod
+## @param image.tag Visit: [Image tag](https://hub.docker.com/r/gitea/gitea/tags?page=1&ordering=last_updated). Defaults to `appVersion` within Chart.yaml.
+## @param image.pullPolicy Image pull policy
+## @param image.rootless Wether or not to pull the rootless version of Gitea, only works on Gitea 1.14.x or higher
+image:
+  registry: ""
+  repository: gitea/gitea
+  # Overrides the image tag whose default is the chart appVersion.
+  tag: ""
+  pullPolicy: Always
+  rootless: false # only possible when running 1.14 or later
+
+## @param imagePullSecrets Secret to use for pulling the image
+imagePullSecrets: []
+
+## @section Security
+# Security context is only usable with rootless image due to image design
+## @param podSecurityContext.fsGroup Set the shared file system group for all containers in the pod.
+podSecurityContext:
+  fsGroup: 1000
+
+## @param containerSecurityContext Security context
+containerSecurityContext: {}
+#   allowPrivilegeEscalation: false
+#   capabilities:
+#     drop:
+#       - ALL
+#   # Add the SYS_CHROOT capability for root and rootless images if you intend to
+#   # run pods on nodes that use the container runtime cri-o. Otherwise, you will
+#   # get an error message from the SSH server that it is not possible to read from
+#   # the repository.
+#   # https://gitea.com/gitea/helm-chart/issues/161
+#     add:
+#       - SYS_CHROOT
+#   privileged: false
+#   readOnlyRootFilesystem: true
+#   runAsGroup: 1000
+#   runAsNonRoot: true
+#   runAsUser: 1000
+
+## @deprecated The securityContext variable has been split two:
+## - containerSecurityContext
+## - podSecurityContext.
+## @param securityContext Run init and Gitea containers as a specific securityContext
+securityContext: {}
+
+## @section Service
+service:
+  ## @param service.http.type Kubernetes service type for web traffic
+  ## @param service.http.port Port number for web traffic
+  ## @param service.http.clusterIP ClusterIP setting for http autosetup for statefulset is None
+  ## @param service.http.loadBalancerIP LoadBalancer IP setting
+  ## @param service.http.nodePort NodePort for http service
+  ## @param service.http.externalTrafficPolicy If `service.http.type` is `NodePort` or `LoadBalancer`, set this to `Local` to enable source IP preservation
+  ## @param service.http.externalIPs External IPs for service
+  ## @param service.http.ipFamilyPolicy HTTP service dual-stack policy
+  ## @param service.http.ipFamilies HTTP service dual-stack familiy selection,for dual-stack parameters see official kubernetes [dual-stack concept documentation](https://kubernetes.io/docs/concepts/services-networking/dual-stack/).
+  ## @param service.http.loadBalancerSourceRanges Source range filter for http loadbalancer
+  ## @param service.http.annotations HTTP service annotations
+  http:
+    type: ClusterIP
+    port: 3000
+    clusterIP: None
+    loadBalancerIP:
+    nodePort:
+    externalTrafficPolicy:
+    externalIPs:
+    ipFamilyPolicy:
+    ipFamilies:
+    loadBalancerSourceRanges: []
+    annotations: {}
+  ## @param service.ssh.type Kubernetes service type for ssh traffic
+  ## @param service.ssh.port Port number for ssh traffic
+  ## @param service.ssh.clusterIP ClusterIP setting for ssh autosetup for statefulset is None
+  ## @param service.ssh.loadBalancerIP LoadBalancer IP setting
+  ## @param service.ssh.nodePort NodePort for ssh service
+  ## @param service.ssh.externalTrafficPolicy If `service.ssh.type` is `NodePort` or `LoadBalancer`, set this to `Local` to enable source IP preservation
+  ## @param service.ssh.externalIPs External IPs for service
+  ## @param service.ssh.ipFamilyPolicy SSH service dual-stack policy
+  ## @param service.ssh.ipFamilies SSH service dual-stack familiy selection,for dual-stack parameters see official kubernetes [dual-stack concept documentation](https://kubernetes.io/docs/concepts/services-networking/dual-stack/).
+  ## @param service.ssh.hostPort HostPort for ssh service
+  ## @param service.ssh.loadBalancerSourceRanges Source range filter for ssh loadbalancer
+  ## @param service.ssh.annotations SSH service annotations
+  ssh:
+    type: ClusterIP
+    port: 22
+    clusterIP: None
+    loadBalancerIP:
+    nodePort:
+    externalTrafficPolicy:
+    externalIPs:
+    ipFamilyPolicy:
+    ipFamilies:
+    hostPort:
+    loadBalancerSourceRanges: []
+    annotations: {}
+
+
+## @section Ingress
+## @param ingress.enabled Enable ingress
+## @param ingress.className Ingress class name
+## @param ingress.annotations Ingress annotations
+## @param ingress.hosts[0].host Default Ingress host
+## @param ingress.hosts[0].paths[0].path Default Ingress path
+## @param ingress.hosts[0].paths[0].pathType Ingress path type
+## @param ingress.tls Ingress tls settings
+## @extra ingress.apiVersion Specify APIVersion of ingress object. Mostly would only be used for argocd.
+ingress:
+  enabled: false
+  # className: nginx
+  className:
+  annotations: {}
+    # kubernetes.io/ingress.class: nginx
+    # kubernetes.io/tls-acme: "true"
+  hosts:
+    - host: git.example.com
+      paths:
+        - path: /
+          pathType: Prefix
+  tls: []
+  #  - secretName: chart-example-tls
+  #    hosts:
+  #      - git.example.com
+  # Mostly for argocd or any other CI that uses `helm template | kubectl apply` or similar
+  # If helm doesn't correctly detect your ingress API version you can set it here.
+  # apiVersion: networking.k8s.io/v1
+
+## @section StatefulSet
+#
+## @param resources Kubernetes resources
+resources: {}
+  # We usually recommend not to specify default resources and to leave this as a conscious
+  # choice for the user. This also increases chances charts run on environments with little
+  # resources, such as Minikube. If you do want to specify resources, uncomment the following
+  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+  # limits:
+  #   cpu: 100m
+  #   memory: 128Mi
+  # requests:
+  #   cpu: 100m
+  #   memory: 128Mi
+
+## Use an alternate scheduler, e.g. "stork".
+## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/
+##
+## @param schedulerName Use an alternate scheduler, e.g. "stork"
+schedulerName: ""
+
+## @param nodeSelector NodeSelector for the statefulset
+nodeSelector: {}
+
+## @param tolerations Tolerations for the statefulset
+tolerations: []
+
+## @param affinity Affinity for the statefulset
+affinity: {}
+
+## @param dnsConfig dnsConfig for the statefulset
+dnsConfig: {}
+
+## @param statefulset.env  Additional environment variables to pass to containers
+## @param statefulset.terminationGracePeriodSeconds How long to wait until forcefully kill the pod
+## @param statefulset.labels Labels for the statefulset
+## @param statefulset.annotations Annotations for the Gitea StatefulSet to be created
+statefulset:
+  env: []
+    # - name: VARIABLE
+    #   value: my-value
+  terminationGracePeriodSeconds: 60
+  labels: {}
+  annotations: {}
+
+## @section Persistence
+#
+## @param persistence.enabled Enable persistent storage
+## @param persistence.existingClaim Use an existing claim to store repository information
+## @param persistence.size Size for persistence to store repo information
+## @param persistence.accessModes AccessMode for persistence
+## @param persistence.labels Labels for the persistence volume claim to be created
+## @param persistence.annotations Annotations for the persistence volume claim to be created
+## @param persistence.storageClass Name of the storage class to use
+## @param persistence.subPath Subdirectory of the volume to mount at
+persistence:
+  enabled: true
+  existingClaim:
+  size: 10Gi
+  accessModes:
+    - ReadWriteOnce
+  labels: {}
+  annotations: {}
+  storageClass:
+  subPath:
+
+## @param extraVolumes Additional volumes to mount to the Gitea statefulset
+extraVolumes: []
+# - name: postgres-ssl-vol
+#   secret:
+#     secretName: gitea-postgres-ssl
+
+## @param extraContainerVolumeMounts Mounts that are only mapped into the Gitea runtime/main container, to e.g. override custom templates.
+extraContainerVolumeMounts: []
+
+## @param extraInitVolumeMounts Mounts that are only mapped into the init-containers. Can be used for additional preconfiguration.
+extraInitVolumeMounts: []
+
+## @deprecated The extraVolumeMounts variable has been split two:
+## - extraContainerVolumeMounts
+## - extraInitVolumeMounts
+## As an example, can be used to mount a client cert when connecting to an external Postgres server.
+## @param extraVolumeMounts **DEPRECATED** Additional volume mounts for init containers and the Gitea main container
+extraVolumeMounts: []
+# - name: postgres-ssl-vol
+#   readOnly: true
+#   mountPath: "/pg-ssl"
+
+## @section Init
+## @param initPreScript Bash shell script copied verbatim to the start of the init-container.
+initPreScript: ""
+#
+# initPreScript: |
+#   mkdir -p /data/git/.postgresql
+#   cp /pg-ssl/* /data/git/.postgresql/
+#   chown -R git:git /data/git/.postgresql/
+#   chmod 400 /data/git/.postgresql/postgresql.key
+
+# Configure commit/action signing prerequisites
+## @section Signing
+#
+## @param signing.enabled Enable commit/action signing
+## @param signing.gpgHome GPG home directory
+## @param signing.privateKey Inline private gpg key for signed Gitea actions
+## @param signing.existingSecret Use an existing secret to store the value of `signing.privateKey`
+signing:
+  enabled: false
+  gpgHome: /data/git/.gnupg
+  privateKey: ""
+  # privateKey: |-
+  #   -----BEGIN PGP PRIVATE KEY BLOCK-----
+  #   ...
+  #   -----END PGP PRIVATE KEY BLOCK-----
+  existingSecret: ""
+
+## @section Gitea
+#
+gitea:
+  ## @param gitea.admin.username Username for the Gitea admin user
+  ## @param gitea.admin.existingSecret Use an existing secret to store admin user credentials
+  ## @param gitea.admin.password Password for the Gitea admin user
+  ## @param gitea.admin.email Email for the Gitea admin user
+  admin:
+    #existingSecret: gitea-admin-secret
+    existingSecret:
+    username: gitea_admin
+    password: r8sA8CPHD9!bt6d
+    email: "gitea@local.domain"
+
+  ## @param gitea.metrics.enabled Enable Gitea metrics
+  ## @param gitea.metrics.serviceMonitor.enabled Enable Gitea metrics service monitor
+  metrics:
+    enabled: false
+    serviceMonitor:
+      enabled: false
+      #  additionalLabels:
+      #    prometheus-release: prom1
+
+  ## @param gitea.ldap LDAP configuration
+  ldap: []
+    # - name: "LDAP 1"
+    #  existingSecret:
+    #  securityProtocol:
+    #  host:
+    #  port:
+    #  userSearchBase:
+    #  userFilter:
+    #  adminFilter:
+    #  emailAttribute:
+    #  bindDn:
+    #  bindPassword:
+    #  usernameAttribute:
+    #  publicSSHKeyAttribute:
+
+  # Either specify inline `key` and `secret` or refer to them via `existingSecret`
+  ## @param gitea.oauth OAuth configuration
+  oauth: []
+    # - name: 'OAuth 1'
+    #   provider:
+    #   key:
+    #   secret:
+    #   existingSecret:
+    #   autoDiscoverUrl:
+    #   useCustomUrls:
+    #   customAuthUrl:
+    #   customTokenUrl:
+    #   customProfileUrl:
+    #   customEmailUrl:
+
+  ## @param gitea.config  Configuration for the Gitea server,ref: [config-cheat-sheet](https://docs.gitea.io/en-us/config-cheat-sheet/)
+  config: {}
+  #  APP_NAME: "Gitea: Git with a cup of tea"
+  #  RUN_MODE: dev
+  #
+  #  server:
+  #    SSH_PORT: 22
+  #
+  #  security:
+  #    PASSWORD_COMPLEXITY: spec
+
+  ## @param gitea.additionalConfigSources Additional configuration from secret or configmap
+  additionalConfigSources: []
+  #   - secret:
+  #       secretName: gitea-app-ini-oauth
+  #   - configMap:
+  #       name: gitea-app-ini-plaintext
+
+  ## @param gitea.additionalConfigFromEnvs Additional configuration sources from environment variables
+  additionalConfigFromEnvs: []
+
+  ## @param gitea.podAnnotations Annotations for the Gitea pod
+  podAnnotations: {}
+
+  ## @section LivenessProbe
+  #
+  ## @param gitea.livenessProbe.enabled Enable liveness probe
+  ## @param gitea.livenessProbe.tcpSocket.port Port to probe for liveness
+  ## @param gitea.livenessProbe.initialDelaySeconds Initial delay before liveness probe is initiated
+  ## @param gitea.livenessProbe.timeoutSeconds Timeout for liveness probe
+  ## @param gitea.livenessProbe.periodSeconds Period for liveness probe
+  ## @param gitea.livenessProbe.successThreshold Success threshold for liveness probe
+  ## @param gitea.livenessProbe.failureThreshold Failure threshold for liveness probe
+  # Modify the liveness probe for your needs or completely disable it by commenting out.
+  livenessProbe:
+    enabled: true
+    tcpSocket:
+      port: http
+    initialDelaySeconds: 200
+    timeoutSeconds: 1
+    periodSeconds: 10
+    successThreshold: 1
+    failureThreshold: 10
+
+  ## @section ReadinessProbe
+  #
+  ## @param gitea.readinessProbe.enabled Enable readiness probe
+  ## @param gitea.readinessProbe.tcpSocket.port Port to probe for readiness
+  ## @param gitea.readinessProbe.initialDelaySeconds Initial delay before readiness probe is initiated
+  ## @param gitea.readinessProbe.timeoutSeconds Timeout for readiness probe
+  ## @param gitea.readinessProbe.periodSeconds Period for readiness probe
+  ## @param gitea.readinessProbe.successThreshold Success threshold for readiness probe
+  ## @param gitea.readinessProbe.failureThreshold Failure threshold for readiness probe
+  # Modify the readiness probe for your needs or completely disable it by commenting out.
+  readinessProbe:
+    enabled: true
+    tcpSocket:
+      port: http
+    initialDelaySeconds: 5
+    timeoutSeconds: 1
+    periodSeconds: 10
+    successThreshold: 1
+    failureThreshold: 3
+
+  # # Uncomment the startup probe to enable and modify it for your needs.
+  ## @section StartupProbe
+  #
+  ## @param gitea.startupProbe.enabled Enable startup probe
+  ## @param gitea.startupProbe.tcpSocket.port Port to probe for startup
+  ## @param gitea.startupProbe.initialDelaySeconds Initial delay before startup probe is initiated
+  ## @param gitea.startupProbe.timeoutSeconds Timeout for startup probe
+  ## @param gitea.startupProbe.periodSeconds Period for startup probe
+  ## @param gitea.startupProbe.successThreshold Success threshold for startup probe
+  ## @param gitea.startupProbe.failureThreshold Failure threshold for startup probe
+  startupProbe:
+    enabled: false
+    tcpSocket:
+      port: http
+    initialDelaySeconds: 60
+    timeoutSeconds: 1
+    periodSeconds: 10
+    successThreshold: 1
+    failureThreshold: 10
+
+## @section Memcached
+#
+## @param memcached.enabled Memcached is loaded as a dependency from [Bitnami](https://github.com/bitnami/charts/tree/master/bitnami/memcached) if enabled in the values. Complete Configuration can be taken from their website.
+## @param memcached.service.port Port for Memcached
+memcached:
+  enabled: true
+  service:
+    port: 11211
+
+## @section PostgreSQL
+#
+## @param postgresql.enabled Enable PostgreSQL
+## @param postgresql.global.postgresql.postgresqlDatabase PostgreSQL database (overrides postgresqlDatabase)
+## @param postgresql.global.postgresql.postgresqlUsername PostgreSQL username (overrides postgresqlUsername)
+## @param postgresql.global.postgresql.postgresqlPassword PostgreSQL admin password (overrides postgresqlPassword)
+## @param postgresql.global.postgresql.servicePort PostgreSQL port (overrides service.port)
+## @param postgresql.persistence.size PVC Storage Request for PostgreSQL volume
+postgresql:
+  enabled: true
+  global:
+    postgresql:
+      postgresqlDatabase: gitea
+      postgresqlUsername: gitea
+      postgresqlPassword: gitea
+      servicePort: 5432
+  persistence:
+    size: 10Gi
+
+## @section MySQL
+#
+## @param mysql.enabled Enable MySQL
+## @param mysql.root.password Password for the root user. Ignored if existing secret is provided
+## @param mysql.db.user Username of new user to create.
+## @param mysql.db.password Password for the new user.Ignored if existing secret is provided
+## @param mysql.db.name Name for new database to create.
+## @param mysql.service.port Port to connect to MySQL service
+## @param mysql.persistence.size PVC Storage Request for MySQL volume
+mysql:
+  enabled: false
+  root:
+    password: gitea
+  db:
+    user: gitea
+    password: gitea
+    name: gitea
+  service:
+    port: 3306
+  persistence:
+    size: 10Gi
+
+## @section MariaDB
+#
+## @param mariadb.enabled Enable MariaDB
+## @param mariadb.auth.database Name of the database to create.
+## @param mariadb.auth.username Username of the new user to create.
+## @param mariadb.auth.password Password for the new user. Ignored if existing secret is provided
+## @param mariadb.auth.rootPassword Password for the root user.
+## @param mariadb.primary.service.port Port to connect to MariaDB service
+## @param mariadb.primary.persistence.size Persistence size for MariaDB
+mariadb:
+  enabled: false
+  auth:
+    database: gitea
+    username: gitea
+    password: gitea
+    rootPassword: gitea
+  primary:
+    service:
+      port: 3306
+    persistence:
+      size: 10Gi
+
+# By default, removed or moved settings that still remain in a user defined values.yaml will cause Helm to fail running the install/update.
+# Set it to false to skip this basic validation check.
+## @section Advanced
+## @param checkDeprecation Set it to false to skip this basic validation check.
+checkDeprecation: true
+
diff --git a/installers/mgmt-cluster/gitea/values-standalone-ingress-ssh2222.yaml b/installers/mgmt-cluster/gitea/values-standalone-ingress-ssh2222.yaml
new file mode 100644 (file)
index 0000000..bf1296a
--- /dev/null
@@ -0,0 +1,509 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+# Default values for gitea.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+## @section Global
+#
+## @param global.imageRegistry global image registry override
+## @param global.imagePullSecrets global image pull secrets override; can be extended by `imagePullSecrets`
+## @param global.storageClass global storage class override
+## @param global.hostAliases global hostAliases which will be added to the pod's hosts files
+global:
+  imageRegistry: ""
+  ## E.g.
+  ## imagePullSecrets:
+  ##   - myRegistryKeySecretName
+  ##
+  imagePullSecrets: []
+  storageClass: ""
+  hostAliases: []
+  # - ip: 192.168.137.2
+  #   hostnames:
+  #   - example.com
+
+## @param replicaCount number of replicas for the statefulset
+replicaCount: 1
+
+## @param clusterDomain cluster domain
+clusterDomain: cluster.local
+
+## @section Image
+## @param image.registry image registry, e.g. gcr.io,docker.io
+## @param image.repository Image to start for this pod
+## @param image.tag Visit: [Image tag](https://hub.docker.com/r/gitea/gitea/tags?page=1&ordering=last_updated). Defaults to `appVersion` within Chart.yaml.
+## @param image.pullPolicy Image pull policy
+## @param image.rootless Wether or not to pull the rootless version of Gitea, only works on Gitea 1.14.x or higher
+image:
+  registry: ""
+  repository: gitea/gitea
+  # Overrides the image tag whose default is the chart appVersion.
+  tag: ""
+  pullPolicy: Always
+  rootless: false # only possible when running 1.14 or later
+
+## @param imagePullSecrets Secret to use for pulling the image
+imagePullSecrets: []
+
+## @section Security
+# Security context is only usable with rootless image due to image design
+## @param podSecurityContext.fsGroup Set the shared file system group for all containers in the pod.
+podSecurityContext:
+  fsGroup: 1000
+
+## @param containerSecurityContext Security context
+containerSecurityContext: {}
+#   allowPrivilegeEscalation: false
+#   capabilities:
+#     drop:
+#       - ALL
+#   # Add the SYS_CHROOT capability for root and rootless images if you intend to
+#   # run pods on nodes that use the container runtime cri-o. Otherwise, you will
+#   # get an error message from the SSH server that it is not possible to read from
+#   # the repository.
+#   # https://gitea.com/gitea/helm-chart/issues/161
+#     add:
+#       - SYS_CHROOT
+#   privileged: false
+#   readOnlyRootFilesystem: true
+#   runAsGroup: 1000
+#   runAsNonRoot: true
+#   runAsUser: 1000
+
+## @deprecated The securityContext variable has been split two:
+## - containerSecurityContext
+## - podSecurityContext.
+## @param securityContext Run init and Gitea containers as a specific securityContext
+securityContext: {}
+
+## @section Service
+service:
+  ## @param service.http.type Kubernetes service type for web traffic
+  ## @param service.http.port Port number for web traffic
+  ## @param service.http.clusterIP ClusterIP setting for http autosetup for statefulset is None
+  ## @param service.http.loadBalancerIP LoadBalancer IP setting
+  ## @param service.http.nodePort NodePort for http service
+  ## @param service.http.externalTrafficPolicy If `service.http.type` is `NodePort` or `LoadBalancer`, set this to `Local` to enable source IP preservation
+  ## @param service.http.externalIPs External IPs for service
+  ## @param service.http.ipFamilyPolicy HTTP service dual-stack policy
+  ## @param service.http.ipFamilies HTTP service dual-stack familiy selection,for dual-stack parameters see official kubernetes [dual-stack concept documentation](https://kubernetes.io/docs/concepts/services-networking/dual-stack/).
+  ## @param service.http.loadBalancerSourceRanges Source range filter for http loadbalancer
+  ## @param service.http.annotations HTTP service annotations
+  http:
+    type: ClusterIP
+    # port: 3000
+    port: 8080
+    clusterIP: None
+    loadBalancerIP:
+    nodePort:
+    externalTrafficPolicy:
+    externalIPs:
+    ipFamilyPolicy:
+    ipFamilies:
+    loadBalancerSourceRanges: []
+    annotations: {}
+  ## @param service.ssh.type Kubernetes service type for ssh traffic
+  ## @param service.ssh.port Port number for ssh traffic
+  ## @param service.ssh.clusterIP ClusterIP setting for ssh autosetup for statefulset is None
+  ## @param service.ssh.loadBalancerIP LoadBalancer IP setting
+  ## @param service.ssh.nodePort NodePort for ssh service
+  ## @param service.ssh.externalTrafficPolicy If `service.ssh.type` is `NodePort` or `LoadBalancer`, set this to `Local` to enable source IP preservation
+  ## @param service.ssh.externalIPs External IPs for service
+  ## @param service.ssh.ipFamilyPolicy SSH service dual-stack policy
+  ## @param service.ssh.ipFamilies SSH service dual-stack familiy selection,for dual-stack parameters see official kubernetes [dual-stack concept documentation](https://kubernetes.io/docs/concepts/services-networking/dual-stack/).
+  ## @param service.ssh.hostPort HostPort for ssh service
+  ## @param service.ssh.loadBalancerSourceRanges Source range filter for ssh loadbalancer
+  ## @param service.ssh.annotations SSH service annotations
+  ssh:
+    type: LoadBalancer
+    port: 2222
+    clusterIP: None
+    loadBalancerIP:
+    nodePort:
+    externalTrafficPolicy:
+    externalIPs:
+    ipFamilyPolicy:
+    ipFamilies:
+    hostPort:
+    loadBalancerSourceRanges: []
+    annotations: {}
+
+
+## @section Ingress
+## @param ingress.enabled Enable ingress
+## @param ingress.className Ingress class name
+## @param ingress.annotations Ingress annotations
+## @param ingress.hosts[0].host Default Ingress host
+## @param ingress.hosts[0].paths[0].path Default Ingress path
+## @param ingress.hosts[0].paths[0].pathType Ingress path type
+## @param ingress.tls Ingress tls settings
+## @extra ingress.apiVersion Specify APIVersion of ingress object. Mostly would only be used for argocd.
+ingress:
+  enabled: true
+  className: nginx
+  # className:
+  annotations: {}
+    # kubernetes.io/ingress.class: nginx
+    # kubernetes.io/tls-acme: "true"
+  hosts:
+    - host: git.miejemplo.com
+      paths:
+        - path: /
+          pathType: Prefix
+  tls: []
+  #  - secretName: chart-example-tls
+  #    hosts:
+  #      - git.example.com
+  # Mostly for argocd or any other CI that uses `helm template | kubectl apply` or similar
+  # If helm doesn't correctly detect your ingress API version you can set it here.
+  # apiVersion: networking.k8s.io/v1
+
+## @section StatefulSet
+#
+## @param resources Kubernetes resources
+resources: {}
+  # We usually recommend not to specify default resources and to leave this as a conscious
+  # choice for the user. This also increases chances charts run on environments with little
+  # resources, such as Minikube. If you do want to specify resources, uncomment the following
+  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+  # limits:
+  #   cpu: 100m
+  #   memory: 128Mi
+  # requests:
+  #   cpu: 100m
+  #   memory: 128Mi
+
+## Use an alternate scheduler, e.g. "stork".
+## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/
+##
+## @param schedulerName Use an alternate scheduler, e.g. "stork"
+schedulerName: ""
+
+## @param nodeSelector NodeSelector for the statefulset
+nodeSelector: {}
+
+## @param tolerations Tolerations for the statefulset
+tolerations: []
+
+## @param affinity Affinity for the statefulset
+affinity: {}
+
+## @param dnsConfig dnsConfig for the statefulset
+dnsConfig: {}
+
+## @param statefulset.env  Additional environment variables to pass to containers
+## @param statefulset.terminationGracePeriodSeconds How long to wait until forcefully kill the pod
+## @param statefulset.labels Labels for the statefulset
+## @param statefulset.annotations Annotations for the Gitea StatefulSet to be created
+statefulset:
+  env: []
+    # - name: VARIABLE
+    #   value: my-value
+  terminationGracePeriodSeconds: 60
+  labels: {}
+  annotations: {}
+
+## @section Persistence
+#
+## @param persistence.enabled Enable persistent storage
+## @param persistence.existingClaim Use an existing claim to store repository information
+## @param persistence.size Size for persistence to store repo information
+## @param persistence.accessModes AccessMode for persistence
+## @param persistence.labels Labels for the persistence volume claim to be created
+## @param persistence.annotations Annotations for the persistence volume claim to be created
+## @param persistence.storageClass Name of the storage class to use
+## @param persistence.subPath Subdirectory of the volume to mount at
+persistence:
+  enabled: true
+  existingClaim:
+  size: 10Gi
+  accessModes:
+    - ReadWriteOnce
+  labels: {}
+  annotations: {}
+  storageClass:
+  subPath:
+
+## @param extraVolumes Additional volumes to mount to the Gitea statefulset
+extraVolumes: []
+# - name: postgres-ssl-vol
+#   secret:
+#     secretName: gitea-postgres-ssl
+
+## @param extraContainerVolumeMounts Mounts that are only mapped into the Gitea runtime/main container, to e.g. override custom templates.
+extraContainerVolumeMounts: []
+
+## @param extraInitVolumeMounts Mounts that are only mapped into the init-containers. Can be used for additional preconfiguration.
+extraInitVolumeMounts: []
+
+## @deprecated The extraVolumeMounts variable has been split two:
+## - extraContainerVolumeMounts
+## - extraInitVolumeMounts
+## As an example, can be used to mount a client cert when connecting to an external Postgres server.
+## @param extraVolumeMounts **DEPRECATED** Additional volume mounts for init containers and the Gitea main container
+extraVolumeMounts: []
+# - name: postgres-ssl-vol
+#   readOnly: true
+#   mountPath: "/pg-ssl"
+
+## @section Init
+## @param initPreScript Bash shell script copied verbatim to the start of the init-container.
+initPreScript: ""
+#
+# initPreScript: |
+#   mkdir -p /data/git/.postgresql
+#   cp /pg-ssl/* /data/git/.postgresql/
+#   chown -R git:git /data/git/.postgresql/
+#   chmod 400 /data/git/.postgresql/postgresql.key
+
+# Configure commit/action signing prerequisites
+## @section Signing
+#
+## @param signing.enabled Enable commit/action signing
+## @param signing.gpgHome GPG home directory
+## @param signing.privateKey Inline private gpg key for signed Gitea actions
+## @param signing.existingSecret Use an existing secret to store the value of `signing.privateKey`
+signing:
+  enabled: false
+  gpgHome: /data/git/.gnupg
+  privateKey: ""
+  # privateKey: |-
+  #   -----BEGIN PGP PRIVATE KEY BLOCK-----
+  #   ...
+  #   -----END PGP PRIVATE KEY BLOCK-----
+  existingSecret: ""
+
+## @section Gitea
+#
+gitea:
+  ## @param gitea.admin.username Username for the Gitea admin user
+  ## @param gitea.admin.existingSecret Use an existing secret to store admin user credentials
+  ## @param gitea.admin.password Password for the Gitea admin user
+  ## @param gitea.admin.email Email for the Gitea admin user
+  admin:
+    #existingSecret: gitea-admin-secret
+    existingSecret:
+    username: gitea_admin
+    password: r8sA8CPHD9!bt6d
+    email: "gitea@local.domain"
+
+  ## @param gitea.metrics.enabled Enable Gitea metrics
+  ## @param gitea.metrics.serviceMonitor.enabled Enable Gitea metrics service monitor
+  metrics:
+    enabled: false
+    serviceMonitor:
+      enabled: false
+      #  additionalLabels:
+      #    prometheus-release: prom1
+
+  ## @param gitea.ldap LDAP configuration
+  ldap: []
+    # - name: "LDAP 1"
+    #  existingSecret:
+    #  securityProtocol:
+    #  host:
+    #  port:
+    #  userSearchBase:
+    #  userFilter:
+    #  adminFilter:
+    #  emailAttribute:
+    #  bindDn:
+    #  bindPassword:
+    #  usernameAttribute:
+    #  publicSSHKeyAttribute:
+
+  # Either specify inline `key` and `secret` or refer to them via `existingSecret`
+  ## @param gitea.oauth OAuth configuration
+  oauth: []
+    # - name: 'OAuth 1'
+    #   provider:
+    #   key:
+    #   secret:
+    #   existingSecret:
+    #   autoDiscoverUrl:
+    #   useCustomUrls:
+    #   customAuthUrl:
+    #   customTokenUrl:
+    #   customProfileUrl:
+    #   customEmailUrl:
+
+  ## @param gitea.config  Configuration for the Gitea server,ref: [config-cheat-sheet](https://docs.gitea.io/en-us/config-cheat-sheet/)
+  config:
+  #  APP_NAME: "Gitea: Git with a cup of tea"
+
+  #  RUN_MODE: dev
+  #
+    server:
+      DOMAIN: git.miejemplo.com
+      ROOT_URL: http://git.miejemplo.com
+    #  SSH_PORT: 22
+  #
+  #  security:
+  #    PASSWORD_COMPLEXITY: spec
+
+  ## @param gitea.additionalConfigSources Additional configuration from secret or configmap
+  additionalConfigSources: []
+  #   - secret:
+  #       secretName: gitea-app-ini-oauth
+  #   - configMap:
+  #       name: gitea-app-ini-plaintext
+
+  ## @param gitea.additionalConfigFromEnvs Additional configuration sources from environment variables
+  additionalConfigFromEnvs: []
+
+  ## @param gitea.podAnnotations Annotations for the Gitea pod
+  podAnnotations: {}
+
+  ## @section LivenessProbe
+  #
+  ## @param gitea.livenessProbe.enabled Enable liveness probe
+  ## @param gitea.livenessProbe.tcpSocket.port Port to probe for liveness
+  ## @param gitea.livenessProbe.initialDelaySeconds Initial delay before liveness probe is initiated
+  ## @param gitea.livenessProbe.timeoutSeconds Timeout for liveness probe
+  ## @param gitea.livenessProbe.periodSeconds Period for liveness probe
+  ## @param gitea.livenessProbe.successThreshold Success threshold for liveness probe
+  ## @param gitea.livenessProbe.failureThreshold Failure threshold for liveness probe
+  # Modify the liveness probe for your needs or completely disable it by commenting out.
+  livenessProbe:
+    enabled: true
+    tcpSocket:
+      port: http
+    initialDelaySeconds: 200
+    timeoutSeconds: 1
+    periodSeconds: 10
+    successThreshold: 1
+    failureThreshold: 10
+
+  ## @section ReadinessProbe
+  #
+  ## @param gitea.readinessProbe.enabled Enable readiness probe
+  ## @param gitea.readinessProbe.tcpSocket.port Port to probe for readiness
+  ## @param gitea.readinessProbe.initialDelaySeconds Initial delay before readiness probe is initiated
+  ## @param gitea.readinessProbe.timeoutSeconds Timeout for readiness probe
+  ## @param gitea.readinessProbe.periodSeconds Period for readiness probe
+  ## @param gitea.readinessProbe.successThreshold Success threshold for readiness probe
+  ## @param gitea.readinessProbe.failureThreshold Failure threshold for readiness probe
+  # Modify the readiness probe for your needs or completely disable it by commenting out.
+  readinessProbe:
+    enabled: true
+    tcpSocket:
+      port: http
+    initialDelaySeconds: 5
+    timeoutSeconds: 1
+    periodSeconds: 10
+    successThreshold: 1
+    failureThreshold: 3
+
+  # # Uncomment the startup probe to enable and modify it for your needs.
+  ## @section StartupProbe
+  #
+  ## @param gitea.startupProbe.enabled Enable startup probe
+  ## @param gitea.startupProbe.tcpSocket.port Port to probe for startup
+  ## @param gitea.startupProbe.initialDelaySeconds Initial delay before startup probe is initiated
+  ## @param gitea.startupProbe.timeoutSeconds Timeout for startup probe
+  ## @param gitea.startupProbe.periodSeconds Period for startup probe
+  ## @param gitea.startupProbe.successThreshold Success threshold for startup probe
+  ## @param gitea.startupProbe.failureThreshold Failure threshold for startup probe
+  startupProbe:
+    enabled: false
+    tcpSocket:
+      port: http
+    initialDelaySeconds: 60
+    timeoutSeconds: 1
+    periodSeconds: 10
+    successThreshold: 1
+    failureThreshold: 10
+
+## @section Memcached
+#
+## @param memcached.enabled Memcached is loaded as a dependency from [Bitnami](https://github.com/bitnami/charts/tree/master/bitnami/memcached) if enabled in the values. Complete Configuration can be taken from their website.
+## @param memcached.service.port Port for Memcached
+memcached:
+  enabled: true
+  service:
+    port: 11211
+
+## @section PostgreSQL
+#
+## @param postgresql.enabled Enable PostgreSQL
+## @param postgresql.global.postgresql.postgresqlDatabase PostgreSQL database (overrides postgresqlDatabase)
+## @param postgresql.global.postgresql.postgresqlUsername PostgreSQL username (overrides postgresqlUsername)
+## @param postgresql.global.postgresql.postgresqlPassword PostgreSQL admin password (overrides postgresqlPassword)
+## @param postgresql.global.postgresql.servicePort PostgreSQL port (overrides service.port)
+## @param postgresql.persistence.size PVC Storage Request for PostgreSQL volume
+postgresql:
+  enabled: true
+  global:
+    postgresql:
+      postgresqlDatabase: gitea
+      postgresqlUsername: gitea
+      postgresqlPassword: gitea
+      servicePort: 5432
+  persistence:
+    size: 10Gi
+
+## @section MySQL
+#
+## @param mysql.enabled Enable MySQL
+## @param mysql.root.password Password for the root user. Ignored if existing secret is provided
+## @param mysql.db.user Username of new user to create.
+## @param mysql.db.password Password for the new user.Ignored if existing secret is provided
+## @param mysql.db.name Name for new database to create.
+## @param mysql.service.port Port to connect to MySQL service
+## @param mysql.persistence.size PVC Storage Request for MySQL volume
+mysql:
+  enabled: false
+  root:
+    password: gitea
+  db:
+    user: gitea
+    password: gitea
+    name: gitea
+  service:
+    port: 3306
+  persistence:
+    size: 10Gi
+
+## @section MariaDB
+#
+## @param mariadb.enabled Enable MariaDB
+## @param mariadb.auth.database Name of the database to create.
+## @param mariadb.auth.username Username of the new user to create.
+## @param mariadb.auth.password Password for the new user. Ignored if existing secret is provided
+## @param mariadb.auth.rootPassword Password for the root user.
+## @param mariadb.primary.service.port Port to connect to MariaDB service
+## @param mariadb.primary.persistence.size Persistence size for MariaDB
+mariadb:
+  enabled: false
+  auth:
+    database: gitea
+    username: gitea
+    password: gitea
+    rootPassword: gitea
+  primary:
+    service:
+      port: 3306
+    persistence:
+      size: 10Gi
+
+# By default, removed or moved settings that still remain in a user defined values.yaml will cause Helm to fail running the install/update.
+# Set it to false to skip this basic validation check.
+## @section Advanced
+## @param checkDeprecation Set it to false to skip this basic validation check.
+checkDeprecation: true
+
diff --git a/installers/mgmt-cluster/gitea/values-standalone-ingress.yaml b/installers/mgmt-cluster/gitea/values-standalone-ingress.yaml
new file mode 100644 (file)
index 0000000..4c4bb31
--- /dev/null
@@ -0,0 +1,509 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+# Default values for gitea.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+## @section Global
+#
+## @param global.imageRegistry global image registry override
+## @param global.imagePullSecrets global image pull secrets override; can be extended by `imagePullSecrets`
+## @param global.storageClass global storage class override
+## @param global.hostAliases global hostAliases which will be added to the pod's hosts files
+global:
+  imageRegistry: ""
+  ## E.g.
+  ## imagePullSecrets:
+  ##   - myRegistryKeySecretName
+  ##
+  imagePullSecrets: []
+  storageClass: ""
+  hostAliases: []
+  # - ip: 192.168.137.2
+  #   hostnames:
+  #   - example.com
+
+## @param replicaCount number of replicas for the statefulset
+replicaCount: 1
+
+## @param clusterDomain cluster domain
+clusterDomain: cluster.local
+
+## @section Image
+## @param image.registry image registry, e.g. gcr.io,docker.io
+## @param image.repository Image to start for this pod
+## @param image.tag Visit: [Image tag](https://hub.docker.com/r/gitea/gitea/tags?page=1&ordering=last_updated). Defaults to `appVersion` within Chart.yaml.
+## @param image.pullPolicy Image pull policy
+## @param image.rootless Wether or not to pull the rootless version of Gitea, only works on Gitea 1.14.x or higher
+image:
+  registry: ""
+  repository: gitea/gitea
+  # Overrides the image tag whose default is the chart appVersion.
+  tag: ""
+  pullPolicy: Always
+  rootless: false # only possible when running 1.14 or later
+
+## @param imagePullSecrets Secret to use for pulling the image
+imagePullSecrets: []
+
+## @section Security
+# Security context is only usable with rootless image due to image design
+## @param podSecurityContext.fsGroup Set the shared file system group for all containers in the pod.
+podSecurityContext:
+  fsGroup: 1000
+
+## @param containerSecurityContext Security context
+containerSecurityContext: {}
+#   allowPrivilegeEscalation: false
+#   capabilities:
+#     drop:
+#       - ALL
+#   # Add the SYS_CHROOT capability for root and rootless images if you intend to
+#   # run pods on nodes that use the container runtime cri-o. Otherwise, you will
+#   # get an error message from the SSH server that it is not possible to read from
+#   # the repository.
+#   # https://gitea.com/gitea/helm-chart/issues/161
+#     add:
+#       - SYS_CHROOT
+#   privileged: false
+#   readOnlyRootFilesystem: true
+#   runAsGroup: 1000
+#   runAsNonRoot: true
+#   runAsUser: 1000
+
+## @deprecated The securityContext variable has been split two:
+## - containerSecurityContext
+## - podSecurityContext.
+## @param securityContext Run init and Gitea containers as a specific securityContext
+securityContext: {}
+
+## @section Service
+service:
+  ## @param service.http.type Kubernetes service type for web traffic
+  ## @param service.http.port Port number for web traffic
+  ## @param service.http.clusterIP ClusterIP setting for http autosetup for statefulset is None
+  ## @param service.http.loadBalancerIP LoadBalancer IP setting
+  ## @param service.http.nodePort NodePort for http service
+  ## @param service.http.externalTrafficPolicy If `service.http.type` is `NodePort` or `LoadBalancer`, set this to `Local` to enable source IP preservation
+  ## @param service.http.externalIPs External IPs for service
+  ## @param service.http.ipFamilyPolicy HTTP service dual-stack policy
+  ## @param service.http.ipFamilies HTTP service dual-stack familiy selection,for dual-stack parameters see official kubernetes [dual-stack concept documentation](https://kubernetes.io/docs/concepts/services-networking/dual-stack/).
+  ## @param service.http.loadBalancerSourceRanges Source range filter for http loadbalancer
+  ## @param service.http.annotations HTTP service annotations
+  http:
+    type: ClusterIP
+    # port: 3000
+    port: 8080
+    clusterIP: None
+    loadBalancerIP:
+    nodePort:
+    externalTrafficPolicy:
+    externalIPs:
+    ipFamilyPolicy:
+    ipFamilies:
+    loadBalancerSourceRanges: []
+    annotations: {}
+  ## @param service.ssh.type Kubernetes service type for ssh traffic
+  ## @param service.ssh.port Port number for ssh traffic
+  ## @param service.ssh.clusterIP ClusterIP setting for ssh autosetup for statefulset is None
+  ## @param service.ssh.loadBalancerIP LoadBalancer IP setting
+  ## @param service.ssh.nodePort NodePort for ssh service
+  ## @param service.ssh.externalTrafficPolicy If `service.ssh.type` is `NodePort` or `LoadBalancer`, set this to `Local` to enable source IP preservation
+  ## @param service.ssh.externalIPs External IPs for service
+  ## @param service.ssh.ipFamilyPolicy SSH service dual-stack policy
+  ## @param service.ssh.ipFamilies SSH service dual-stack familiy selection,for dual-stack parameters see official kubernetes [dual-stack concept documentation](https://kubernetes.io/docs/concepts/services-networking/dual-stack/).
+  ## @param service.ssh.hostPort HostPort for ssh service
+  ## @param service.ssh.loadBalancerSourceRanges Source range filter for ssh loadbalancer
+  ## @param service.ssh.annotations SSH service annotations
+  ssh:
+    type: LoadBalancer
+    port: 22
+    clusterIP: None
+    loadBalancerIP:
+    nodePort:
+    externalTrafficPolicy:
+    externalIPs:
+    ipFamilyPolicy:
+    ipFamilies:
+    hostPort:
+    loadBalancerSourceRanges: []
+    annotations: {}
+
+
+## @section Ingress
+## @param ingress.enabled Enable ingress
+## @param ingress.className Ingress class name
+## @param ingress.annotations Ingress annotations
+## @param ingress.hosts[0].host Default Ingress host
+## @param ingress.hosts[0].paths[0].path Default Ingress path
+## @param ingress.hosts[0].paths[0].pathType Ingress path type
+## @param ingress.tls Ingress tls settings
+## @extra ingress.apiVersion Specify APIVersion of ingress object. Mostly would only be used for argocd.
+ingress:
+  enabled: true
+  className: nginx
+  # className:
+  annotations: {}
+    # kubernetes.io/ingress.class: nginx
+    # kubernetes.io/tls-acme: "true"
+  hosts:
+    - host: git.miejemplo.com
+      paths:
+        - path: /
+          pathType: Prefix
+  tls: []
+  #  - secretName: chart-example-tls
+  #    hosts:
+  #      - git.example.com
+  # Mostly for argocd or any other CI that uses `helm template | kubectl apply` or similar
+  # If helm doesn't correctly detect your ingress API version you can set it here.
+  # apiVersion: networking.k8s.io/v1
+
+## @section StatefulSet
+#
+## @param resources Kubernetes resources
+resources: {}
+  # We usually recommend not to specify default resources and to leave this as a conscious
+  # choice for the user. This also increases chances charts run on environments with little
+  # resources, such as Minikube. If you do want to specify resources, uncomment the following
+  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+  # limits:
+  #   cpu: 100m
+  #   memory: 128Mi
+  # requests:
+  #   cpu: 100m
+  #   memory: 128Mi
+
+## Use an alternate scheduler, e.g. "stork".
+## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/
+##
+## @param schedulerName Use an alternate scheduler, e.g. "stork"
+schedulerName: ""
+
+## @param nodeSelector NodeSelector for the statefulset
+nodeSelector: {}
+
+## @param tolerations Tolerations for the statefulset
+tolerations: []
+
+## @param affinity Affinity for the statefulset
+affinity: {}
+
+## @param dnsConfig dnsConfig for the statefulset
+dnsConfig: {}
+
+## @param statefulset.env  Additional environment variables to pass to containers
+## @param statefulset.terminationGracePeriodSeconds How long to wait until forcefully kill the pod
+## @param statefulset.labels Labels for the statefulset
+## @param statefulset.annotations Annotations for the Gitea StatefulSet to be created
+statefulset:
+  env: []
+    # - name: VARIABLE
+    #   value: my-value
+  terminationGracePeriodSeconds: 60
+  labels: {}
+  annotations: {}
+
+## @section Persistence
+#
+## @param persistence.enabled Enable persistent storage
+## @param persistence.existingClaim Use an existing claim to store repository information
+## @param persistence.size Size for persistence to store repo information
+## @param persistence.accessModes AccessMode for persistence
+## @param persistence.labels Labels for the persistence volume claim to be created
+## @param persistence.annotations Annotations for the persistence volume claim to be created
+## @param persistence.storageClass Name of the storage class to use
+## @param persistence.subPath Subdirectory of the volume to mount at
+persistence:
+  enabled: true
+  existingClaim:
+  size: 10Gi
+  accessModes:
+    - ReadWriteOnce
+  labels: {}
+  annotations: {}
+  storageClass:
+  subPath:
+
+## @param extraVolumes Additional volumes to mount to the Gitea statefulset
+extraVolumes: []
+# - name: postgres-ssl-vol
+#   secret:
+#     secretName: gitea-postgres-ssl
+
+## @param extraContainerVolumeMounts Mounts that are only mapped into the Gitea runtime/main container, to e.g. override custom templates.
+extraContainerVolumeMounts: []
+
+## @param extraInitVolumeMounts Mounts that are only mapped into the init-containers. Can be used for additional preconfiguration.
+extraInitVolumeMounts: []
+
+## @deprecated The extraVolumeMounts variable has been split two:
+## - extraContainerVolumeMounts
+## - extraInitVolumeMounts
+## As an example, can be used to mount a client cert when connecting to an external Postgres server.
+## @param extraVolumeMounts **DEPRECATED** Additional volume mounts for init containers and the Gitea main container
+extraVolumeMounts: []
+# - name: postgres-ssl-vol
+#   readOnly: true
+#   mountPath: "/pg-ssl"
+
+## @section Init
+## @param initPreScript Bash shell script copied verbatim to the start of the init-container.
+initPreScript: ""
+#
+# initPreScript: |
+#   mkdir -p /data/git/.postgresql
+#   cp /pg-ssl/* /data/git/.postgresql/
+#   chown -R git:git /data/git/.postgresql/
+#   chmod 400 /data/git/.postgresql/postgresql.key
+
+# Configure commit/action signing prerequisites
+## @section Signing
+#
+## @param signing.enabled Enable commit/action signing
+## @param signing.gpgHome GPG home directory
+## @param signing.privateKey Inline private gpg key for signed Gitea actions
+## @param signing.existingSecret Use an existing secret to store the value of `signing.privateKey`
+signing:
+  enabled: false
+  gpgHome: /data/git/.gnupg
+  privateKey: ""
+  # privateKey: |-
+  #   -----BEGIN PGP PRIVATE KEY BLOCK-----
+  #   ...
+  #   -----END PGP PRIVATE KEY BLOCK-----
+  existingSecret: ""
+
+## @section Gitea
+#
+gitea:
+  ## @param gitea.admin.username Username for the Gitea admin user
+  ## @param gitea.admin.existingSecret Use an existing secret to store admin user credentials
+  ## @param gitea.admin.password Password for the Gitea admin user
+  ## @param gitea.admin.email Email for the Gitea admin user
+  admin:
+    #existingSecret: gitea-admin-secret
+    existingSecret:
+    username: gitea_admin
+    password: r8sA8CPHD9!bt6d
+    email: "gitea@local.domain"
+
+  ## @param gitea.metrics.enabled Enable Gitea metrics
+  ## @param gitea.metrics.serviceMonitor.enabled Enable Gitea metrics service monitor
+  metrics:
+    enabled: false
+    serviceMonitor:
+      enabled: false
+      #  additionalLabels:
+      #    prometheus-release: prom1
+
+  ## @param gitea.ldap LDAP configuration
+  ldap: []
+    # - name: "LDAP 1"
+    #  existingSecret:
+    #  securityProtocol:
+    #  host:
+    #  port:
+    #  userSearchBase:
+    #  userFilter:
+    #  adminFilter:
+    #  emailAttribute:
+    #  bindDn:
+    #  bindPassword:
+    #  usernameAttribute:
+    #  publicSSHKeyAttribute:
+
+  # Either specify inline `key` and `secret` or refer to them via `existingSecret`
+  ## @param gitea.oauth OAuth configuration
+  oauth: []
+    # - name: 'OAuth 1'
+    #   provider:
+    #   key:
+    #   secret:
+    #   existingSecret:
+    #   autoDiscoverUrl:
+    #   useCustomUrls:
+    #   customAuthUrl:
+    #   customTokenUrl:
+    #   customProfileUrl:
+    #   customEmailUrl:
+
+  ## @param gitea.config  Configuration for the Gitea server,ref: [config-cheat-sheet](https://docs.gitea.io/en-us/config-cheat-sheet/)
+  config:
+  #  APP_NAME: "Gitea: Git with a cup of tea"
+
+  #  RUN_MODE: dev
+  #
+    server:
+      DOMAIN: git.miejemplo.com
+      ROOT_URL: http://git.miejemplo.com
+    #  SSH_PORT: 22
+  #
+  #  security:
+  #    PASSWORD_COMPLEXITY: spec
+
+  ## @param gitea.additionalConfigSources Additional configuration from secret or configmap
+  additionalConfigSources: []
+  #   - secret:
+  #       secretName: gitea-app-ini-oauth
+  #   - configMap:
+  #       name: gitea-app-ini-plaintext
+
+  ## @param gitea.additionalConfigFromEnvs Additional configuration sources from environment variables
+  additionalConfigFromEnvs: []
+
+  ## @param gitea.podAnnotations Annotations for the Gitea pod
+  podAnnotations: {}
+
+  ## @section LivenessProbe
+  #
+  ## @param gitea.livenessProbe.enabled Enable liveness probe
+  ## @param gitea.livenessProbe.tcpSocket.port Port to probe for liveness
+  ## @param gitea.livenessProbe.initialDelaySeconds Initial delay before liveness probe is initiated
+  ## @param gitea.livenessProbe.timeoutSeconds Timeout for liveness probe
+  ## @param gitea.livenessProbe.periodSeconds Period for liveness probe
+  ## @param gitea.livenessProbe.successThreshold Success threshold for liveness probe
+  ## @param gitea.livenessProbe.failureThreshold Failure threshold for liveness probe
+  # Modify the liveness probe for your needs or completely disable it by commenting out.
+  livenessProbe:
+    enabled: true
+    tcpSocket:
+      port: http
+    initialDelaySeconds: 200
+    timeoutSeconds: 1
+    periodSeconds: 10
+    successThreshold: 1
+    failureThreshold: 10
+
+  ## @section ReadinessProbe
+  #
+  ## @param gitea.readinessProbe.enabled Enable readiness probe
+  ## @param gitea.readinessProbe.tcpSocket.port Port to probe for readiness
+  ## @param gitea.readinessProbe.initialDelaySeconds Initial delay before readiness probe is initiated
+  ## @param gitea.readinessProbe.timeoutSeconds Timeout for readiness probe
+  ## @param gitea.readinessProbe.periodSeconds Period for readiness probe
+  ## @param gitea.readinessProbe.successThreshold Success threshold for readiness probe
+  ## @param gitea.readinessProbe.failureThreshold Failure threshold for readiness probe
+  # Modify the readiness probe for your needs or completely disable it by commenting out.
+  readinessProbe:
+    enabled: true
+    tcpSocket:
+      port: http
+    initialDelaySeconds: 5
+    timeoutSeconds: 1
+    periodSeconds: 10
+    successThreshold: 1
+    failureThreshold: 3
+
+  # # Uncomment the startup probe to enable and modify it for your needs.
+  ## @section StartupProbe
+  #
+  ## @param gitea.startupProbe.enabled Enable startup probe
+  ## @param gitea.startupProbe.tcpSocket.port Port to probe for startup
+  ## @param gitea.startupProbe.initialDelaySeconds Initial delay before startup probe is initiated
+  ## @param gitea.startupProbe.timeoutSeconds Timeout for startup probe
+  ## @param gitea.startupProbe.periodSeconds Period for startup probe
+  ## @param gitea.startupProbe.successThreshold Success threshold for startup probe
+  ## @param gitea.startupProbe.failureThreshold Failure threshold for startup probe
+  startupProbe:
+    enabled: false
+    tcpSocket:
+      port: http
+    initialDelaySeconds: 60
+    timeoutSeconds: 1
+    periodSeconds: 10
+    successThreshold: 1
+    failureThreshold: 10
+
+## @section Memcached
+#
+## @param memcached.enabled Memcached is loaded as a dependency from [Bitnami](https://github.com/bitnami/charts/tree/master/bitnami/memcached) if enabled in the values. Complete Configuration can be taken from their website.
+## @param memcached.service.port Port for Memcached
+memcached:
+  enabled: true
+  service:
+    port: 11211
+
+## @section PostgreSQL
+#
+## @param postgresql.enabled Enable PostgreSQL
+## @param postgresql.global.postgresql.postgresqlDatabase PostgreSQL database (overrides postgresqlDatabase)
+## @param postgresql.global.postgresql.postgresqlUsername PostgreSQL username (overrides postgresqlUsername)
+## @param postgresql.global.postgresql.postgresqlPassword PostgreSQL admin password (overrides postgresqlPassword)
+## @param postgresql.global.postgresql.servicePort PostgreSQL port (overrides service.port)
+## @param postgresql.persistence.size PVC Storage Request for PostgreSQL volume
+postgresql:
+  enabled: true
+  global:
+    postgresql:
+      postgresqlDatabase: gitea
+      postgresqlUsername: gitea
+      postgresqlPassword: gitea
+      servicePort: 5432
+  persistence:
+    size: 10Gi
+
+## @section MySQL
+#
+## @param mysql.enabled Enable MySQL
+## @param mysql.root.password Password for the root user. Ignored if existing secret is provided
+## @param mysql.db.user Username of new user to create.
+## @param mysql.db.password Password for the new user.Ignored if existing secret is provided
+## @param mysql.db.name Name for new database to create.
+## @param mysql.service.port Port to connect to MySQL service
+## @param mysql.persistence.size PVC Storage Request for MySQL volume
+mysql:
+  enabled: false
+  root:
+    password: gitea
+  db:
+    user: gitea
+    password: gitea
+    name: gitea
+  service:
+    port: 3306
+  persistence:
+    size: 10Gi
+
+## @section MariaDB
+#
+## @param mariadb.enabled Enable MariaDB
+## @param mariadb.auth.database Name of the database to create.
+## @param mariadb.auth.username Username of the new user to create.
+## @param mariadb.auth.password Password for the new user. Ignored if existing secret is provided
+## @param mariadb.auth.rootPassword Password for the root user.
+## @param mariadb.primary.service.port Port to connect to MariaDB service
+## @param mariadb.primary.persistence.size Persistence size for MariaDB
+mariadb:
+  enabled: false
+  auth:
+    database: gitea
+    username: gitea
+    password: gitea
+    rootPassword: gitea
+  primary:
+    service:
+      port: 3306
+    persistence:
+      size: 10Gi
+
+# By default, removed or moved settings that still remain in a user defined values.yaml will cause Helm to fail running the install/update.
+# Set it to false to skip this basic validation check.
+## @section Advanced
+## @param checkDeprecation Set it to false to skip this basic validation check.
+checkDeprecation: true
+
diff --git a/installers/mgmt-cluster/gitea/values-standalone.yaml b/installers/mgmt-cluster/gitea/values-standalone.yaml
new file mode 100644 (file)
index 0000000..867fc05
--- /dev/null
@@ -0,0 +1,509 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+# Default values for gitea.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+## @section Global
+#
+## @param global.imageRegistry global image registry override
+## @param global.imagePullSecrets global image pull secrets override; can be extended by `imagePullSecrets`
+## @param global.storageClass global storage class override
+## @param global.hostAliases global hostAliases which will be added to the pod's hosts files
+global:
+  imageRegistry: ""
+  ## E.g.
+  ## imagePullSecrets:
+  ##   - myRegistryKeySecretName
+  ##
+  imagePullSecrets: []
+  storageClass: ""
+  hostAliases: []
+  # - ip: 192.168.137.2
+  #   hostnames:
+  #   - example.com
+
+## @param replicaCount number of replicas for the statefulset
+replicaCount: 1
+
+## @param clusterDomain cluster domain
+clusterDomain: cluster.local
+
+## @section Image
+## @param image.registry image registry, e.g. gcr.io,docker.io
+## @param image.repository Image to start for this pod
+## @param image.tag Visit: [Image tag](https://hub.docker.com/r/gitea/gitea/tags?page=1&ordering=last_updated). Defaults to `appVersion` within Chart.yaml.
+## @param image.pullPolicy Image pull policy
+## @param image.rootless Wether or not to pull the rootless version of Gitea, only works on Gitea 1.14.x or higher
+image:
+  registry: ""
+  repository: gitea/gitea
+  # Overrides the image tag whose default is the chart appVersion.
+  tag: ""
+  pullPolicy: Always
+  rootless: false # only possible when running 1.14 or later
+
+## @param imagePullSecrets Secret to use for pulling the image
+imagePullSecrets: []
+
+## @section Security
+# Security context is only usable with rootless image due to image design
+## @param podSecurityContext.fsGroup Set the shared file system group for all containers in the pod.
+podSecurityContext:
+  fsGroup: 1000
+
+## @param containerSecurityContext Security context
+containerSecurityContext: {}
+#   allowPrivilegeEscalation: false
+#   capabilities:
+#     drop:
+#       - ALL
+#   # Add the SYS_CHROOT capability for root and rootless images if you intend to
+#   # run pods on nodes that use the container runtime cri-o. Otherwise, you will
+#   # get an error message from the SSH server that it is not possible to read from
+#   # the repository.
+#   # https://gitea.com/gitea/helm-chart/issues/161
+#     add:
+#       - SYS_CHROOT
+#   privileged: false
+#   readOnlyRootFilesystem: true
+#   runAsGroup: 1000
+#   runAsNonRoot: true
+#   runAsUser: 1000
+
+## @deprecated The securityContext variable has been split two:
+## - containerSecurityContext
+## - podSecurityContext.
+## @param securityContext Run init and Gitea containers as a specific securityContext
+securityContext: {}
+
+## @section Service
+service:
+  ## @param service.http.type Kubernetes service type for web traffic
+  ## @param service.http.port Port number for web traffic
+  ## @param service.http.clusterIP ClusterIP setting for http autosetup for statefulset is None
+  ## @param service.http.loadBalancerIP LoadBalancer IP setting
+  ## @param service.http.nodePort NodePort for http service
+  ## @param service.http.externalTrafficPolicy If `service.http.type` is `NodePort` or `LoadBalancer`, set this to `Local` to enable source IP preservation
+  ## @param service.http.externalIPs External IPs for service
+  ## @param service.http.ipFamilyPolicy HTTP service dual-stack policy
+  ## @param service.http.ipFamilies HTTP service dual-stack familiy selection,for dual-stack parameters see official kubernetes [dual-stack concept documentation](https://kubernetes.io/docs/concepts/services-networking/dual-stack/).
+  ## @param service.http.loadBalancerSourceRanges Source range filter for http loadbalancer
+  ## @param service.http.annotations HTTP service annotations
+  http:
+    type: LoadBalancer
+    # port: 3000
+    port: 8080
+    clusterIP: None
+    loadBalancerIP:
+    nodePort:
+    externalTrafficPolicy:
+    externalIPs:
+    ipFamilyPolicy:
+    ipFamilies:
+    loadBalancerSourceRanges: []
+    annotations: {}
+  ## @param service.ssh.type Kubernetes service type for ssh traffic
+  ## @param service.ssh.port Port number for ssh traffic
+  ## @param service.ssh.clusterIP ClusterIP setting for ssh autosetup for statefulset is None
+  ## @param service.ssh.loadBalancerIP LoadBalancer IP setting
+  ## @param service.ssh.nodePort NodePort for ssh service
+  ## @param service.ssh.externalTrafficPolicy If `service.ssh.type` is `NodePort` or `LoadBalancer`, set this to `Local` to enable source IP preservation
+  ## @param service.ssh.externalIPs External IPs for service
+  ## @param service.ssh.ipFamilyPolicy SSH service dual-stack policy
+  ## @param service.ssh.ipFamilies SSH service dual-stack familiy selection,for dual-stack parameters see official kubernetes [dual-stack concept documentation](https://kubernetes.io/docs/concepts/services-networking/dual-stack/).
+  ## @param service.ssh.hostPort HostPort for ssh service
+  ## @param service.ssh.loadBalancerSourceRanges Source range filter for ssh loadbalancer
+  ## @param service.ssh.annotations SSH service annotations
+  ssh:
+    type: LoadBalancer
+    port: 22
+    clusterIP: None
+    loadBalancerIP:
+    nodePort:
+    externalTrafficPolicy:
+    externalIPs:
+    ipFamilyPolicy:
+    ipFamilies:
+    hostPort:
+    loadBalancerSourceRanges: []
+    annotations: {}
+
+
+## @section Ingress
+## @param ingress.enabled Enable ingress
+## @param ingress.className Ingress class name
+## @param ingress.annotations Ingress annotations
+## @param ingress.hosts[0].host Default Ingress host
+## @param ingress.hosts[0].paths[0].path Default Ingress path
+## @param ingress.hosts[0].paths[0].pathType Ingress path type
+## @param ingress.tls Ingress tls settings
+## @extra ingress.apiVersion Specify APIVersion of ingress object. Mostly would only be used for argocd.
+ingress:
+  enabled: false
+  # className: nginx
+  className:
+  annotations: {}
+    # kubernetes.io/ingress.class: nginx
+    # kubernetes.io/tls-acme: "true"
+  hosts:
+    - host: git.example.com
+      paths:
+        - path: /
+          pathType: Prefix
+  tls: []
+  #  - secretName: chart-example-tls
+  #    hosts:
+  #      - git.example.com
+  # Mostly for argocd or any other CI that uses `helm template | kubectl apply` or similar
+  # If helm doesn't correctly detect your ingress API version you can set it here.
+  # apiVersion: networking.k8s.io/v1
+
+## @section StatefulSet
+#
+## @param resources Kubernetes resources
+resources: {}
+  # We usually recommend not to specify default resources and to leave this as a conscious
+  # choice for the user. This also increases chances charts run on environments with little
+  # resources, such as Minikube. If you do want to specify resources, uncomment the following
+  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+  # limits:
+  #   cpu: 100m
+  #   memory: 128Mi
+  # requests:
+  #   cpu: 100m
+  #   memory: 128Mi
+
+## Use an alternate scheduler, e.g. "stork".
+## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/
+##
+## @param schedulerName Use an alternate scheduler, e.g. "stork"
+schedulerName: ""
+
+## @param nodeSelector NodeSelector for the statefulset
+nodeSelector: {}
+
+## @param tolerations Tolerations for the statefulset
+tolerations: []
+
+## @param affinity Affinity for the statefulset
+affinity: {}
+
+## @param dnsConfig dnsConfig for the statefulset
+dnsConfig: {}
+
+## @param statefulset.env  Additional environment variables to pass to containers
+## @param statefulset.terminationGracePeriodSeconds How long to wait until forcefully kill the pod
+## @param statefulset.labels Labels for the statefulset
+## @param statefulset.annotations Annotations for the Gitea StatefulSet to be created
+statefulset:
+  env: []
+    # - name: VARIABLE
+    #   value: my-value
+  terminationGracePeriodSeconds: 60
+  labels: {}
+  annotations: {}
+
+## @section Persistence
+#
+## @param persistence.enabled Enable persistent storage
+## @param persistence.existingClaim Use an existing claim to store repository information
+## @param persistence.size Size for persistence to store repo information
+## @param persistence.accessModes AccessMode for persistence
+## @param persistence.labels Labels for the persistence volume claim to be created
+## @param persistence.annotations Annotations for the persistence volume claim to be created
+## @param persistence.storageClass Name of the storage class to use
+## @param persistence.subPath Subdirectory of the volume to mount at
+persistence:
+  enabled: true
+  existingClaim:
+  size: 10Gi
+  accessModes:
+    - ReadWriteOnce
+  labels: {}
+  annotations: {}
+  storageClass:
+  subPath:
+
+## @param extraVolumes Additional volumes to mount to the Gitea statefulset
+extraVolumes: []
+# - name: postgres-ssl-vol
+#   secret:
+#     secretName: gitea-postgres-ssl
+
+## @param extraContainerVolumeMounts Mounts that are only mapped into the Gitea runtime/main container, to e.g. override custom templates.
+extraContainerVolumeMounts: []
+
+## @param extraInitVolumeMounts Mounts that are only mapped into the init-containers. Can be used for additional preconfiguration.
+extraInitVolumeMounts: []
+
+## @deprecated The extraVolumeMounts variable has been split two:
+## - extraContainerVolumeMounts
+## - extraInitVolumeMounts
+## As an example, can be used to mount a client cert when connecting to an external Postgres server.
+## @param extraVolumeMounts **DEPRECATED** Additional volume mounts for init containers and the Gitea main container
+extraVolumeMounts: []
+# - name: postgres-ssl-vol
+#   readOnly: true
+#   mountPath: "/pg-ssl"
+
+## @section Init
+## @param initPreScript Bash shell script copied verbatim to the start of the init-container.
+initPreScript: ""
+#
+# initPreScript: |
+#   mkdir -p /data/git/.postgresql
+#   cp /pg-ssl/* /data/git/.postgresql/
+#   chown -R git:git /data/git/.postgresql/
+#   chmod 400 /data/git/.postgresql/postgresql.key
+
+# Configure commit/action signing prerequisites
+## @section Signing
+#
+## @param signing.enabled Enable commit/action signing
+## @param signing.gpgHome GPG home directory
+## @param signing.privateKey Inline private gpg key for signed Gitea actions
+## @param signing.existingSecret Use an existing secret to store the value of `signing.privateKey`
+signing:
+  enabled: false
+  gpgHome: /data/git/.gnupg
+  privateKey: ""
+  # privateKey: |-
+  #   -----BEGIN PGP PRIVATE KEY BLOCK-----
+  #   ...
+  #   -----END PGP PRIVATE KEY BLOCK-----
+  existingSecret: ""
+
+## @section Gitea
+#
+gitea:
+  ## @param gitea.admin.username Username for the Gitea admin user
+  ## @param gitea.admin.existingSecret Use an existing secret to store admin user credentials
+  ## @param gitea.admin.password Password for the Gitea admin user
+  ## @param gitea.admin.email Email for the Gitea admin user
+  admin:
+    #existingSecret: gitea-admin-secret
+    existingSecret:
+    username: gitea_admin
+    password: r8sA8CPHD9!bt6d
+    email: "gitea@local.domain"
+
+  ## @param gitea.metrics.enabled Enable Gitea metrics
+  ## @param gitea.metrics.serviceMonitor.enabled Enable Gitea metrics service monitor
+  metrics:
+    enabled: false
+    serviceMonitor:
+      enabled: false
+      #  additionalLabels:
+      #    prometheus-release: prom1
+
+  ## @param gitea.ldap LDAP configuration
+  ldap: []
+    # - name: "LDAP 1"
+    #  existingSecret:
+    #  securityProtocol:
+    #  host:
+    #  port:
+    #  userSearchBase:
+    #  userFilter:
+    #  adminFilter:
+    #  emailAttribute:
+    #  bindDn:
+    #  bindPassword:
+    #  usernameAttribute:
+    #  publicSSHKeyAttribute:
+
+  # Either specify inline `key` and `secret` or refer to them via `existingSecret`
+  ## @param gitea.oauth OAuth configuration
+  oauth: []
+    # - name: 'OAuth 1'
+    #   provider:
+    #   key:
+    #   secret:
+    #   existingSecret:
+    #   autoDiscoverUrl:
+    #   useCustomUrls:
+    #   customAuthUrl:
+    #   customTokenUrl:
+    #   customProfileUrl:
+    #   customEmailUrl:
+
+  ## @param gitea.config  Configuration for the Gitea server,ref: [config-cheat-sheet](https://docs.gitea.io/en-us/config-cheat-sheet/)
+  config:
+  #  APP_NAME: "Gitea: Git with a cup of tea"
+
+  #  RUN_MODE: dev
+  #
+    server:
+      DOMAIN: git.miejemplo.com
+      ROOT_URL: http://git.miejemplo.com
+    #  SSH_PORT: 22
+  #
+  #  security:
+  #    PASSWORD_COMPLEXITY: spec
+
+  ## @param gitea.additionalConfigSources Additional configuration from secret or configmap
+  additionalConfigSources: []
+  #   - secret:
+  #       secretName: gitea-app-ini-oauth
+  #   - configMap:
+  #       name: gitea-app-ini-plaintext
+
+  ## @param gitea.additionalConfigFromEnvs Additional configuration sources from environment variables
+  additionalConfigFromEnvs: []
+
+  ## @param gitea.podAnnotations Annotations for the Gitea pod
+  podAnnotations: {}
+
+  ## @section LivenessProbe
+  #
+  ## @param gitea.livenessProbe.enabled Enable liveness probe
+  ## @param gitea.livenessProbe.tcpSocket.port Port to probe for liveness
+  ## @param gitea.livenessProbe.initialDelaySeconds Initial delay before liveness probe is initiated
+  ## @param gitea.livenessProbe.timeoutSeconds Timeout for liveness probe
+  ## @param gitea.livenessProbe.periodSeconds Period for liveness probe
+  ## @param gitea.livenessProbe.successThreshold Success threshold for liveness probe
+  ## @param gitea.livenessProbe.failureThreshold Failure threshold for liveness probe
+  # Modify the liveness probe for your needs or completely disable it by commenting out.
+  livenessProbe:
+    enabled: true
+    tcpSocket:
+      port: http
+    initialDelaySeconds: 200
+    timeoutSeconds: 1
+    periodSeconds: 10
+    successThreshold: 1
+    failureThreshold: 10
+
+  ## @section ReadinessProbe
+  #
+  ## @param gitea.readinessProbe.enabled Enable readiness probe
+  ## @param gitea.readinessProbe.tcpSocket.port Port to probe for readiness
+  ## @param gitea.readinessProbe.initialDelaySeconds Initial delay before readiness probe is initiated
+  ## @param gitea.readinessProbe.timeoutSeconds Timeout for readiness probe
+  ## @param gitea.readinessProbe.periodSeconds Period for readiness probe
+  ## @param gitea.readinessProbe.successThreshold Success threshold for readiness probe
+  ## @param gitea.readinessProbe.failureThreshold Failure threshold for readiness probe
+  # Modify the readiness probe for your needs or completely disable it by commenting out.
+  readinessProbe:
+    enabled: true
+    tcpSocket:
+      port: http
+    initialDelaySeconds: 5
+    timeoutSeconds: 1
+    periodSeconds: 10
+    successThreshold: 1
+    failureThreshold: 3
+
+  # # Uncomment the startup probe to enable and modify it for your needs.
+  ## @section StartupProbe
+  #
+  ## @param gitea.startupProbe.enabled Enable startup probe
+  ## @param gitea.startupProbe.tcpSocket.port Port to probe for startup
+  ## @param gitea.startupProbe.initialDelaySeconds Initial delay before startup probe is initiated
+  ## @param gitea.startupProbe.timeoutSeconds Timeout for startup probe
+  ## @param gitea.startupProbe.periodSeconds Period for startup probe
+  ## @param gitea.startupProbe.successThreshold Success threshold for startup probe
+  ## @param gitea.startupProbe.failureThreshold Failure threshold for startup probe
+  startupProbe:
+    enabled: false
+    tcpSocket:
+      port: http
+    initialDelaySeconds: 60
+    timeoutSeconds: 1
+    periodSeconds: 10
+    successThreshold: 1
+    failureThreshold: 10
+
+## @section Memcached
+#
+## @param memcached.enabled Memcached is loaded as a dependency from [Bitnami](https://github.com/bitnami/charts/tree/master/bitnami/memcached) if enabled in the values. Complete Configuration can be taken from their website.
+## @param memcached.service.port Port for Memcached
+memcached:
+  enabled: true
+  service:
+    port: 11211
+
+## @section PostgreSQL
+#
+## @param postgresql.enabled Enable PostgreSQL
+## @param postgresql.global.postgresql.postgresqlDatabase PostgreSQL database (overrides postgresqlDatabase)
+## @param postgresql.global.postgresql.postgresqlUsername PostgreSQL username (overrides postgresqlUsername)
+## @param postgresql.global.postgresql.postgresqlPassword PostgreSQL admin password (overrides postgresqlPassword)
+## @param postgresql.global.postgresql.servicePort PostgreSQL port (overrides service.port)
+## @param postgresql.persistence.size PVC Storage Request for PostgreSQL volume
+postgresql:
+  enabled: true
+  global:
+    postgresql:
+      postgresqlDatabase: gitea
+      postgresqlUsername: gitea
+      postgresqlPassword: gitea
+      servicePort: 5432
+  persistence:
+    size: 10Gi
+
+## @section MySQL
+#
+## @param mysql.enabled Enable MySQL
+## @param mysql.root.password Password for the root user. Ignored if existing secret is provided
+## @param mysql.db.user Username of new user to create.
+## @param mysql.db.password Password for the new user.Ignored if existing secret is provided
+## @param mysql.db.name Name for new database to create.
+## @param mysql.service.port Port to connect to MySQL service
+## @param mysql.persistence.size PVC Storage Request for MySQL volume
+mysql:
+  enabled: false
+  root:
+    password: gitea
+  db:
+    user: gitea
+    password: gitea
+    name: gitea
+  service:
+    port: 3306
+  persistence:
+    size: 10Gi
+
+## @section MariaDB
+#
+## @param mariadb.enabled Enable MariaDB
+## @param mariadb.auth.database Name of the database to create.
+## @param mariadb.auth.username Username of the new user to create.
+## @param mariadb.auth.password Password for the new user. Ignored if existing secret is provided
+## @param mariadb.auth.rootPassword Password for the root user.
+## @param mariadb.primary.service.port Port to connect to MariaDB service
+## @param mariadb.primary.persistence.size Persistence size for MariaDB
+mariadb:
+  enabled: false
+  auth:
+    database: gitea
+    username: gitea
+    password: gitea
+    rootPassword: gitea
+  primary:
+    service:
+      port: 3306
+    persistence:
+      size: 10Gi
+
+# By default, removed or moved settings that still remain in a user defined values.yaml will cause Helm to fail running the install/update.
+# Set it to false to skip this basic validation check.
+## @section Advanced
+## @param checkDeprecation Set it to false to skip this basic validation check.
+checkDeprecation: true
+
diff --git a/installers/mgmt-cluster/install_mgmt_cluster.sh b/installers/mgmt-cluster/install_mgmt_cluster.sh
new file mode 100755 (executable)
index 0000000..5550393
--- /dev/null
@@ -0,0 +1,144 @@
+#!/bin/bash
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+#
+
+set -x
+
+# main
+while getopts ":D:d:G:M:-: " o; do
+    case "${o}" in
+        d)
+            OSM_HOME_DIR="${OPTARG}"
+            ;;
+        D)
+            OSM_DEVOPS="${OPTARG}"
+            ;;
+        M)
+            KUBECONFIG_MGMT_CLUSTER="${OPTARG}"
+            ;;
+        G)
+            KUBECONFIG_AUX_CLUSTER="${OPTARG}"
+            ;;
+        -)
+            [ "${OPTARG}" == "debug" ] && DEBUG_INSTALL="y" && continue
+            [ "${OPTARG}" == "no-mgmt-cluster" ] && INSTALL_MGMT_CLUSTER="" && continue
+            [ "${OPTARG}" == "no-aux-cluster" ] && INSTALL_AUX_CLUSTER="" && continue
+            [ "${OPTARG}" == "minio" ] && INSTALL_MINIO="y" && continue
+            [ "${OPTARG}" == "no-minio" ] && INSTALL_MINIO="" && continue
+            echo -e "Invalid option: '--$OPTARG'\n" >&2
+            exit 1
+            ;;
+        :)
+            echo "Option -$OPTARG requires an argument" >&2
+            exit 1
+            ;;
+        \?)
+            echo -e "Invalid option: '-$OPTARG'\n" >&2
+            exit 1
+            ;;
+        *)
+            exit 1
+            ;;
+    esac
+done
+
+DEBUG_INSTALL=${DEBUG_INSTALL:-}
+OSM_DEVOPS=${OSM_DEVOPS:-"/usr/share/osm-devops"}
+OSM_HOME_DIR=${OSM_HOME_DIR:-"$HOME/.osm"}
+OSM_MGMTCLUSTER_BASE_FOLDER="${OSM_DEVOPS}/installers/mgmt-cluster"
+INSTALL_MGMT_CLUSTER=${INSTALL_MGMT_CLUSTER:-"y"}
+INSTALL_AUX_CLUSTER=${INSTALL_AUX_CLUSTER:-"y"}
+KUBECONFIG_MGMT_CLUSTER=${KUBECONFIG_MGMT_CLUSTER:-"$HOME/.kube/config"}
+KUBECONFIG_AUX_CLUSTER=${KUBECONFIG_AUX_CLUSTER:-"$HOME/.kube/config"}
+KUBECONFIG_OLD=${KUBECONFIG:-"$HOME/.kube/config"}
+export CREDENTIALS_DIR="${OSM_HOME_DIR}/.credentials"
+export WORK_REPOS_DIR="${OSM_HOME_DIR}/repos"
+export INSTALL_MINIO=${INSTALL_MINIO:-""}
+echo "DEBUG_INSTALL=$DEBUG_INSTALL"
+echo "OSM_DEVOPS=$OSM_DEVOPS"
+echo "OSM_HOME_DIR=$OSM_HOME_DIR"
+echo "OSM_MGMTCLUSTER_BASE_FOLDER=$OSM_MGMTCLUSTER_BASE_FOLDER"
+echo "INSTALL_MGMT_CLUSTER=$INSTALL_MGMT_CLUSTER"
+echo "INSTALL_AUX_CLUSTER=$INSTALL_AUX_CLUSTER"
+echo "KUBECONFIG_MGMT_CLUSTER=$KUBECONFIG_MGMT_CLUSTER"
+echo "KUBECONFIG_AUX_CLUSTER=$KUBECONFIG_AUX_CLUSTER"
+echo "CREDENTIALS_DIR=$CREDENTIALS_DIR"
+echo "WORK_REPOS_DIR=$WORK_REPOS_DIR"
+
+source $OSM_DEVOPS/common/logging
+source $OSM_DEVOPS/common/track
+
+pushd $OSM_MGMTCLUSTER_BASE_FOLDER
+
+if [ -n "${INSTALL_AUX_CLUSTER}" ] || [ -n "${INSTALL_MGMT_CLUSTER}" ]; then
+
+    echo "Setup CLI tools for mgmt and aux cluster"
+    ./setup-cli-tools.sh
+    track mgmtcluster setupclitools_ok
+
+    echo "Creating folders under ${OSM_HOME_DIR} for credentials and repos"
+    mkdir -p "${CREDENTIALS_DIR}"
+    mkdir -p "${WORK_REPOS_DIR}"
+    track mgmtcluster folders_ok
+
+    # Test if the user exists. Otherwise, create a git user
+    echo "Test if there is a git user. Otherwise, create it."
+    if [ -n "$(git config user.name)" ]; then
+        git -C $WORK_REPOS_DIR config --local user.name osm_user
+        git -C $WORK_REPOS_DIR config --local user.email osm_user@mydomain.com
+    fi
+
+    # Test if the user exists. Otherwise, create a git user
+    echo "Checking if the user has an SSH key pair"
+    if [ ! -f "$HOME/.ssh/id_rsa" ]; then
+        echo "Generating an SSH key pair for the user"
+        ssh-keygen -t rsa -f "$HOME/.ssh/id_rsa" -N "" -q
+    fi
+
+    echo "Loading env variables from 00-base-config.rc"
+    source 00-base-config.rc
+
+fi
+
+# "aux-svc" cluster
+if [ -n "${INSTALL_AUX_CLUSTER}" ]; then
+    echo "Provisioning auxiliary cluster with Gitea"
+    export KUBECONFIG="${KUBECONFIG_AUX_CLUSTER}"
+    ./01-provision-aux-svc.sh
+    track mgmtcluster aux_cluster_ok
+
+    ./02-provision-local-git-user.sh
+    track mgmtcluster local_git_user_ok
+fi
+
+# "mgmt" cluster
+if [ -n "${INSTALL_MGMT_CLUSTER}" ]; then
+    echo "Provisioning mgmt cluster"
+    export KUBECONFIG="${KUBECONFIG_MGMT_CLUSTER}"
+    ./03-provision-mgmt-cluster.sh
+    track mgmtcluster mgmt_cluster_ok
+fi
+
+export KUBECONFIG=${KUBECONFIG_OLD}
+if [ -n "${INSTALL_MGMT_CLUSTER}" ]; then
+    echo "Saving age keys in OSM cluster"
+    kubectl -n osm create secret generic mgmt-cluster-age-keys --from-file=privkey="${CREDENTIALS_DIR}/age.mgmt.key" --from-file=pubkey="${CREDENTIALS_DIR}/age.mgmt.pub"
+fi
+
+echo "Creating secrets with kubeconfig files"
+kubectl -n osm create secret generic auxcluster-secret --from-file=kubeconfig="${KUBECONFIG_AUX_CLUSTER}"
+kubectl -n osm create secret generic mgmtcluster-secret --from-file=kubeconfig="${KUBECONFIG_MGMT_CLUSTER}"
+
+popd
+
diff --git a/installers/mgmt-cluster/library/functions.sh b/installers/mgmt-cluster/library/functions.sh
new file mode 100755 (executable)
index 0000000..638a1d2
--- /dev/null
@@ -0,0 +1,91 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+BLUE='\033[0;34m'
+CYAN='\033[0;36m'
+RESET='\033[0m'
+
+# Colored messages (blue is the default)
+# Examples:
+#   m "hello world"
+#   m "hello world" "$GREEN"
+function m() {
+  local COLOR=${2:-$BLUE}
+  echo -e "$COLOR$1$RESET"
+}
+
+function copy_function() {
+  local ORIG_FUNC=$(declare -f $1)
+  local NEWNAME_FUNC="$2${ORIG_FUNC#$1}"
+  eval "$NEWNAME_FUNC"
+}
+
+function replace_text() {
+  local FILE=$1
+  local START=$2
+  local END=$3
+  local NEW=$4
+  local T=$(mktemp)
+  head -n $((START-1)) "$FILE" > "$T"
+  echo "$NEW" >> "$T"
+  tail -n +$((END+1)) "$FILE" >> "$T"
+  mv "$T" "$FILE"
+}
+
+function insert_text() {
+  local FILE=$1
+  local START=$2
+  local NEW=$3
+  local T=$(mktemp)
+  head -n $((START-1)) "$FILE" > "$T"
+  echo "$NEW" >> "$T"
+  tail -n +$START "$FILE" >> "$T"
+  mv "$T" "$FILE"
+}
+
+function remove_text() {
+  local FILE=$1
+  local START=$2
+  local END=$3
+  local T=$(mktemp)
+  head -n $((START-1)) "$FILE" > "$T"
+  tail -n +$((END+1)) "$FILE" >> "$T"
+  mv "$T" "$FILE"
+}
+
+function envsubst_cp() {
+  local FROM_FILE=$1
+  local TO_FILE=$2
+  mkdir --parents "$(dirname "$TO_FILE")"
+  cat "$FROM_FILE" | envsubst > "$TO_FILE"
+}
+
+function envsubst_dir() {
+  local FROM_DIR=$1
+  local TO_DIR=$2
+  rm --recursive --force "$TO_DIR"
+  mkdir --parents "$TO_DIR"
+  pushd "$FROM_DIR" > /dev/null
+  local F
+  find . -type f | while read F; do
+    envsubst_cp "$F" "$TO_DIR/$F"
+  done
+  popd > /dev/null
+}
diff --git a/installers/mgmt-cluster/library/trap.sh b/installers/mgmt-cluster/library/trap.sh
new file mode 100755 (executable)
index 0000000..2a1156d
--- /dev/null
@@ -0,0 +1,48 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+function goodbye() {
+  local DURATION=$(date --date=@$(( "$(date +%s)" - "$TRAP_START_TIME" )) --utc +%T)
+  local CODE=$1
+  cd "$TRAP_DIR"
+  if [ "$CODE" == 0 ]; then
+    m "$(realpath --relative-to="$HERE" "$0") succeeded! $DURATION" "$GREEN"
+  elif [ "$CODE" == abort ]; then
+    m "Aborted $(realpath --relative-to="$HERE" "$0")! $DURATION" "$RED"
+  else
+    m "Oh no! $(realpath --relative-to="$HERE" "$0") failed! $DURATION" "$RED"
+  fi
+}
+
+function trap_EXIT() {
+  local ERR=$?
+  goodbye "$ERR"
+  exit "$ERR"
+}
+
+function trap_INT() {
+  goodbye abort
+  trap - EXIT
+  exit 1
+}
+
+TRAP_DIR=$PWD
+TRAP_START_TIME=$(date +%s)
+
+trap trap_INT INT
+
+trap trap_EXIT EXIT
diff --git a/installers/mgmt-cluster/mgmt-operators-and-crds/add-operators-and-crds.sh b/installers/mgmt-cluster/mgmt-operators-and-crds/add-operators-and-crds.sh
new file mode 100755 (executable)
index 0000000..2ee36aa
--- /dev/null
@@ -0,0 +1,52 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e -o pipefail
+
+export HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+source "${HERE}/library/functions.sh"
+source "${HERE}/library/trap.sh"
+
+
+# Input values
+export PROJECT_DIR="$1"
+export PROFILE_NAME="$2"
+
+# Reference folders
+export ADDON_CTRL_DIR="${PROJECT_DIR}/infra-controller-profiles/${PROFILE_NAME}"
+export ADDON_CONFIG_DIR="${PROJECT_DIR}/infra-config-profiles/${PROFILE_NAME}"
+
+# Add the CrossPlane controller
+PACKAGE="${SW_CATALOGS_REPO_DIR}/infra-controllers/crossplane/controller"
+cp "${PACKAGE}/templates"/* "${ADDON_CTRL_DIR}/"
+
+# Add the CrossPlane providers
+## Azure providers
+PACKAGE="${SW_CATALOGS_REPO_DIR}/infra-controllers/crossplane/providers/azure"
+cp "${PACKAGE}/templates"/* "${ADDON_CTRL_DIR}/"
+
+## GCP providers
+PACKAGE="${SW_CATALOGS_REPO_DIR}/infra-controllers/crossplane/providers/gcp"
+cp "${PACKAGE}/templates"/* "${ADDON_CTRL_DIR}/"
+
+## AWS providers
+PACKAGE="${SW_CATALOGS_REPO_DIR}/infra-controllers/crossplane/providers/aws"
+cp "${PACKAGE}/templates"/* "${ADDON_CTRL_DIR}/"
+
+# Add the Argo WorkFlows controller
+PACKAGE="${SW_CATALOGS_REPO_DIR}/infra-controllers/argo-workflows"
+cp "${PACKAGE}/templates"/* "${ADDON_CTRL_DIR}/"
diff --git a/installers/mgmt-cluster/mgmt-operators-and-crds/configure-workflows.sh b/installers/mgmt-cluster/mgmt-operators-and-crds/configure-workflows.sh
new file mode 100755 (executable)
index 0000000..8948560
--- /dev/null
@@ -0,0 +1,95 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e -o pipefail
+
+export HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+source "${HERE}/library/functions.sh"
+source "${HERE}/library/trap.sh"
+
+
+# Input values
+export PROJECT_DIR="$1"
+export PROFILE_NAME="$2"
+export PUBLIC_KEY="$3"
+
+
+# Helper functions to clone secret from one namespace to other
+function clone_secret_to_new_ns_stdout() {
+  local SECRET_NAME="$1"
+  local SOURCE_NS="$2"
+  local DESTINATION_NS="$3"
+
+  kubectl get secret "${SECRET_NAME}" -n "${SOURCE_NS}" -o yaml | \
+  yq 'del(.metadata.uid) | del(.metadata.resourceVersion) | del(.metadata.creationTimestamp)' | \
+  yq ".metadata.namespace = \"${DESTINATION_NS}\""
+}
+
+# Helper function to encrypt secrets from stdin
+function encrypt_secret_from_stdin() {
+  local PUBLIC_KEY="$1"
+
+  # Save secret manifest to temporary file
+  local TMPFILE=$(mktemp /tmp/secret.XXXXXXXXXX.yaml) || exit 1
+  cat > "${TMPFILE}"
+
+  # Encrypt
+  sops \
+    --age=${PUBLIC_KEY} \
+    --encrypt \
+    --encrypted-regex '^(data|stringData)$' \
+    --in-place "${TMPFILE}"
+
+  # Outputs the result and removes the temporary file
+  cat "${TMPFILE}" && rm -f "${TMPFILE}"
+}
+
+
+# Reference folder for addon configs
+export ADDON_CONFIG_DIR="${PROJECT_DIR}/infra-config-profiles/${PROFILE_NAME}"
+
+# KSU folder for workflows
+export RESOURCES_DIR="${ADDON_CONFIG_DIR}/osm-workflows"
+mkdir -p "${RESOURCES_DIR}"
+
+# Create namespace for OSM workflows
+WORKFLOWS_NS=osm-workflows
+kubectl create ns ${WORKFLOWS_NS} \
+    -o yaml \
+    --dry-run=client \
+    > "${RESOURCES_DIR}/namespace.yaml"
+
+# Copy secrets for Git repos from `flux-system` to `osm-workflows` namespace
+clone_secret_to_new_ns_stdout \
+  fleet-repo \
+  flux-system \
+  "${WORKFLOWS_NS}" | \
+encrypt_secret_from_stdin \
+  "${PUBLIC_KEY}" \
+> "${RESOURCES_DIR}/secret-fleet-repo.yaml"
+
+clone_secret_to_new_ns_stdout \
+  sw-catalogs \
+  flux-system \
+  "${WORKFLOWS_NS}" | \
+encrypt_secret_from_stdin \
+  "${PUBLIC_KEY}" \
+> "${RESOURCES_DIR}/secret-sw-catalogs.yaml"
+
+# Add appropriate configurations and workflow templates for Argo WorkFlows into the namespace
+PACKAGE="${SW_CATALOGS_REPO_DIR}/infra-configs/osm-workflows"
+cp -r "${PACKAGE}/templates"/* "${RESOURCES_DIR}/"
diff --git a/installers/mgmt-cluster/mgmt-operators-and-crds/library/functions.sh b/installers/mgmt-cluster/mgmt-operators-and-crds/library/functions.sh
new file mode 100755 (executable)
index 0000000..638a1d2
--- /dev/null
@@ -0,0 +1,91 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+BLUE='\033[0;34m'
+CYAN='\033[0;36m'
+RESET='\033[0m'
+
+# Colored messages (blue is the default)
+# Examples:
+#   m "hello world"
+#   m "hello world" "$GREEN"
+function m() {
+  local COLOR=${2:-$BLUE}
+  echo -e "$COLOR$1$RESET"
+}
+
+function copy_function() {
+  local ORIG_FUNC=$(declare -f $1)
+  local NEWNAME_FUNC="$2${ORIG_FUNC#$1}"
+  eval "$NEWNAME_FUNC"
+}
+
+function replace_text() {
+  local FILE=$1
+  local START=$2
+  local END=$3
+  local NEW=$4
+  local T=$(mktemp)
+  head -n $((START-1)) "$FILE" > "$T"
+  echo "$NEW" >> "$T"
+  tail -n +$((END+1)) "$FILE" >> "$T"
+  mv "$T" "$FILE"
+}
+
+function insert_text() {
+  local FILE=$1
+  local START=$2
+  local NEW=$3
+  local T=$(mktemp)
+  head -n $((START-1)) "$FILE" > "$T"
+  echo "$NEW" >> "$T"
+  tail -n +$START "$FILE" >> "$T"
+  mv "$T" "$FILE"
+}
+
+function remove_text() {
+  local FILE=$1
+  local START=$2
+  local END=$3
+  local T=$(mktemp)
+  head -n $((START-1)) "$FILE" > "$T"
+  tail -n +$((END+1)) "$FILE" >> "$T"
+  mv "$T" "$FILE"
+}
+
+function envsubst_cp() {
+  local FROM_FILE=$1
+  local TO_FILE=$2
+  mkdir --parents "$(dirname "$TO_FILE")"
+  cat "$FROM_FILE" | envsubst > "$TO_FILE"
+}
+
+function envsubst_dir() {
+  local FROM_DIR=$1
+  local TO_DIR=$2
+  rm --recursive --force "$TO_DIR"
+  mkdir --parents "$TO_DIR"
+  pushd "$FROM_DIR" > /dev/null
+  local F
+  find . -type f | while read F; do
+    envsubst_cp "$F" "$TO_DIR/$F"
+  done
+  popd > /dev/null
+}
diff --git a/installers/mgmt-cluster/mgmt-operators-and-crds/library/trap.sh b/installers/mgmt-cluster/mgmt-operators-and-crds/library/trap.sh
new file mode 100755 (executable)
index 0000000..2a1156d
--- /dev/null
@@ -0,0 +1,48 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+function goodbye() {
+  local DURATION=$(date --date=@$(( "$(date +%s)" - "$TRAP_START_TIME" )) --utc +%T)
+  local CODE=$1
+  cd "$TRAP_DIR"
+  if [ "$CODE" == 0 ]; then
+    m "$(realpath --relative-to="$HERE" "$0") succeeded! $DURATION" "$GREEN"
+  elif [ "$CODE" == abort ]; then
+    m "Aborted $(realpath --relative-to="$HERE" "$0")! $DURATION" "$RED"
+  else
+    m "Oh no! $(realpath --relative-to="$HERE" "$0") failed! $DURATION" "$RED"
+  fi
+}
+
+function trap_EXIT() {
+  local ERR=$?
+  goodbye "$ERR"
+  exit "$ERR"
+}
+
+function trap_INT() {
+  goodbye abort
+  trap - EXIT
+  exit 1
+}
+
+TRAP_DIR=$PWD
+TRAP_START_TIME=$(date +%s)
+
+trap trap_INT INT
+
+trap trap_EXIT EXIT
diff --git a/installers/mgmt-cluster/minio/00-base-config.rc b/installers/mgmt-cluster/minio/00-base-config.rc
new file mode 100644 (file)
index 0000000..e4cf1d6
--- /dev/null
@@ -0,0 +1,38 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+# Location where credentials should be saved
+export CREDENTIALS_DIR=${CREDENTIALS_DIR:-../../../.credentials}; export CREDENTIALS_DIR=$(readlink -f "${CREDENTIALS_DIR}")
+
+# Minio version
+export MINIO_VERSION="${MINIO_VERSION:-v5.0.11}"
+
+# Minio tenant name
+export MINIO_TENANT_NAME=${MINIO_TENANT_NAME:-minio-osm-tenant}
+
+# Minio tenant capacity
+export MINIO_TENANT_CAPACITY=${MINIO_TENANT_CAPACITY:-10Gi}
+
+# Number of tenant servers
+export MINIO_TENANT_SERVERS=${MINIO_TENANT_SERVERS:-2}
+
+# Number of tenant volumes
+export MINIO_TENANT_VOLUMES=${MINIO_TENANT_VOLUMES:-4}
+
+# Expose with Ingress
+export MINIO_EXPOSE_CONSOLE=true
+export MINIO_EXPOSE_TENANT=true
diff --git a/installers/mgmt-cluster/minio/01-deploy-minio-operator.sh b/installers/mgmt-cluster/minio/01-deploy-minio-operator.sh
new file mode 100755 (executable)
index 0000000..e87162b
--- /dev/null
@@ -0,0 +1,41 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e
+
+export HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+source "${HERE}/library/functions.sh"
+source "${HERE}/library/trap.sh"
+
+############################################
+# Main script starts here
+############################################
+
+m "\nDeploying Minio Operator..."
+
+# Deploy Minio Operator
+MINIO_VERSION="${MINIO_VERSION:-v5.0.11}"
+TIMEOUT=120 # By default is 27. Since sometimes connection may be slow, here we allow more time
+kustomize build "github.com/minio/operator/resources/?timeout=${TIMEOUT}&ref=${MINIO_VERSION}" | \
+    # (optional) To allow deployments over single-node clusters
+    yq 'del(.spec.template.spec.affinity)' | \
+    # Deploy
+    kubectl apply -f -
+
+# Wait until completion
+kubectl rollout status deploy/minio-operator --namespace=minio-operator --watch --timeout=1h
diff --git a/installers/mgmt-cluster/minio/02-create-minio-tenant.sh b/installers/mgmt-cluster/minio/02-create-minio-tenant.sh
new file mode 100755 (executable)
index 0000000..fa21b8c
--- /dev/null
@@ -0,0 +1,59 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e
+
+export HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+source "${HERE}/library/functions.sh"
+source "${HERE}/library/trap.sh"
+
+############################################
+# Main script starts here
+############################################
+
+# In case no arguments are passed, takes the value of the corresponding environment variables
+MINIO_TENANT_NAME=${1:-${MINIO_TENANT_NAME}}
+MINIO_TENANT_CAPACITY=${2:-${MINIO_TENANT_CAPACITY}}
+
+# Adjusts tenant sizes
+export MINIO_TENANT_SERVERS=${MINIO_TENANT_SERVERS:-4}
+export MINIO_TENANT_VOLUMES=${MINIO_TENANT_VOLUMES:-8}
+
+
+m "\nDeploying ${MINIO_TENANT_NAME} tenant..."
+
+# Create Minio tenant
+kubectl create ns ${MINIO_TENANT_NAME}
+OPTIONS=""
+# OPTIONS="--storage-class default"
+kubectl minio tenant create                     \
+    ${MINIO_TENANT_NAME}                        \
+    --servers          ${MINIO_TENANT_SERVERS}  \
+    --volumes          ${MINIO_TENANT_VOLUMES}  \
+    --capacity         ${MINIO_TENANT_CAPACITY} \
+    --namespace        ${MINIO_TENANT_NAME}     \
+    ${OPTIONS}                                  \
+    --output | \
+    # Fix malformed manifest with wrong fields
+    yq 'del(.spec.pools[0].volumeClaimTemplate.metadata.creationTimestamp)' | \
+    kubectl apply -f -
+
+# Wait until completion
+echo "Waiting for tenant's statefulset to be ready..."
+sleep 30    # To allow the statefulset object to exist
+kubectl rollout status sts/minio-osm-tenant-ss-0 --namespace=${MINIO_TENANT_NAME} --watch --timeout=1h
diff --git a/installers/mgmt-cluster/minio/03-deploy-ingress-for-minio.sh b/installers/mgmt-cluster/minio/03-deploy-ingress-for-minio.sh
new file mode 100755 (executable)
index 0000000..5f2824e
--- /dev/null
@@ -0,0 +1,82 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e
+
+export HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+source "${HERE}/library/functions.sh"
+source "${HERE}/library/trap.sh"
+
+############################################
+# Main script starts here
+############################################
+
+# If there is no Ingress Controller, returns
+if [[ -z $(kubectl get svc/ingress-nginx-controller -n ingress-nginx 2> /dev/null) ]]
+then
+    echo "No Ingress controller installed. Exiting"
+    exit 1
+fi
+
+# Retrieve ports
+export MINIO_CONSOLE_HTTP_PORT=$(kubectl get svc/console -n minio-operator -o jsonpath='{.spec.ports[?(.name=="http")].port}')
+export MINIO_CONSOLE_HTTPS_PORT=$(kubectl get svc/console -n minio-operator -o jsonpath='{.spec.ports[?(.name=="https")].port}')
+export MINIO_TENANT_HTTPS_PORT=$(kubectl get svc/minio -n ${MINIO_TENANT_NAME} -o jsonpath='{.spec.ports[?(.name=="https-minio")].port}')
+
+# Determine Ingress host names
+INGRESS_IP=$(kubectl get svc/ingress-nginx-controller -n ingress-nginx -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
+export MINIO_INGRESS_CONSOLE_HOST="console.s3.${INGRESS_IP}.nip.io"
+export MINIO_INGRESS_TENANT_HOST="${MINIO_TENANT_NAME}.s3.${INGRESS_IP}.nip.io"
+
+# Determine locations of TLS certificates for tenant's endpoint, if applicable
+export MINIO_TENANT_TLS_KEY="${CREDENTIALS_DIR}/tls.${MINIO_TENANT_NAME}.key"
+export MINIO_TENANT_TLS_CERT="${CREDENTIALS_DIR}/tls.${MINIO_TENANT_NAME}.cert"
+
+# If applicable, deploy Ingress to access Minio Console from outside
+if [[ "${MINIO_EXPOSE_CONSOLE}" == "true" ]]
+then
+    m "\nDeploying Ingress for Console..."
+    envsubst < ingress-manifests/console/ingress-console.yaml | \
+        kubectl apply -f -
+fi
+
+# If applicable, deploy Ingress to access the Minio Tenant from outside
+if [[ "${MINIO_EXPOSE_TENANT}" == "true" ]]
+then
+    m "\nDeploying Ingress for ${MINIO_TENANT_NAME} tenant..."
+
+    # Create self-signed certificate (comment if using pre-created certificate)
+    openssl req -x509 \
+        -nodes \
+        -days 365 \
+        -newkey rsa:2048 \
+        -keyout "${MINIO_TENANT_TLS_KEY}" \
+        -out "${MINIO_TENANT_TLS_CERT}" \
+        -subj "/CN=${MINIO_INGRESS_TENANT_HOST}/O=${MINIO_INGRESS_TENANT_HOST}" \
+        -addext "subjectAltName = DNS:${MINIO_INGRESS_TENANT_HOST}"
+
+    kubectl create secret tls nginx-tls \
+        --key "${MINIO_TENANT_TLS_KEY}" \
+        --cert "${MINIO_TENANT_TLS_CERT}" \
+        -n ${MINIO_TENANT_NAME}
+
+    envsubst < ingress-manifests/tenant/ingress-tenant.yaml | \
+        kubectl apply -f -
+
+    echo "${MINIO_TENANT_NAME} tenant exposed at https://${MINIO_INGRESS_TENANT_HOST}"
+fi
diff --git a/installers/mgmt-cluster/minio/04-get-minio-connection-info.rc b/installers/mgmt-cluster/minio/04-get-minio-connection-info.rc
new file mode 100644 (file)
index 0000000..d02e5af
--- /dev/null
@@ -0,0 +1,62 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+# Retrieves Minio connection info data
+
+# Internal services and ports
+export MINIO_INTERNAL_CONSOLE_HOST=console.minio-operator
+export MINIO_INTERNAL_TENANT_HOST=minio.${MINIO_TENANT_NAME}
+export MINIO_CONSOLE_HTTP_PORT=$(kubectl get svc/console -n minio-operator -o jsonpath='{.spec.ports[?(.name=="http")].port}')
+export MINIO_CONSOLE_HTTPS_PORT=$(kubectl get svc/console -n minio-operator -o jsonpath='{.spec.ports[?(.name=="https")].port}')
+export MINIO_TENANT_HTTPS_PORT=$(kubectl get svc/minio -n ${MINIO_TENANT_NAME} -o jsonpath='{.spec.ports[?(.name=="https-minio")].port}')
+# NOTE: There is no HTTP port for the Minio Tenant. For HTTP-like accesses, use the `--insecure` flag in Minio client.
+
+# Final Minio's Console HTTP service
+## In case it is behind an Ingress
+if [[ -n $(kubectl get ingress/minio-console-ingress -n minio-operator 2> /dev/null) ]]
+then
+    # Retrieves the external host name
+    INGRESS_IP=$(kubectl get svc/ingress-nginx-controller -n ingress-nginx -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
+    export MINIO_INGRESS_CONSOLE_HOST="console.s3.${INGRESS_IP}.nip.io"
+
+    # Uses the external host name as the default console endpoint
+    export MINIO_CONSOLE_HOST=${MINIO_INGRESS_CONSOLE_HOST}
+## Otherwise just uses the internal service name
+else
+    export MINIO_CONSOLE_HOST=${MINIO_INTERNAL_CONSOLE_HOST}
+fi
+export MINIO_CONSOLE_URL="http://${MINIO_CONSOLE_HOST}"
+
+# Final Minio's Tenant HTTPS service
+## In case it is behind an Ingress
+if [[ -n $(kubectl get ingress/minio-tenant-ingress -n ${MINIO_TENANT_NAME} 2> /dev/null) ]]
+then
+    # Retrieves the external host name
+    INGRESS_IP=$(kubectl get svc/ingress-nginx-controller -n ingress-nginx -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
+    export MINIO_INGRESS_TENANT_HOST="${MINIO_TENANT_NAME}.s3.${INGRESS_IP}.nip.io"
+
+    # Uses the external host name as the default console endpoint
+    export MINIO_TENANT_HOST=${MINIO_INGRESS_TENANT_HOST}
+## Otherwise just uses the internal service name
+else
+    export MINIO_TENANT_HOST=${MINIO_INTERNAL_TENANT_HOST}
+fi
+export MINIO_TENANT_URL="https://${MINIO_TENANT_HOST}"
+
+# Determine locations of TLS certificates for tenant's endpoint, if applicable
+export MINIO_TENANT_TLS_KEY="${CREDENTIALS_DIR}/tls.${MINIO_TENANT_NAME}.key"
+export MINIO_TENANT_TLS_CERT="${CREDENTIALS_DIR}/tls.${MINIO_TENANT_NAME}.cert"
diff --git a/installers/mgmt-cluster/minio/05-export-connection-info.sh b/installers/mgmt-cluster/minio/05-export-connection-info.sh
new file mode 100755 (executable)
index 0000000..9524106
--- /dev/null
@@ -0,0 +1,68 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e
+
+export HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+source "${HERE}/library/functions.sh"
+source "${HERE}/library/trap.sh"
+
+############################################
+# Main script starts here
+############################################
+
+# In case no argument is passed, takes the value of the environment variable
+MINIO_TENANT_NAME=${1:-${MINIO_TENANT_NAME}}
+
+m "\nSaving Minio enviroment to credentials folder..."
+
+# Loads credentials into environment variables
+export MINIO_SA_TOKEN=$(kubectl -n minio-operator get secret console-sa-secret -o jsonpath="{.data.token}" | base64 -d)
+export MINIO_OSM_USERNAME=$(kubectl get secret ${MINIO_TENANT_NAME}-user-1 -n ${MINIO_TENANT_NAME} -o jsonpath='{.data.CONSOLE_ACCESS_KEY}' | base64 -d)
+export MINIO_OSM_PASSWORD=$(kubectl get secret ${MINIO_TENANT_NAME}-user-1 -n ${MINIO_TENANT_NAME} -o jsonpath='{.data.CONSOLE_SECRET_KEY}' | base64 -d)
+
+# Grants that all environment variables are defined
+export MINIO_INGRESS_CONSOLE_HOST=${MINIO_INGRESS_CONSOLE_HOST:-""}
+export MINIO_INGRESS_TENANT_HOST=${MINIO_INGRESS_TENANT_HOST:-""}
+
+# Saves locally to local environment at credentials folder
+cat << EOF > "${CREDENTIALS_DIR}/minio_environment.rc"
+# Minio credentials
+export MINIO_SA_TOKEN=${MINIO_SA_TOKEN}
+export MINIO_OSM_USERNAME=${MINIO_OSM_USERNAME}
+export MINIO_OSM_PASSWORD='${MINIO_OSM_PASSWORD}'
+
+# Minio Console endpoint(s)
+export MINIO_CONSOLE_URL=${MINIO_CONSOLE_URL}
+export MINIO_CONSOLE_HOST=${MINIO_CONSOLE_HOST}
+export MINIO_INTERNAL_CONSOLE_HOST=${MINIO_INTERNAL_CONSOLE_HOST}
+export MINIO_INGRESS_CONSOLE_HOST=${MINIO_INGRESS_CONSOLE_HOST}
+export MINIO_CONSOLE_HTTP_PORT=${MINIO_CONSOLE_HTTP_PORT}
+export MINIO_CONSOLE_HTTPS_PORT=${MINIO_CONSOLE_HTTPS_PORT}
+
+# Minio tenant endpoint(s)
+export MINIO_TENANT_URL=${MINIO_TENANT_URL}
+export MINIO_TENANT_HOST=${MINIO_TENANT_HOST}
+export MINIO_INTERNAL_TENANT_HOST=${MINIO_INTERNAL_TENANT_HOST}
+export MINIO_INGRESS_TENANT_HOST=${MINIO_INGRESS_TENANT_HOST}
+export MINIO_TENANT_HTTPS_PORT=${MINIO_TENANT_HTTPS_PORT}
+
+# Location of certificate and key for Minio's tenant enpoint
+export MINIO_TENANT_TLS_CERT='${MINIO_TENANT_TLS_CERT}'
+export MINIO_TENANT_TLS_KEY='${MINIO_TENANT_TLS_KEY}'
+EOF
diff --git a/installers/mgmt-cluster/minio/ALL-IN-ONE-Minio-install.sh b/installers/mgmt-cluster/minio/ALL-IN-ONE-Minio-install.sh
new file mode 100755 (executable)
index 0000000..c3f586e
--- /dev/null
@@ -0,0 +1,46 @@
+#!/bin/bash
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+set -e
+
+export HERE=$(dirname "$(readlink --canonicalize "$BASH_SOURCE")")
+source "${HERE}/library/functions.sh"
+source "${HERE}/library/trap.sh"
+
+
+############################################
+# Main script starts here
+############################################
+
+# Complete environment variables with sensible defaults, if needed
+source 00-base-config.rc
+
+# Install Minio operator
+./01-deploy-minio-operator.sh
+
+# Create Minio tenant
+./02-create-minio-tenant.sh
+
+# If applicable, deploy Ingress to provide external access
+./03-deploy-ingress-for-minio.sh
+
+# Retrieve URLs and credentials
+source 04-get-minio-connection-info.rc
+
+# Save credentials
+./05-export-connection-info.sh
diff --git a/installers/mgmt-cluster/minio/README.md b/installers/mgmt-cluster/minio/README.md
new file mode 100644 (file)
index 0000000..d32a26e
--- /dev/null
@@ -0,0 +1,215 @@
+<!--
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+implied.
+See the License for the specific language governing permissions and
+limitations under the License
+-->
+# How to install Minio
+
+- [How to install Minio](#how-to-install-minio)
+  - [0. Pre-requirements](#0-pre-requirements)
+  - [1. Installation](#1-installation)
+    - [1.1 Quickstart (recommended)](#11-quickstart-recommended)
+    - [1.2 Detailed procedure (useful for regenerating manifests with newer versions)](#12-detailed-procedure-useful-for-regenerating-manifests-with-newer-versions)
+    - [1.2.1 Minio Operator](#121-minio-operator)
+    - [2.1.2 Create a Minio Tenant](#212-create-a-minio-tenant)
+  - [3. Tests](#3-tests)
+    - [3.1 Access using Ingress (recommended)](#31-access-using-ingress-recommended)
+    - [3.2 Access using a port forward](#32-access-using-a-port-forward)
+    - [3.3 Tests from a container into the K8s cluster](#33-tests-from-a-container-into-the-k8s-cluster)
+  - [ANNEX A: How to set-up the local Minio CLI tools](#annex-a-how-to-set-up-the-local-minio-cli-tools)
+
+This procedure is based in the [Minio Operator guide](https://github.com/minio/operator/blob/master/README.md) and the [Guide to deploy a Deploy a MinIO Tenant](https://min.io/docs/minio/kubernetes/upstream/operations/install-deploy-manage/deploy-minio-tenant.html).
+
+## 0. Pre-requirements
+
+- Kubernetes cluster available.
+- Minio's `kubectl` plugin.
+- `mc` (Minio Client) tool installed.
+  - We will assume that the tool is renamed as `minioc` to avoid collisions with a pre-existing installation of the popular _Midnight Commander_.
+  - We will use the tool to validate that the installation has been successful.
+
+## 1. Installation
+
+### 1.1 Quickstart (recommended)
+
+```bash
+./ALL-IN-ONE-Minio-install.sh
+
+# (optional) To retrieve the environment variables
+source 00-base-config.rc
+source "${CREDENTIALS_DIR}/minio_environment.rc"
+```
+
+### 1.2 Detailed procedure (useful for regenerating manifests with newer versions)
+
+### 1.2.1 Minio Operator
+
+```bash
+VERSION=v5.0.11
+TIMEOUT=120 # By default is 27. Since sometimes connection may be slow, here we allow more time.
+kustomize build "github.com/minio/operator/resources/?timeout=${TIMEOUT}&ref=${VERSION}" > minio-operator.yaml
+
+# (optional) To allow deployments over single-node clusters
+yq -i 'del(.spec.template.spec.affinity)' minio-operator.yaml
+
+# Deploy
+kubectl apply -f minio-operator.yaml
+
+# Wait until completion
+kubectl rollout status deploy/minio-operator --namespace=minio-operator --watch --timeout=1h
+```
+
+Save SA token:
+
+```bash
+export MINIO_SA_TOKEN=$(kubectl -n minio-operator  get secret console-sa-secret -o jsonpath="{.data.token}" | base64 -d)
+```
+
+### 2.1.2 Create a Minio Tenant
+
+Deploy a tenant for OSM:
+
+```bash
+MINIO_TENANT_NAME=minio-osm-tenant
+MINIO_TENANT_CAPACITY=10Gi
+kubectl create ns ${MINIO_TENANT_NAME}
+kubectl minio tenant create                     \
+    ${MINIO_TENANT_NAME}                        \
+    --servers          4                        \
+    --volumes          8                        \
+    --capacity         ${MINIO_TENANT_CAPACITY} \
+    --namespace        ${MINIO_TENANT_NAME}     \
+    --storage-class    default                  \
+    --output > ${MINIO_TENANT_NAME}.yaml
+
+# Fix malformed manifest with wrong fields
+yq -i 'del(.spec.pools[0].volumeClaimTemplate.metadata.creationTimestamp)' ${MINIO_TENANT_NAME}.yaml
+
+kubectl apply -f ${MINIO_TENANT_NAME}.yaml
+```
+
+Save credentials:
+
+```bash
+export MINIO_OSM_USERNAME=$(kubectl get secret ${MINIO_TENANT_NAME}-user-1 -n ${MINIO_TENANT_NAME} -o jsonpath='{.data.CONSOLE_ACCESS_KEY}' | base64 -d)
+export MINIO_OSM_PASSWORD=$(kubectl get secret ${MINIO_TENANT_NAME}-user-1 -n ${MINIO_TENANT_NAME} -o jsonpath='{.data.CONSOLE_SECRET_KEY}' | base64 -d)
+```
+
+## 3. Tests
+
+### 3.1 Access using Ingress (recommended)
+
+Get the URL and the JWT token to access the Minio Operator Console with the browser:
+
+```bash
+# Open URL in browser using the JWT as access token
+echo "Console URL: ${MINIO_CONSOLE_URL}"
+echo -e "JWT token:\n${MINIO_SA_TOKEN}"
+```
+
+Then we can also test the tenant:
+
+```bash
+# Add alias to connect to the tenant
+ALIAS=osm
+echo "Minio Tenant URL: ${MINIO_TENANT_URL}"
+minioc alias set ${ALIAS} ${MINIO_TENANT_URL} ${MINIO_OSM_USERNAME} ${MINIO_OSM_PASSWORD} --insecure
+
+# Test
+minioc admin info ${ALIAS} --insecure
+
+# (optional) Delete the alias
+minioc alias remove ${ALIAS}
+```
+
+Note the use of the `--insecure` when the endpoint certificate is self-signed. **This will not be an issue from a container inside the cluster (using the internal DNS name) or when the certificate is signed by a CA**.
+
+### 3.2 Access using a port forward
+
+Access the Minio Operator Console:
+
+```bash
+# See SA Token, so that it can be used as JWT to access the Operator Console
+echo ${MINIO_SA_TOKEN}
+
+# Port forward to access from outside K8s
+kubectl port-forward svc/console -n minio-operator 9090:9090
+
+# Open in browser: http://localhost:9090
+```
+
+The we can test the health of the Minio tenant. First, we need to forward the port:
+
+```bash
+# Port forward to access from outside K8s
+kubectl port-forward svc/minio -n ${MINIO_TENANT_NAME} 4443:443
+```
+
+Then we test the tenant:
+
+```bash
+# Add alias to connect to the tenant
+ALIAS=osm
+MINIO_HOSTNAME=https://localhost:4443
+ACCESS_KEY=${MINIO_OSM_USERNAME}
+SECRET_KEY=${MINIO_OSM_PASSWORD}
+minioc alias set ${ALIAS} ${MINIO_HOSTNAME} ${ACCESS_KEY} ${SECRET_KEY} --insecure
+
+# Test
+minioc admin info ${ALIAS} --insecure
+
+# (optional) Delete the alias
+minioc alias remove ${ALIAS}
+```
+
+Note the use of the `--insecure`, since the endpoint certificate is not valid for a `localhost` endpoint. **This will not be an issue from a container inside the cluster**.
+
+### 3.3 Tests from a container into the K8s cluster
+
+Launch the container:
+
+```bash
+kubectl run -it --rm --image=alpine --env=ACCESS_KEY=${MINIO_OSM_USERNAME} --env=SECRET_KEY=${MINIO_OSM_PASSWORD} -- sh
+```
+
+Into the container:
+
+```bash
+# Install Minio client into the container
+apk add curl
+curl https://dl.min.io/client/mc/release/linux-amd64/mc -o minioc
+chmod +x minioc
+mv minioc /usr/local/bin/
+
+# Add alias to connect to the tenant
+ALIAS=osm
+MINIO_TENANT_NAME=minio-osm-tenant
+MINIO_HOSTNAME=https://minio.${MINIO_TENANT_NAME}
+minioc alias set ${ALIAS} ${MINIO_HOSTNAME} ${ACCESS_KEY} ${SECRET_KEY}
+
+# Test
+minioc admin info ${ALIAS}
+```
+
+## ANNEX A: How to set-up the local Minio CLI tools
+
+```bash
+# Minio kubectl plugin:
+curl https://github.com/minio/operator/releases/download/v5.0.12/kubectl-minio_5.0.12_linux_amd64 -Lo kubectl-minio
+chmod +x kubectl-minio
+sudo mv kubectl-minio /usr/local/bin/
+
+# Minio Client:
+curl https://dl.min.io/client/mc/release/linux-amd64/mc -o minioc
+chmod +x minioc
+sudo mv minioc /usr/local/bin/
+```
diff --git a/installers/mgmt-cluster/minio/ingress-manifests/console/ingress-console.yaml b/installers/mgmt-cluster/minio/ingress-manifests/console/ingress-console.yaml
new file mode 100644 (file)
index 0000000..5d3301e
--- /dev/null
@@ -0,0 +1,35 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  name: minio-console-ingress
+  namespace: minio-operator
+spec:
+  ingressClassName: nginx
+  rules:
+  - host: ${MINIO_INGRESS_CONSOLE_HOST}
+    http:
+      paths:
+      - path: /
+        pathType: Prefix
+        backend:
+          service:
+            name: console
+            port:
+              number: ${MINIO_CONSOLE_HTTP_PORT}
diff --git a/installers/mgmt-cluster/minio/ingress-manifests/tenant/ingress-tenant.yaml b/installers/mgmt-cluster/minio/ingress-manifests/tenant/ingress-tenant.yaml
new file mode 100644 (file)
index 0000000..bd1be7e
--- /dev/null
@@ -0,0 +1,45 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  name: minio-tenant-ingress
+  namespace: ${MINIO_TENANT_NAME}
+  annotations:
+    ## Comment if using a CA signed certificate
+    nginx.ingress.kubernetes.io/proxy-ssl-verify: "off"
+    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
+    nginx.ingress.kubernetes.io/rewrite-target: /
+    nginx.ingress.kubernetes.io/proxy-body-size: "0"
+spec:
+  ingressClassName: nginx
+  tls:
+  - hosts:
+      - ${MINIO_INGRESS_TENANT_HOST}
+    secretName: nginx-tls
+  rules:
+  - host: ${MINIO_INGRESS_TENANT_HOST}
+    http:
+      paths:
+      - path: /
+        pathType: Prefix
+        backend:
+          service:
+            name: minio
+            port:
+              number: ${MINIO_TENANT_HTTPS_PORT}
diff --git a/installers/mgmt-cluster/minio/library/functions.sh b/installers/mgmt-cluster/minio/library/functions.sh
new file mode 100755 (executable)
index 0000000..638a1d2
--- /dev/null
@@ -0,0 +1,91 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+BLUE='\033[0;34m'
+CYAN='\033[0;36m'
+RESET='\033[0m'
+
+# Colored messages (blue is the default)
+# Examples:
+#   m "hello world"
+#   m "hello world" "$GREEN"
+function m() {
+  local COLOR=${2:-$BLUE}
+  echo -e "$COLOR$1$RESET"
+}
+
+function copy_function() {
+  local ORIG_FUNC=$(declare -f $1)
+  local NEWNAME_FUNC="$2${ORIG_FUNC#$1}"
+  eval "$NEWNAME_FUNC"
+}
+
+function replace_text() {
+  local FILE=$1
+  local START=$2
+  local END=$3
+  local NEW=$4
+  local T=$(mktemp)
+  head -n $((START-1)) "$FILE" > "$T"
+  echo "$NEW" >> "$T"
+  tail -n +$((END+1)) "$FILE" >> "$T"
+  mv "$T" "$FILE"
+}
+
+function insert_text() {
+  local FILE=$1
+  local START=$2
+  local NEW=$3
+  local T=$(mktemp)
+  head -n $((START-1)) "$FILE" > "$T"
+  echo "$NEW" >> "$T"
+  tail -n +$START "$FILE" >> "$T"
+  mv "$T" "$FILE"
+}
+
+function remove_text() {
+  local FILE=$1
+  local START=$2
+  local END=$3
+  local T=$(mktemp)
+  head -n $((START-1)) "$FILE" > "$T"
+  tail -n +$((END+1)) "$FILE" >> "$T"
+  mv "$T" "$FILE"
+}
+
+function envsubst_cp() {
+  local FROM_FILE=$1
+  local TO_FILE=$2
+  mkdir --parents "$(dirname "$TO_FILE")"
+  cat "$FROM_FILE" | envsubst > "$TO_FILE"
+}
+
+function envsubst_dir() {
+  local FROM_DIR=$1
+  local TO_DIR=$2
+  rm --recursive --force "$TO_DIR"
+  mkdir --parents "$TO_DIR"
+  pushd "$FROM_DIR" > /dev/null
+  local F
+  find . -type f | while read F; do
+    envsubst_cp "$F" "$TO_DIR/$F"
+  done
+  popd > /dev/null
+}
diff --git a/installers/mgmt-cluster/minio/library/trap.sh b/installers/mgmt-cluster/minio/library/trap.sh
new file mode 100755 (executable)
index 0000000..2a1156d
--- /dev/null
@@ -0,0 +1,48 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+
+function goodbye() {
+  local DURATION=$(date --date=@$(( "$(date +%s)" - "$TRAP_START_TIME" )) --utc +%T)
+  local CODE=$1
+  cd "$TRAP_DIR"
+  if [ "$CODE" == 0 ]; then
+    m "$(realpath --relative-to="$HERE" "$0") succeeded! $DURATION" "$GREEN"
+  elif [ "$CODE" == abort ]; then
+    m "Aborted $(realpath --relative-to="$HERE" "$0")! $DURATION" "$RED"
+  else
+    m "Oh no! $(realpath --relative-to="$HERE" "$0") failed! $DURATION" "$RED"
+  fi
+}
+
+function trap_EXIT() {
+  local ERR=$?
+  goodbye "$ERR"
+  exit "$ERR"
+}
+
+function trap_INT() {
+  goodbye abort
+  trap - EXIT
+  exit 1
+}
+
+TRAP_DIR=$PWD
+TRAP_START_TIME=$(date +%s)
+
+trap trap_INT INT
+
+trap trap_EXIT EXIT
diff --git a/installers/mgmt-cluster/setup-cli-tools.sh b/installers/mgmt-cluster/setup-cli-tools.sh
new file mode 100755 (executable)
index 0000000..140d437
--- /dev/null
@@ -0,0 +1,45 @@
+#!/bin/bash
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+#
+
+# Install `gnupg` and `gpg` - Typically pre-installed in Ubuntu
+sudo apt-get install gnupg gpg
+
+# Install `sops`
+curl -LO https://github.com/getsops/sops/releases/download/v3.8.1/sops-v3.8.1.linux.amd64
+sudo mv sops-v3.8.1.linux.amd64 /usr/local/bin/sops
+sudo chmod +x /usr/local/bin/sops
+
+# Install `envsubst`
+sudo apt-get install gettext-base
+
+# Install `age`
+#   Ubuntu 22.04+:
+sudo apt-get install age
+
+# (Only for Gitea) Install `apg`
+sudo apt-get install apg
+
+# # (Only for Minio) `kubectl minio` plugin and Minio Client
+# curl https://github.com/minio/operator/releases/download/v5.0.12/kubectl-minio_5.0.12_linux_amd64 -Lo kubectl-minio
+# curl https://dl.min.io/client/mc/release/linux-amd64/mc -o minioc
+# chmod +x kubectl-minio minioc
+# sudo mv kubectl-minio minioc /usr/local/bin/
+# # (Only for HTTPS Ingress for Minio tenant) Install `openssl`
+# sudo apt-get install openssl
+
+# Flux client
+curl -s https://fluxcd.io/install.sh | sudo bash
+# Autocompletion
+. <(flux completion bash)