From b9b83d1fea881449ed0579dc8d76b77d24c4083c Mon Sep 17 00:00:00 2001 From: rblundon Date: Sun, 30 Mar 2025 15:44:27 -0500 Subject: [PATCH] Squashed 'acm-hub-bootstrap/' content from commit aea23ee git-subtree-dir: acm-hub-bootstrap git-subtree-split: aea23ee88fafd5cab0e2d9189f872159c5f16b8e --- .gitignore | 4 + README.md | 38 + bootstrap.sh | 45 + bootstrap/install-gitops/README.md | 1 + bootstrap/install-gitops/setup.sh | 58 + .../overlays/default/kustomization.yaml | 8 + bootstrap/secrets/base/README.md | 1 + .../secrets/base/hub-secrets-namespace.yaml | 4 + bootstrap/secrets/base/kustomization.yaml | 10 + bootstrap/secrets/base/namespace.yaml | 8 + .../apps/acm/overlays/hub/kustomization.yaml | 12 + .../custom-metrics-allowlist.yaml | 31 + .../observability/gitops-dashboard.json | 4212 +++++++++++++++++ .../overlays/observability/kustomization.yaml | 46 + components/clusters/base/kustomization.yaml | 3 + components/clusters/base/local-home.yaml | 18 + components/clusters/base/local-hub.yaml | 20 + .../cert-expiration/base/kustomization.yaml | 2 + .../base/policy-cert-expiration.yaml | 50 + .../compliance/base/kustomization.yaml | 2 + .../base/scan-nist-800-53-policy.yaml | 55 + .../gatekeeper/config-policy-namespace.yaml | 7 + .../gatekeeper-exclude-namespaces.yaml | 131 + .../gatekeeper/gatekeeper-install-policy.yaml | 139 + .../policies/gitops/base/kustomization.yaml | 8 + .../gitops/base/managedclustersetbinding.yaml | 7 + .../base/manifests/eso/base/secret-store.yaml | 39 + .../gitops-alerting/base/kustomization.yaml | 4 + .../base/prometheus-rules.yaml | 31 + .../gitops-bootstrap/base/bootstrap-app.yaml | 27 + .../base/bootstrap-appproject.yaml | 16 + .../gitops-bootstrap/base/kustomization.yaml | 3 + .../gitops-instance/base/argocd.yaml | 389 ++ .../gitops-instance/base/kustomization.yaml | 3 + .../base/setenv-cmp-plugin-cm.yaml | 19 + .../base/kustomization.yaml | 2 + .../base/notifications-cm.yaml | 256 + .../base/notifications-config.yaml | 540 +++ .../base/argocd-external-secret.yaml | 20 + .../gitops-secrets/base/kustomization.yaml | 3 + .../base/notifications-secret.yaml | 17 + .../base/cluster-admin-rolebinding.yaml | 12 + .../base/gitops-controller-rbac.yaml | 39 + .../base/gitops-server-rbac.yaml | 53 + .../base/kustomization.yaml | 8 + .../gitops-subscription/base/namespace.yaml | 6 + .../base/sub-namespace.yaml | 6 + .../base/sub-operatorgroup.yaml | 7 + .../base/subscription.yaml | 19 + .../policies/gitops/base/placement.yaml | 28 + .../gitops/base/policy-generator-config.yaml | 60 + .../opa/gatekeeper-probes-livenessnotset.yaml | 459 ++ .../gatekeeper-probes-readinessnotset.yaml | 459 ++ 53 files changed, 7445 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100755 bootstrap.sh create mode 100644 bootstrap/install-gitops/README.md create mode 100644 bootstrap/install-gitops/setup.sh create mode 100644 bootstrap/policies/overlays/default/kustomization.yaml create mode 100644 bootstrap/secrets/base/README.md create mode 100644 bootstrap/secrets/base/hub-secrets-namespace.yaml create mode 100644 bootstrap/secrets/base/kustomization.yaml create mode 100644 bootstrap/secrets/base/namespace.yaml create mode 100644 components/apps/acm/overlays/hub/kustomization.yaml create mode 100644 components/apps/acm/overlays/observability/custom-metrics-allowlist.yaml create mode 100644 components/apps/acm/overlays/observability/gitops-dashboard.json create mode 100644 components/apps/acm/overlays/observability/kustomization.yaml create mode 100644 components/clusters/base/kustomization.yaml create mode 100644 components/clusters/base/local-home.yaml create mode 100644 components/clusters/base/local-hub.yaml create mode 100644 components/policies/cert-expiration/base/kustomization.yaml create mode 100644 components/policies/cert-expiration/base/policy-cert-expiration.yaml create mode 100644 components/policies/compliance/base/kustomization.yaml create mode 100644 components/policies/compliance/base/scan-nist-800-53-policy.yaml create mode 100644 components/policies/gatekeeper/config-policy-namespace.yaml create mode 100644 components/policies/gatekeeper/gatekeeper-exclude-namespaces.yaml create mode 100644 components/policies/gatekeeper/gatekeeper-install-policy.yaml create mode 100644 components/policies/gitops/base/kustomization.yaml create mode 100644 components/policies/gitops/base/managedclustersetbinding.yaml create mode 100644 components/policies/gitops/base/manifests/eso/base/secret-store.yaml create mode 100644 components/policies/gitops/base/manifests/gitops-alerting/base/kustomization.yaml create mode 100644 components/policies/gitops/base/manifests/gitops-alerting/base/prometheus-rules.yaml create mode 100644 components/policies/gitops/base/manifests/gitops-bootstrap/base/bootstrap-app.yaml create mode 100644 components/policies/gitops/base/manifests/gitops-bootstrap/base/bootstrap-appproject.yaml create mode 100644 components/policies/gitops/base/manifests/gitops-bootstrap/base/kustomization.yaml create mode 100644 components/policies/gitops/base/manifests/gitops-instance/base/argocd.yaml create mode 100644 components/policies/gitops/base/manifests/gitops-instance/base/kustomization.yaml create mode 100644 components/policies/gitops/base/manifests/gitops-instance/base/setenv-cmp-plugin-cm.yaml create mode 100644 components/policies/gitops/base/manifests/gitops-notifications/base/kustomization.yaml create mode 100644 components/policies/gitops/base/manifests/gitops-notifications/base/notifications-cm.yaml create mode 100644 components/policies/gitops/base/manifests/gitops-notifications/base/notifications-config.yaml create mode 100644 components/policies/gitops/base/manifests/gitops-secrets/base/argocd-external-secret.yaml create mode 100644 components/policies/gitops/base/manifests/gitops-secrets/base/kustomization.yaml create mode 100644 components/policies/gitops/base/manifests/gitops-secrets/base/notifications-secret.yaml create mode 100644 components/policies/gitops/base/manifests/gitops-subscription/base/cluster-admin-rolebinding.yaml create mode 100644 components/policies/gitops/base/manifests/gitops-subscription/base/gitops-controller-rbac.yaml create mode 100644 components/policies/gitops/base/manifests/gitops-subscription/base/gitops-server-rbac.yaml create mode 100644 components/policies/gitops/base/manifests/gitops-subscription/base/kustomization.yaml create mode 100644 components/policies/gitops/base/manifests/gitops-subscription/base/namespace.yaml create mode 100644 components/policies/gitops/base/manifests/gitops-subscription/base/sub-namespace.yaml create mode 100644 components/policies/gitops/base/manifests/gitops-subscription/base/sub-operatorgroup.yaml create mode 100644 components/policies/gitops/base/manifests/gitops-subscription/base/subscription.yaml create mode 100644 components/policies/gitops/base/placement.yaml create mode 100644 components/policies/gitops/base/policy-generator-config.yaml create mode 100644 components/policies/opa/gatekeeper-probes-livenessnotset.yaml create mode 100644 components/policies/opa/gatekeeper-probes-readinessnotset.yaml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5c083b8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +sealed-secrets-key.yaml +slack-token-key.yaml +*-private.yaml +eso-token-*.yaml \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..ce0c676 --- /dev/null +++ b/README.md @@ -0,0 +1,38 @@ +### Introduction + +This repository is used to bootstrap the RHACM Hub cluster as well as hold the ACM configuration +I use in my homelab environment. It is referenced by the [cluster-config](https://github.com/gnunn-gitops/cluster-config) repo for the `local.hub` cluster's ACM applications (Hub, Policies and Observerability). + +From the perspective of bootstrapping the Hub there are a couple of different ways to go. You could +manually install OpenShift GitOps and have it bootstrap everything on the Hub including RHACM. However while +I did consider that approach I'm using ACM to bootstrap my managed clusters and I wanted to use the exact same workflow +if I could for the Hub. This is because I wanted to avoid having to create a tweaked workflow just for the Hub. + +### Bootstrap Process + +The bootstrap process, encapsulated in the `bootstrap.sh` script, is as follows: + +1. Install the RHACM operator and wait for it to complete +2. Install the MultiClusterHub custom resource and wait for it to be in the Running phase +3. Deploy all of the RHACM policies including the policy that deploys the OpenShift +GitOps operator with the bootstrap application +4. Label the Hub cluster, `local-cluster`, with the label `gitops=local.hub`. This trigger the +GitOps policy we deployed in step #3 to install OpenShift GitOps on the Hub cluster and +deploy the bootstrap application pointing to the repo and path needed for this cluster, i.e. +`local.home` + +At this point the GitOps operator deploys everything the Hub cluster requires including storage, operators, etc +as well as other ACM components. In particular, the components that the script deployed (Hub + Policies) have +Argo applications that will take over managing these. + +With the script bootstrapping the Hub because a one command affair. Once the command completes successfully +I walk away for 20-30 minutes while everything gets sorted out. + +### Side-note on LVM Operator + +If you are running a SNO cluster like I am and using the LVM Operator make sure that whatever device you are +using for storage with it is free. For example, if you are doing a reinstall of the hub (or other cluster), after +the cluster is provisioned but before you provision Day 2 ops ssh to the cluster and run `lsblk` to make sure +the device is empty with no partitions. + +A reminder for future me. :) \ No newline at end of file diff --git a/bootstrap.sh b/bootstrap.sh new file mode 100755 index 0000000..be9010f --- /dev/null +++ b/bootstrap.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +LANG=C +SLEEP_SECONDS=30 + +echo "" +echo "Installing RHACM Operator." + +kustomize build github.com/redhat-cop/gitops-catalog/advanced-cluster-management/operator/overlays/release-2.9 | oc apply -f - + +echo "Pause $SLEEP_SECONDS seconds for the creation of the rhacm-operator..." +sleep $SLEEP_SECONDS + +echo "Waiting for operator to start" +until oc get deployment multiclusterhub-operator -n open-cluster-management +do + sleep 10; +done + +echo "Installing the MultiClusterHub" + +kustomize build github.com/redhat-cop/gitops-catalog/advanced-cluster-management/instance/base | oc apply -f - + +echo "Waiting for hub to be installed" + +until [[ $(oc get multiclusterhub multiclusterhub -n open-cluster-management -o jsonpath='{.status.phase}') == 'Running' ]] +do + echo "Waiting for hub, current status:" + oc get multiclusterhub multiclusterhub -n open-cluster-management + sleep 10 +done + +echo "Installing policies and initial secrets" + +kustomize build bootstrap/secrets/base | oc apply -f - +kustomize build bootstrap/policies/overlays/default --enable-alpha-plugins | oc apply -f - + +echo "Labeling cluster with 'gitops: local.home'" +oc label managedcluster local-cluster gitops=local.hub --overwrite=true + +echo "Check policy compliance with the following command:" +echo " oc get policy -A" + +echo "Once GitOps configuration is complete you may need to run the following to fix Unknown status\n" +echo " oc delete secret local-cluster-import -n local-cluster\n" diff --git a/bootstrap/install-gitops/README.md b/bootstrap/install-gitops/README.md new file mode 100644 index 0000000..7346b2b --- /dev/null +++ b/bootstrap/install-gitops/README.md @@ -0,0 +1 @@ +Experimental, not used at the momentgit add \ No newline at end of file diff --git a/bootstrap/install-gitops/setup.sh b/bootstrap/install-gitops/setup.sh new file mode 100644 index 0000000..77a8973 --- /dev/null +++ b/bootstrap/install-gitops/setup.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +LANG=C +SLEEP_SECONDS=45 + +echo "" +echo "Installing GitOps Operator." + +kustomize build ../../components/policies/gitops/base/manifests/gitops-subscription | oc apply -f - + +echo "Pause $SLEEP_SECONDS seconds for the creation of the gitops-operator..." +sleep $SLEEP_SECONDS + +echo "Waiting for operator to start" +until oc get deployment gitops-operator-controller-manager -n openshift-operators +do + sleep 5; +done + +echo "Waiting for openshift-gitops namespace to be created" +until oc get ns openshift-gitops +do + sleep 5; +done + +echo "Waiting for deployments to start" +until oc get deployment cluster -n openshift-gitops +do + sleep 5; +done + +echo "Waiting for all pods to be created" +deployments=(cluster kam openshift-gitops-applicationset-controller openshift-gitops-redis openshift-gitops-repo-server openshift-gitops-server) +for i in "${deployments[@]}"; +do + echo "Waiting for deployment $i"; + oc rollout status deployment $i -n openshift-gitops +done + +echo "Apply overlay to override default instance" +# echo "Create default instance of gitops operator" +kustomize build ../../components/policies/gitops/base/manifests/gitops-instance/base | + yq -y ".spec.repo.env |= map(select(.name == \"INFRASTRUCTURE_ID\").value=\"$INFRASTRUCTURE_ID\")" | + yq -y ".spec.repo.env |= map(select(.name == \"CLUSTER_ID\").value=\"$CLUSTER_ID\")" | + yq -y ".spec.repo.env |= map(select(.name == \"CLUSTER_NAME\").value=\"$CLUSTER_NAME\")" | + yq -y ".spec.repo.env |= map(select(.name == \"SUB_DOMAIN\").value=\"$SUB_DOMAIN\")" | + oc apply -f - + +sleep 10 +echo "Waiting for all pods to redeploy" +deployments=(cluster kam openshift-gitops-applicationset-controller openshift-gitops-redis openshift-gitops-repo-server openshift-gitops-server) +for i in "${deployments[@]}"; +do + echo "Waiting for deployment $i"; + oc rollout status deployment $i -n openshift-gitops +done + +echo "GitOps Operator ready" \ No newline at end of file diff --git a/bootstrap/policies/overlays/default/kustomization.yaml b/bootstrap/policies/overlays/default/kustomization.yaml new file mode 100644 index 0000000..8159677 --- /dev/null +++ b/bootstrap/policies/overlays/default/kustomization.yaml @@ -0,0 +1,8 @@ +namespace: acm-policies + +namespace: acm-policies + +resources: +# - ../../../../components/policies/compliance/base +- ../../../../components/policies/cert-expiration/base +- ../../../../components/policies/gitops/base diff --git a/bootstrap/secrets/base/README.md b/bootstrap/secrets/base/README.md new file mode 100644 index 0000000..02dd1cc --- /dev/null +++ b/bootstrap/secrets/base/README.md @@ -0,0 +1 @@ +Bootstrap tokens for ESO to access Doppler projects, note that these secrets are not in git. \ No newline at end of file diff --git a/bootstrap/secrets/base/hub-secrets-namespace.yaml b/bootstrap/secrets/base/hub-secrets-namespace.yaml new file mode 100644 index 0000000..c27f512 --- /dev/null +++ b/bootstrap/secrets/base/hub-secrets-namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: hub-secrets diff --git a/bootstrap/secrets/base/kustomization.yaml b/bootstrap/secrets/base/kustomization.yaml new file mode 100644 index 0000000..4ccb786 --- /dev/null +++ b/bootstrap/secrets/base/kustomization.yaml @@ -0,0 +1,10 @@ +resources: +- namespace.yaml +- hub-secrets-namespace.yaml +# Note these secrets are not stored in git and only applied during bootstrap process +# They are the tokens for accessing the Doppler secrets SaaS service where secrets are stored +- eso-token-cluster-push-secret.yaml +- eso-token-cluster-home-secret.yaml +- eso-token-cluster-hub-secret.yaml +- eso-token-cluster-rhdp-secret.yaml +- eso-token-cluster-microshift-secret.yaml diff --git a/bootstrap/secrets/base/namespace.yaml b/bootstrap/secrets/base/namespace.yaml new file mode 100644 index 0000000..0d05982 --- /dev/null +++ b/bootstrap/secrets/base/namespace.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Namespace +metadata: + annotations: + openshift.io/description: ACM Policies + openshift.io/display-name: ACM Policies + labels: + name: acm-policies diff --git a/components/apps/acm/overlays/hub/kustomization.yaml b/components/apps/acm/overlays/hub/kustomization.yaml new file mode 100644 index 0000000..1ecabad --- /dev/null +++ b/components/apps/acm/overlays/hub/kustomization.yaml @@ -0,0 +1,12 @@ +resources: +- github.com/redhat-cop/gitops-catalog/advanced-cluster-management/operator/overlays/release-2.12 +- github.com/redhat-cop/gitops-catalog/advanced-cluster-management/instance/base + +patches: + - patch: |- + - op: replace + path: /spec/channel + value: 'release-2.13' + target: + kind: Subscription + name: advanced-cluster-management diff --git a/components/apps/acm/overlays/observability/custom-metrics-allowlist.yaml b/components/apps/acm/overlays/observability/custom-metrics-allowlist.yaml new file mode 100644 index 0000000..97a591f --- /dev/null +++ b/components/apps/acm/overlays/observability/custom-metrics-allowlist.yaml @@ -0,0 +1,31 @@ +kind: ConfigMap +apiVersion: v1 +metadata: + name: observability-metrics-custom-allowlist + namespace: open-cluster-management-observability +data: + metrics_list.yaml: | + names: + - argocd_cluster_info + - argocd-server-metrics + - argocd_app_info + - argocd_app_sync_total + - argocd_app_reconcile_count + - argocd_app_reconcile_bucket + - argocd_app_k8s_request_total + - argocd_kubectl_exec_pending + - argocd-metrics + - argocd_cluster_api_resource_objects + - argocd_cluster_api_resources + - argocd_cluster_events_total + - argocd_git_request_total + - argocd_git_request_duration_seconds_bucket + - argocd-repo-server + - argocd_redis_request_total + - process_start_time_seconds + - workqueue_depth + - go_memstats_heap_alloc_bytes + - process_cpu_seconds_total + - go_goroutines + - go_gc_duration_seconds + - grpc_server_handled_total \ No newline at end of file diff --git a/components/apps/acm/overlays/observability/gitops-dashboard.json b/components/apps/acm/overlays/observability/gitops-dashboard.json new file mode 100644 index 0000000..bc87db0 --- /dev/null +++ b/components/apps/acm/overlays/observability/gitops-dashboard.json @@ -0,0 +1,4212 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 1, + "iteration": 1605574886303, + "links": [], + "panels": [ + { + "collapsed": false, + "datasource": "$datasource", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 68, + "panels": [], + "title": "Overview", + "type": "row" + }, + { + "content": "![argoimage](https://avatars1.githubusercontent.com/u/30269780?s=110&v=4)", + "datasource": "$datasource", + "gridPos": { + "h": 4, + "w": 2, + "x": 0, + "y": 1 + }, + "id": 26, + "links": [], + "mode": "markdown", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "$datasource", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 2, + "y": 1 + }, + "id": 32, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "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": "count(count by (cluster) (argocd_cluster_info{namespace=~\"$namespace\",cluster=~\"$host\"}))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Clusters", + "description": "Number of clusters hosting Argo CD", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "0", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "$datasource", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 5, + "y": 1 + }, + "id": 94, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "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": "count(count by (cluster,namespace) (argocd_cluster_info{namespace=~\"$namespace\",cluster=~\"$host\"}))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Instances", + "description": "Total number of Argo CD instances", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "0", + "value": "null" + } + ], + "valueName": "current" + }, + { + "id": 23763571883, + "gridPos": { + "h": 4, + "w": 3, + "x": 8, + "y": 1 + }, + "type": "piechart", + "title": "Health Status", + "datasource": "$datasource", + "description": "Application Health Status", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "tooltip": false, + "viz": false, + "legend": false + } + }, + "color": { + "mode": "palette-classic" + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Degraded" + }, + "properties": [ + { + "id": "color", + "value": { + "mode": "fixed", + "fixedColor": "semi-dark-red" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Healthy" + }, + "properties": [ + { + "id": "color", + "value": { + "mode": "fixed", + "fixedColor": "green" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Progressing" + }, + "properties": [ + { + "id": "color", + "value": { + "mode": "fixed", + "fixedColor": "semi-dark-blue" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Missing" + }, + "properties": [ + { + "id": "color", + "value": { + "mode": "fixed", + "fixedColor": "semi-dark-orange" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unknown" + }, + "properties": [ + { + "id": "color", + "value": { + "mode": "fixed", + "fixedColor": "rgb(255, 255, 255)" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Suspended" + }, + "properties": [ + { + "id": "color", + "value": { + "mode": "fixed", + "fixedColor": "semi-dark-purple" + } + } + ] + } + ] + }, + "options": { + "reduceOptions": { + "values": false, + "calcs": [ + "lastNotNull" + ], + "fields": "" + }, + "pieType": "donut", + "displayLabels": [], + "tooltip": { + "mode": "single" + }, + "legend": { + "displayMode": "hidden", + "placement": "bottom" + } + }, + "targets": [ + { + "exemplar": true, + "expr": "sum(argocd_app_info{namespace=~\"$namespace\",dest_server=~\"$cluster\",health_status=~\"$health_status\",sync_status=~\"$sync_status\",health_status!=\"\",cluster=~\"$host\"}) by (health_status)", + "interval": "", + "legendFormat": "{{health_status}}", + "refId": "A" + } + ] + }, + { + "id": 23763571995, + "gridPos": { + "h": 4, + "w": 3, + "x": 11, + "y": 1 + }, + "type": "piechart", + "title": "Sync Status", + "datasource": "$datasource", + "description": "Application Sync Status", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "tooltip": false, + "viz": false, + "legend": false + } + }, + "color": { + "mode": "palette-classic" + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Unknown" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "rgb(255, 255, 255)", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Synced" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "OutOfSync" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "semi-dark-yellow", + "mode": "fixed" + } + } + ] + } + ] + }, + "options": { + "reduceOptions": { + "values": false, + "calcs": [ + "lastNotNull" + ], + "fields": "" + }, + "pieType": "donut", + "displayLabels": [], + "tooltip": { + "mode": "single" + }, + "legend": { + "displayMode": "hidden", + "placement": "bottom" + } + }, + "targets": [ + { + "exemplar": true, + "expr": "sum(argocd_app_info{namespace=~\"$namespace\",dest_server=~\"$cluster\",health_status=~\"$health_status\",sync_status=~\"$sync_status\",health_status!=\"\",cluster=~\"$host\"}) by (sync_status)", + "interval": "", + "legendFormat": "{{sync_status}}", + "refId": "A" + } + ] + }, + { + "cacheTimeout": null, + "datasource": "$datasource", + "gridPos": { + "h": 4, + "w": 3, + "x": 14, + "y": 1 + }, + "id": 100, + "links": [], + "options": { + "fieldOptions": { + "calcs": [ + "lastNotNull" + ], + "defaults": { + "mappings": [ + { + "id": 0, + "op": "=", + "text": "0", + "type": 1, + "value": "null" + } + ], + "max": 100, + "min": 0, + "nullValueMode": "connected", + "thresholds": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ], + "unit": "none" + }, + "override": {}, + "overrides": [], + "values": false + }, + "orientation": "horizontal", + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "6.5.2", + "repeatDirection": "h", + "targets": [ + { + "expr": "sum(argocd_app_info{namespace=~\"$namespace\",dest_server=~\"$cluster\",operation!=\"\",cluster=~\"$host\"})", + "format": "time_series", + "instant": true, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Operations", + "type": "gauge" + }, + { + "aliasColors": {}, + "bars": false, + "cacheTimeout": null, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "decimals": null, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 4, + "w": 7, + "x": 17, + "y": 1 + }, + "hiddenSeries": false, + "id": 28, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "paceLength": 10, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(argocd_app_info{namespace=~\"$namespace\",dest_server=~\"$cluster\",health_status=~\"$health_status\",sync_status=~\"$sync_status\",cluster=~\"$host\"}) by (cluster)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{cluster}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Applications", + "description": "Applications by host", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "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": true, + "datasource": "$datasource", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 5 + }, + "id": 77, + "panels": [ + { + "id": 23763571776, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 6 + }, + "type": "timeseries", + "title": "Health Status", + "datasource": "$datasource", + "pluginVersion": "8.5.20", + "links": [], + "cacheTimeout": null, + "interval": "", + "targets": [ + { + "expr": "sum(argocd_app_info{namespace=~\"$namespace\",dest_server=~\"$cluster\",health_status=~\"$health_status\",sync_status=~\"$sync_status\",health_status!=\"\",cluster=~\"$host\"}) by (cluster,namespace,health_status)", + "legendFormat": "{{health_status}} ({{cluster}}/{{namespace}})", + "interval": "", + "exemplar": true, + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "fieldConfig": { + "defaults": { + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "barAlignment": 0, + "lineWidth": 1, + "fillOpacity": 10, + "gradientMode": "none", + "spanNulls": false, + "showPoints": "never", + "pointSize": 5, + "stacking": { + "mode": "none", + "group": "A" + }, + "axisPlacement": "auto", + "axisLabel": "", + "scaleDistribution": { + "type": "linear" + }, + "hideFrom": { + "tooltip": false, + "viz": false, + "legend": false + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "color": { + "mode": "palette-classic" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + }, + { + "value": 80, + "color": "red" + } + ] + }, + "mappings": [], + "links": [], + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "Healthy.*" + }, + "properties": [ + { + "id": "color", + "value": { + "mode": "fixed", + "fixedColor": "green" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "Degraded.*" + }, + "properties": [ + { + "id": "color", + "value": { + "mode": "fixed", + "fixedColor": "semi-dark-red" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "Missing.*" + }, + "properties": [ + { + "id": "color", + "value": { + "mode": "fixed", + "fixedColor": "semi-dark-orange" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "Progressing.*" + }, + "properties": [ + { + "id": "color", + "value": { + "mode": "fixed", + "fixedColor": "semi-dark-blue" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "Suspended.*" + }, + "properties": [ + { + "id": "color", + "value": { + "mode": "fixed", + "fixedColor": "semi-dark-purple" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "Unknown.*" + }, + "properties": [ + { + "id": "color", + "value": { + "mode": "fixed", + "fixedColor": "rgb(255, 255, 255)" + } + } + ] + } + ] + }, + "options": { + "tooltip": { + "mode": "single" + }, + "legend": { + "displayMode": "table", + "placement": "right", + "calcs": [ + "lastNotNull" + ] + } + } + }, + { + "id": 23763571993, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 6 + }, + "type": "timeseries", + "title": "Sync Status", + "datasource": "$datasource", + "pluginVersion": "8.5.20", + "links": [], + "cacheTimeout": null, + "interval": "", + "targets": [ + { + "expr": "sum(argocd_app_info{namespace=~\"$namespace\",dest_server=~\"$cluster\",health_status=~\"$health_status\",sync_status=~\"$sync_status\",health_status!=\"\",cluster=~\"$host\"}) by (cluster,namespace,sync_status)", + "legendFormat": "{{sync_status}} ({{cluster}}/{{namespace}})", + "interval": "", + "exemplar": true, + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "fieldConfig": { + "defaults": { + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "barAlignment": 0, + "lineWidth": 1, + "fillOpacity": 10, + "gradientMode": "none", + "spanNulls": false, + "showPoints": "never", + "pointSize": 5, + "stacking": { + "mode": "none", + "group": "A" + }, + "axisPlacement": "auto", + "axisLabel": "", + "scaleDistribution": { + "type": "linear" + }, + "hideFrom": { + "tooltip": false, + "viz": false, + "legend": false + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "color": { + "mode": "palette-classic" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + }, + { + "value": 80, + "color": "red" + } + ] + }, + "mappings": [], + "links": [], + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "OutOfSync.*" + }, + "properties": [ + { + "id": "color", + "value": { + "mode": "fixed", + "fixedColor": "semi-dark-yellow" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "Synced.*" + }, + "properties": [ + { + "id": "color", + "value": { + "mode": "fixed", + "fixedColor": "semi-dark-green" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "Unknown.*" + }, + "properties": [ + { + "id": "color", + "value": { + "mode": "fixed", + "fixedColor": "rgb(255, 255, 255)" + } + } + ] + } + ] + }, + "options": { + "tooltip": { + "mode": "single" + }, + "legend": { + "displayMode": "table", + "placement": "right", + "calcs": [ + "lastNotNull" + ] + } + } + } + ], + "title": "Application Status", + "type": "row" + }, + { + "collapsed": true, + "datasource": "$datasource", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 104, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "decimals": null, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 3 + }, + "hiddenSeries": false, + "id": 56, + "interval": "", + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sort": "total", + "sortDesc": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "paceLength": 10, + "percentage": false, + "pointradius": 1, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "sum(round(increase(argocd_app_sync_total{namespace=~\"$namespace\",dest_server=~\"$cluster\",cluster=~\"$host\"}[$interval]))) by ($grouping)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{$grouping}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Sync Activity", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "decimals": -12, + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "decimals": null, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 9 + }, + "hiddenSeries": false, + "id": 73, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sort": "total", + "sortDesc": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "paceLength": 10, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(round(increase(argocd_app_sync_total{namespace=~\"$namespace\",phase=~\"Error|Failed\",dest_server=~\"$cluster\",cluster=~\"$host\"}[$interval]))) by ($grouping, phase)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{phase}}: {{$grouping}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Sync Failures", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "none", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "title": "Sync Stats", + "type": "row" + }, + { + "collapsed": true, + "datasource": "$datasource", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 7 + }, + "id": 64, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 12 + }, + "hiddenSeries": false, + "id": 58, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sort": "total", + "sortDesc": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "paceLength": 10, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(increase(argocd_app_reconcile_count{namespace=~\"$namespace\",dest_server=~\"$cluster\",cluster=~\"$host\"}[$interval])) by ($grouping)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{$grouping}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Reconciliation Activity", + "tooltip": { + "shared": false, + "sort": 2, + "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 + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateSpectral", + "exponent": 0.5, + "min": null, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "$datasource", + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 18 + }, + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "id": 60, + "legend": { + "show": true + }, + "links": [], + "options": {}, + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(increase(argocd_app_reconcile_bucket{namespace=~\"$namespace\",cluster=~\"$host\"}[$interval])) by (le)", + "format": "heatmap", + "instant": false, + "intervalFactor": 10, + "legendFormat": "{{le}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Reconciliation Performance", + "tooltip": { + "show": true, + "showHistogram": true + }, + "tooltipDecimals": 0, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 25 + }, + "hiddenSeries": false, + "id": 80, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "options": { + "dataLinks": [] + }, + "paceLength": 10, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(increase(argocd_app_k8s_request_total{namespace=~\"$namespace\",server=~\"$cluster\",cluster=~\"$host\"}[$interval])) by (verb, resource_kind)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{verb}} {{resource_kind}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "K8s API Activity", + "tooltip": { + "shared": true, + "sort": 2, + "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": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 31 + }, + "hiddenSeries": false, + "id": 96, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideZero": true, + "max": true, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(workqueue_depth{namespace=~\"$namespace\",name=~\"app_.*\",cluster=~\"$host\"}) by (name)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{name}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Workqueue Depth", + "tooltip": { + "shared": true, + "sort": 2, + "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": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "decimals": null, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 31 + }, + "hiddenSeries": false, + "id": 98, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideZero": false, + "max": true, + "min": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(argocd_kubectl_exec_pending{namespace=~\"$namespace\",cluster=~\"$host\"}) by (command)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{command}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pending kubectl run", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "decimals": 0, + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "title": "Controller Stats", + "type": "row" + }, + { + "collapsed": true, + "datasource": "$datasource", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 8 + }, + "id": 102, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 26 + }, + "hiddenSeries": false, + "id": 34, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_memstats_heap_alloc_bytes{container=\"argocd-application-controller\",namespace=~\"$namespace\",cluster=~\"$host\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{cluster}}/{{namespace}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory Usage", + "tooltip": { + "shared": false, + "sort": 2, + "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": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 33 + }, + "hiddenSeries": false, + "id": 108, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sort": "avg", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(process_cpu_seconds_total{container=\"argocd-application-controller\",namespace=~\"$namespace\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{cluster}}/{{namespace}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU Usage", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "none", + "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": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 40 + }, + "hiddenSeries": false, + "id": 62, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{container=\"argocd-application-controller\",namespace=~\"$namespace\",cluster=~\"$host\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{cluster}}/{{namespace}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": false, + "sort": 2, + "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 + } + } + ], + "title": "Controller Telemetry", + "type": "row" + }, + { + "collapsed": true, + "datasource": "$datasource", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 9 + }, + "id": 88, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 27 + }, + "hiddenSeries": false, + "id": 90, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(argocd_cluster_api_resource_objects{namespace=~\"$namespace\",server=~\"$cluster\",cluster=~\"$host\"}) by (server)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{server}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Resource Objects Count", + "tooltip": { + "shared": false, + "sort": 2, + "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": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 34 + }, + "hiddenSeries": false, + "id": 92, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": " sum(argocd_cluster_api_resources{namespace=~\"$namespace\",server=~\"$cluster\",cluster=~\"$host\"}) by (server)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{server}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "API Resources Count", + "tooltip": { + "shared": false, + "sort": 2, + "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": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 40 + }, + "hiddenSeries": false, + "id": 86, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(increase(argocd_cluster_events_total{namespace=~\"$namespace\",server=~\"$cluster\",cluster=~\"$host\"}[$interval])) by (server)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{server}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Cluster Events Count", + "tooltip": { + "shared": false, + "sort": 2, + "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 + } + } + ], + "title": "Destination Stats", + "type": "row" + }, + { + "collapsed": true, + "datasource": "$datasource", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 70, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 7 + }, + "hiddenSeries": false, + "id": 82, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(increase(argocd_git_request_total{request_type=\"ls-remote\", namespace=~\"$namespace\",cluster=~\"$host\"}[10m])) by (namespace)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{namespace}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Git Requests (ls-remote)", + "tooltip": { + "shared": true, + "sort": 2, + "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": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 7 + }, + "hiddenSeries": false, + "id": 84, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(increase(argocd_git_request_total{request_type=\"fetch\", namespace=~\"$namespace\",cluster=~\"$host\"}[$__rate_interval])) by (namespace)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{namespace}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Git Requests (checkout)", + "tooltip": { + "shared": true, + "sort": 2, + "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 + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateSpectral", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "$datasource", + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 15 + }, + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "id": 114, + "legend": { + "show": false + }, + "options": {}, + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(increase(argocd_git_request_duration_seconds_bucket{request_type=\"fetch\", namespace=~\"$namespace\",cluster=~\"$host\"}[$__rate_interval])) by (le)", + "format": "heatmap", + "intervalFactor": 10, + "legendFormat": "{{le}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Git Fetch Performance", + "tooltip": { + "show": true, + "showHistogram": false + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateSpectral", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "$datasource", + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 15 + }, + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "id": 116, + "legend": { + "show": false + }, + "options": {}, + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(increase(argocd_git_request_duration_seconds_bucket{request_type=\"ls-remote\", namespace=~\"$namespace\",cluster=~\"$host\"}[$__rate_interval])) by (le)", + "format": "heatmap", + "intervalFactor": 10, + "legendFormat": "{{le}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Git Ls-Remote Performance", + "tooltip": { + "show": true, + "showHistogram": false + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 23 + }, + "hiddenSeries": false, + "id": 71, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_memstats_heap_alloc_bytes{container=\"argocd-repo-server\",namespace=~\"$namespace\",cluster=~\"$host\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory Used", + "tooltip": { + "shared": true, + "sort": 2, + "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": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 31 + }, + "hiddenSeries": false, + "id": 72, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{container=\"argocd-repo-server\",namespace=~\"$namespace\",cluster=~\"$host\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 2, + "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 + } + } + ], + "title": "Repo Server Stats", + "type": "row" + }, + { + "collapsed": true, + "datasource": "$datasource", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 66, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 89 + }, + "id": 61, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_memstats_heap_alloc_bytes{container=\"argocd-server\",namespace=~\"$namespace\",cluster=~\"$host\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory Used", + "tooltip": { + "shared": true, + "sort": 2, + "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": "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": "$datasource", + "fill": 1, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 97 + }, + "id": 36, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{container=\"argocd-server\",namespace=~\"$namespace\",cluster=~\"$host\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 2, + "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": "$datasource", + "fill": 1, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 106 + }, + "id": 38, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_gc_duration_seconds{container=\"argocd-server\", quantile=\"1\", namespace=~\"$namespace\",cluster=~\"$host\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "GC Time Quantiles", + "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 + } + }, + { + "content": "#### gRPC Services:", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 115 + }, + "id": 54, + "links": [], + "mode": "markdown", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "decimals": null, + "fill": 1, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 117 + }, + "id": 40, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sort": "total", + "sortDesc": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(increase(grpc_server_handled_total{container=\"argocd-server\",grpc_service=\"application.ApplicationService\",namespace=~\"$namespace\",cluster=~\"$host\"}[$__rate_interval])) by (grpc_code, grpc_method)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{grpc_code}},{{grpc_method}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "ApplicationService Requests", + "tooltip": { + "shared": false, + "sort": 2, + "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": "$datasource", + "fill": 1, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 117 + }, + "id": 42, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(increase(grpc_server_handled_total{container=\"argocd-server\",grpc_service=\"cluster.ClusterService\",namespace=~\"$namespace\",cluster=~\"$host\"}[$__rate_interval])) by (grpc_code, grpc_method)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{grpc_code}},{{grpc_method}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "ClusterService Requests", + "tooltip": { + "shared": false, + "sort": 2, + "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": "$datasource", + "fill": 1, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 126 + }, + "id": 44, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(increase(grpc_server_handled_total{container=\"argocd-server\",grpc_service=\"project.ProjectService\",namespace=~\"$namespace\",cluster=~\"$host\"}[$__rate_interval])) by (grpc_code, grpc_method)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{grpc_code}},{{grpc_method}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "ProjectService Requests", + "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": "$datasource", + "fill": 1, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 126 + }, + "id": 46, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(increase(grpc_server_handled_total{container=\"argocd-server\",grpc_service=\"repository.RepositoryService\",namespace=~\"$namespace\",cluster=~\"$host\"}[$__rate_interval])) by (grpc_code, grpc_method)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{grpc_code}},{{grpc_method}}", + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "yaxis": "left" + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "RepositoryService Requests", + "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": "$datasource", + "fill": 1, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 135 + }, + "id": 48, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(increase(grpc_server_handled_total{container=\"argocd-server\",grpc_service=\"session.SessionService\",namespace=~\"$namespace\",cluster=~\"$host\"}[$__rate_interval])) by (grpc_code, grpc_method)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{grpc_code}},{{grpc_method}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SessionService Requests", + "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": "$datasource", + "fill": 1, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 135 + }, + "id": 49, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(increase(grpc_server_handled_total{container=\"argocd-server\",grpc_service=\"version.VersionService\",namespace=~\"$namespace\",cluster=~\"$host\"}[$__rate_interval])) by (grpc_code, grpc_method)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{grpc_code}},{{grpc_method}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "VersionService Requests", + "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": "$datasource", + "fill": 1, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 144 + }, + "id": 50, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(increase(grpc_server_handled_total{container=\"argocd-server\",grpc_service=\"account.AccountService\",namespace=~\"$namespace\",cluster=~\"$host\"}[$__rate_interval])) by (grpc_code, grpc_method)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{grpc_code}},{{grpc_method}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "AccountService Requests", + "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": "$datasource", + "fill": 1, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 144 + }, + "id": 99, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(increase(grpc_server_handled_total{container=\"argocd-server\",grpc_service=\"settings.SettingsService\",namespace=~\"$namespace\",cluster=~\"$host\"}[$__rate_interval])) by (grpc_code, grpc_method)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{grpc_code}},{{grpc_method}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SettingsService Requests", + "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 + } + } + ], + "title": "Server Stats", + "type": "row" + }, + { + "collapsed": true, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 12 + }, + "id": 110, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 9 + }, + "hiddenSeries": false, + "id": 112, + "legend": { + "avg": false, + "current": 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(increase(argocd_redis_request_total{namespace=~\"$namespace\",cluster=~\"$host\"}[$__rate_interval])) by (failed)", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Requests by result", + "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 + } + } + ], + "title": "Redis Stats", + "type": "row" + } + ], + "refresh": false, + "schemaVersion": 21, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "datasource", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "allValue": ".*", + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "$datasource", + "definition": "label_values(argocd_cluster_info, cluster)", + "hide": 0, + "includeAll": true, + "label": "cluster", + "multi": false, + "name": "host", + "options": [], + "query": "label_values(argocd_cluster_info, cluster)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "$datasource", + "definition": "label_values(kube_pod_info, namespace)", + "hide": 0, + "includeAll": true, + "label": null, + "multi": false, + "name": "namespace", + "options": [], + "query": "label_values(kube_pod_info, namespace)", + "refresh": 1, + "regex": ".*argocd.*", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "auto": true, + "auto_count": 30, + "auto_min": "1m", + "current": { + "selected": false, + "text": "auto", + "value": "$__auto_interval_interval" + }, + "hide": 0, + "label": null, + "name": "interval", + "options": [ + { + "selected": true, + "text": "auto", + "value": "$__auto_interval_interval" + }, + { + "selected": false, + "text": "1m", + "value": "1m" + }, + { + "selected": false, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "10m", + "value": "10m" + }, + { + "selected": false, + "text": "30m", + "value": "30m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "2h", + "value": "2h" + }, + { + "selected": false, + "text": "4h", + "value": "4h" + }, + { + "selected": false, + "text": "8h", + "value": "8h" + } + ], + "query": "1m,5m,10m,30m,1h,2h,4h,8h", + "refresh": 2, + "skipUrlSync": false, + "type": "interval" + }, + { + "allValue": "", + "current": { + "selected": true, + "text": "namespace", + "value": "namespace" + }, + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "grouping", + "options": [ + { + "selected": true, + "text": "namespace", + "value": "namespace" + }, + { + "selected": false, + "text": "name", + "value": "name" + }, + { + "selected": false, + "text": "project", + "value": "project" + } + ], + "query": "namespace,name,project", + "skipUrlSync": false, + "type": "custom" + }, + { + "allValue": ".*", + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "$datasource", + "definition": "label_values(argocd_cluster_info, server)", + "hide": 0, + "includeAll": true, + "label": "destination", + "multi": false, + "name": "cluster", + "options": [], + "query": "label_values(argocd_cluster_info, server)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": { + "selected": true, + "text": "All", + "value": "$__all" + }, + "hide": 0, + "includeAll": true, + "label": null, + "multi": false, + "name": "health_status", + "options": [ + { + "selected": true, + "text": "All", + "value": "$__all" + }, + { + "selected": false, + "text": "Healthy", + "value": "Healthy" + }, + { + "selected": false, + "text": "Progressing", + "value": "Progressing" + }, + { + "selected": false, + "text": "Suspended", + "value": "Suspended" + }, + { + "selected": false, + "text": "Missing", + "value": "Missing" + }, + { + "selected": false, + "text": "Degraded", + "value": "Degraded" + }, + { + "selected": false, + "text": "Unknown", + "value": "Unknown" + } + ], + "query": "Healthy,Progressing,Suspended,Missing,Degraded,Unknown", + "skipUrlSync": false, + "type": "custom" + }, + { + "allValue": ".*", + "current": { + "selected": true, + "text": "All", + "value": "$__all" + }, + "hide": 0, + "includeAll": true, + "label": null, + "multi": false, + "name": "sync_status", + "options": [ + { + "selected": true, + "text": "All", + "value": "$__all" + }, + { + "selected": false, + "text": "Synced", + "value": "Synced" + }, + { + "selected": false, + "text": "OutOfSync", + "value": "OutOfSync" + }, + { + "selected": false, + "text": "Unknown", + "value": "Unknown" + } + ], + "query": "Synced,OutOfSync,Unknown", + "skipUrlSync": false, + "type": "custom" + } + ] + }, + "time": { + "from": "now-30m", + "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": "GitOps", + "uid": "LCAgc9rWz", + "version": 1 +} diff --git a/components/apps/acm/overlays/observability/kustomization.yaml b/components/apps/acm/overlays/observability/kustomization.yaml new file mode 100644 index 0000000..b7aaf10 --- /dev/null +++ b/components/apps/acm/overlays/observability/kustomization.yaml @@ -0,0 +1,46 @@ +namespace: open-cluster-management-observability + +generatorOptions: + disableNameSuffixHash: true + labels: + grafana-custom-dashboard: "true" + +resources: +- github.com/redhat-cop/gitops-catalog/advanced-cluster-management/instance/observability +- custom-metrics-allowlist.yaml + +configMapGenerator: +- name: gitops-dashboard + files: + - gitops.json=gitops-dashboard.json + +patches: + - patch: |- + - op: replace + path: /spec/storageConfig/storageClass + value: lvms-vg1 + - op: replace + path: /spec/observabilityAddonSpec/interval + value: 60 + - op: add + path: /spec/advanced + value: + alertmanager: + replicas: 1 + grafana: + replicas: 1 + observatoriumAPI: + replicas: 1 + query: + replicas: 1 + queryFrontend: + replicas: 1 + queryFrontendMemcached: + replicas: 1 + rbacQueryProxy: + replicas: 1 + receive: + replicas: 1 + target: + kind: MultiClusterObservability + name: observability diff --git a/components/clusters/base/kustomization.yaml b/components/clusters/base/kustomization.yaml new file mode 100644 index 0000000..e6961ed --- /dev/null +++ b/components/clusters/base/kustomization.yaml @@ -0,0 +1,3 @@ +resources: +- local-home.yaml +- local-hub.yaml diff --git a/components/clusters/base/local-home.yaml b/components/clusters/base/local-home.yaml new file mode 100644 index 0000000..7df0334 --- /dev/null +++ b/components/clusters/base/local-home.yaml @@ -0,0 +1,18 @@ +apiVersion: cluster.open-cluster-management.io/v1 +kind: ManagedCluster +metadata: + annotations: + open-cluster-management/created-via: other + labels: + cloud: Other + cluster.open-cluster-management.io/clusterset: dev + gitops: local.home + color: "0066CC" + name: home + vendor: OpenShift + name: home +spec: + hubAcceptsClient: true + leaseDurationSeconds: 60 + managedClusterClientConfigs: + - url: https://api.home.ocplab.com:6443 diff --git a/components/clusters/base/local-hub.yaml b/components/clusters/base/local-hub.yaml new file mode 100644 index 0000000..fd66fb7 --- /dev/null +++ b/components/clusters/base/local-hub.yaml @@ -0,0 +1,20 @@ +apiVersion: cluster.open-cluster-management.io/v1 +kind: ManagedCluster +metadata: + annotations: + open-cluster-management/created-via: other + labels: + cloud: Other + cluster.open-cluster-management.io/clusterset: default + gitops: local.hub + color: "3E8635" + local-cluster: "true" + name: local-cluster + velero.io/exclude-from-backup: "true" + vendor: OpenShift + name: local-cluster +spec: + hubAcceptsClient: true + leaseDurationSeconds: 60 + managedClusterClientConfigs: + - url: https://api.hub.ocplab.com:6443 diff --git a/components/policies/cert-expiration/base/kustomization.yaml b/components/policies/cert-expiration/base/kustomization.yaml new file mode 100644 index 0000000..467f048 --- /dev/null +++ b/components/policies/cert-expiration/base/kustomization.yaml @@ -0,0 +1,2 @@ +resources: +- policy-cert-expiration.yaml \ No newline at end of file diff --git a/components/policies/cert-expiration/base/policy-cert-expiration.yaml b/components/policies/cert-expiration/base/policy-cert-expiration.yaml new file mode 100644 index 0000000..153a2e4 --- /dev/null +++ b/components/policies/cert-expiration/base/policy-cert-expiration.yaml @@ -0,0 +1,50 @@ +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: certificate-expiration + annotations: + policy.open-cluster-management.io/categories: SC System and Communications Protection + policy.open-cluster-management.io/standards: NIST SP 800-53 + policy.open-cluster-management.io/controls: SC-8 Transmission Confidentiality and Integrity +spec: + disabled: false + remediationAction: inform + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: CertificatePolicy + metadata: + name: policy-certificate + spec: + namespaceSelector: + include: + - default + exclude: + - kube-* + remediationAction: inform + severity: low + minimumDuration: 300h +--- +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: certificate-expiration-placement +spec: + clusterSelector: + matchExpressions: [] + clusterConditions: + - status: "True" + type: ManagedClusterConditionAvailable +--- +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: certificate-expiration-placement +placementRef: + name: certificate-expiration-placement + apiGroup: apps.open-cluster-management.io + kind: PlacementRule +subjects: + - name: certificate-expiration + apiGroup: policy.open-cluster-management.io + kind: Policy \ No newline at end of file diff --git a/components/policies/compliance/base/kustomization.yaml b/components/policies/compliance/base/kustomization.yaml new file mode 100644 index 0000000..08ecde2 --- /dev/null +++ b/components/policies/compliance/base/kustomization.yaml @@ -0,0 +1,2 @@ +resources: +- scan-nist-800-53-policy.yaml \ No newline at end of file diff --git a/components/policies/compliance/base/scan-nist-800-53-policy.yaml b/components/policies/compliance/base/scan-nist-800-53-policy.yaml new file mode 100644 index 0000000..5b1efd2 --- /dev/null +++ b/components/policies/compliance/base/scan-nist-800-53-policy.yaml @@ -0,0 +1,55 @@ +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: scan-nist-800-53 + annotations: + policy.open-cluster-management.io/standards: NIST-CSF + policy.open-cluster-management.io/categories: PR.IP Information Protection Processes and Procedures + policy.open-cluster-management.io/controls: PR.IP-1 Baseline Configuration +spec: + remediationAction: enforce + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: scan-nist-800-53 + spec: + remediationAction: inform + severity: high + object-templates: + - complianceType: mustnothave + objectDefinition: + apiVersion: compliance.openshift.io/v1alpha1 + kind: ComplianceCheckResult + metadata: + namespace: openshift-compliance + labels: + compliance.openshift.io/check-status: FAIL + compliance.openshift.io/suite: cis-compliance +--- +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: binding-scan-nist-800-53 +placementRef: + name: placement-scan-nist-800-53 + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: scan-nist-800-53 + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: placement-scan-nist-800-53 +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - {key: vendor, operator: In, values: ["OpenShift"]} \ No newline at end of file diff --git a/components/policies/gatekeeper/config-policy-namespace.yaml b/components/policies/gatekeeper/config-policy-namespace.yaml new file mode 100644 index 0000000..48aeeff --- /dev/null +++ b/components/policies/gatekeeper/config-policy-namespace.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Namespace +metadata: + annotations: + openshift.io/description: ACM Configuration Policies + openshift.io/display-name: ACM Configuration Policies + name: acm-config-policies \ No newline at end of file diff --git a/components/policies/gatekeeper/gatekeeper-exclude-namespaces.yaml b/components/policies/gatekeeper/gatekeeper-exclude-namespaces.yaml new file mode 100644 index 0000000..61125fc --- /dev/null +++ b/components/policies/gatekeeper/gatekeeper-exclude-namespaces.yaml @@ -0,0 +1,131 @@ +# Sample policy to configure gatekeeper to exclude namespaces from certain processes for all constraints in the cluster +# See: https://github.com/open-policy-agent/gatekeeper/tree/release-3.3#exempting-namespaces-from-gatekeeper +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: policy-gatekeeper-config-exclude-namespaces + annotations: + policy.open-cluster-management.io/standards: NIST SP 800-53 + policy.open-cluster-management.io/categories: CM Configuration Management + policy.open-cluster-management.io/controls: CM-2 Baseline Configuration +spec: + remediationAction: enforce + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: policy-gatekeeper-config-exclude-namespaces + spec: + remediationAction: enforce # will be overridden by remediationAction in parent policy + severity: low + object-templates: + - complianceType: mustonlyhave + objectDefinition: + apiVersion: config.gatekeeper.sh/v1alpha1 + kind: Config + metadata: + name: config + namespace: openshift-gatekeeper-system + spec: + match: + - excludedNamespaces: + - hive + - kube-node-lease + - kube-public + - kube-storage-version-migrator-operator + - kube-system + - open-cluster-management + - open-cluster-management-hub + - open-cluster-management-agent + - open-cluster-management-agent-addon + - openshift + - openshift-apiserver + - openshift-apiserver-operator + - openshift-authentication + - openshift-authentication-operator + - openshift-cloud-credential-operator + - openshift-cluster-csi-drivers + - openshift-cluster-machine-approver + - openshift-cluster-node-tuning-operator + - openshift-cluster-samples-operator + - openshift-cluster-storage-operator + - openshift-cluster-version + - openshift-compliance + - openshift-config + - openshift-config-managed + - openshift-config-operator + - openshift-console + - openshift-console-operator + - openshift-console-user-settings + - openshift-controller-manager + - openshift-controller-manager-operator + - openshift-dns + - openshift-dns-operator + - openshift-etcd + - openshift-etcd-operator + - openshift-gatekeeper-operator + - openshift-gatekeeper-system + - openshift-image-registry + - openshift-infra + - openshift-ingress + - openshift-ingress-canary + - openshift-ingress-operator + - openshift-insights + - openshift-kni-infra + - openshift-kube-apiserver + - openshift-kube-apiserver-operator + - openshift-kube-controller-manager + - openshift-kube-controller-manager-operator + - openshift-kube-scheduler + - openshift-kube-scheduler-operator + - openshift-kube-storage-version-migrator + - openshift-kube-storage-version-migrator-operator + - openshift-kubevirt-infra + - openshift-machine-api + - openshift-machine-config-operator + - openshift-marketplace + - openshift-monitoring + - openshift-multus + - openshift-network-diagnostics + - openshift-network-operator + - openshift-node + - openshift-oauth-apiserver + - openshift-openstack-infra + - openshift-operators + - openshift-operator-lifecycle-manager + - openshift-ovirt-infra + - openshift-ovn-kubernetes + - openshift-sdn + - openshift-service-ca + - openshift-service-ca-operator + - openshift-user-workload-monitoring + - openshift-vsphere-infra + processes: + - '*' +--- +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: binding-policy-gatekeeper-config-exclude-namespaces +placementRef: + name: placement-policy-gatekeeper-config-exclude-namespaces + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: +- name: policy-gatekeeper-config-exclude-namespaces + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: placement-policy-gatekeeper-config-exclude-namespaces +spec: + clusterConditions: + - status: "True" + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - {key: policy, operator: In, values: ["opa"]} \ No newline at end of file diff --git a/components/policies/gatekeeper/gatekeeper-install-policy.yaml b/components/policies/gatekeeper/gatekeeper-install-policy.yaml new file mode 100644 index 0000000..8f36d2d --- /dev/null +++ b/components/policies/gatekeeper/gatekeeper-install-policy.yaml @@ -0,0 +1,139 @@ +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: policy-gatekeeper-operator + annotations: + policy.open-cluster-management.io/standards: NIST SP 800-53 + policy.open-cluster-management.io/categories: CM Configuration Management + policy.open-cluster-management.io/controls: CM-2 Baseline Configuration +spec: + remediationAction: enforce + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: gatekeeper-operator-ns + spec: + remediationAction: enforce + severity: high + object-templates: + - complianceType: musthave + objectDefinition: + apiVersion: v1 + kind: Namespace + metadata: + name: openshift-gatekeeper-operator + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: gatekeeper-operator-catalog-source + spec: + remediationAction: enforce + severity: high + object-templates: + - complianceType: musthave + objectDefinition: + apiVersion: operators.coreos.com/v1alpha1 + kind: CatalogSource + metadata: + name: gatekeeper-operator + namespace: openshift-gatekeeper-operator + spec: + displayName: Gatekeeper Operator Upstream + publisher: github.com/font/gatekeeper-operator + sourceType: grpc + image: 'quay.io/gatekeeper/gatekeeper-operator-bundle-index:v0.2.1' + updateStrategy: + registryPoll: + interval: 45m + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: gatekeeper-operator-group + spec: + remediationAction: enforce + severity: high + object-templates: + - complianceType: musthave + objectDefinition: + apiVersion: operators.coreos.com/v1 + kind: OperatorGroup + metadata: + name: gatekeeper-operator + namespace: openshift-gatekeeper-operator + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: gatekeeper-operator-subscription + spec: + remediationAction: enforce + severity: high + object-templates: + - complianceType: musthave + objectDefinition: + apiVersion: operators.coreos.com/v1alpha1 + kind: Subscription + metadata: + name: gatekeeper-operator-sub + namespace: openshift-gatekeeper-operator + spec: + channel: stable + name: gatekeeper-operator + source: gatekeeper-operator + sourceNamespace: openshift-gatekeeper-operator + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: gatekeeper + spec: + remediationAction: enforce + severity: high + object-templates: + - complianceType: musthave + objectDefinition: + apiVersion: operator.gatekeeper.sh/v1alpha1 + kind: Gatekeeper + metadata: + name: gatekeeper + spec: + audit: + auditChunkSize: 500 + logLevel: INFO + replicas: 1 + validatingWebhook: Enabled + mutatingWebhook: Disabled + webhook: + emitAdmissionEvents: Enabled + logLevel: INFO + replicas: 2 +--- +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: binding-policy-gatekeeper-operator +placementRef: + name: placement-policy-gatekeeper-operator + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: +- name: policy-gatekeeper-operator + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: placement-policy-gatekeeper-operator +spec: + clusterConditions: + - status: "True" + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - {key: policy, operator: In, values: ["opa"]} \ No newline at end of file diff --git a/components/policies/gitops/base/kustomization.yaml b/components/policies/gitops/base/kustomization.yaml new file mode 100644 index 0000000..4041c39 --- /dev/null +++ b/components/policies/gitops/base/kustomization.yaml @@ -0,0 +1,8 @@ +namespace: acm-policies + +resources: +- placement.yaml +- managedclustersetbinding.yaml + +generators: +- policy-generator-config.yaml \ No newline at end of file diff --git a/components/policies/gitops/base/managedclustersetbinding.yaml b/components/policies/gitops/base/managedclustersetbinding.yaml new file mode 100644 index 0000000..7d389dc --- /dev/null +++ b/components/policies/gitops/base/managedclustersetbinding.yaml @@ -0,0 +1,7 @@ +apiVersion: cluster.open-cluster-management.io/v1beta2 +kind: ManagedClusterSetBinding +metadata: + name: global + namespace: acm-policies +spec: + clusterSet: global \ No newline at end of file diff --git a/components/policies/gitops/base/manifests/eso/base/secret-store.yaml b/components/policies/gitops/base/manifests/eso/base/secret-store.yaml new file mode 100644 index 0000000..3388a7c --- /dev/null +++ b/components/policies/gitops/base/manifests/eso/base/secret-store.yaml @@ -0,0 +1,39 @@ +apiVersion: v1 +kind: Secret +metadata: + name: eso-token-cluster + namespace: external-secrets +data: + dopplerToken: '{{hub (fromSecret "acm-policies" (printf "eso-token-cluster-%s" .ManagedClusterName) "dopplerToken") hub}}' +--- +apiVersion: external-secrets.io/v1beta1 +kind: ClusterSecretStore +metadata: + name: doppler-cluster +spec: + provider: + doppler: + auth: + secretRef: + dopplerToken: + name: eso-token-cluster + key: dopplerToken + namespace: external-secrets + + conditions: + - namespaceSelector: + matchLabels: + openshift.io/cluster-monitoring: "true" + + - namespaces: + - "cert-manager" + - "dev-tools" + - "gitops" + - "openshift-config" + - "openshift-gitops" + - "openshift-monitoring" + - "openshift-pipelines" + - "stackrox" + - "stackrox-secured-cluster-service" + - "tenant-secrets" + - "trusted-profile-analyzer" diff --git a/components/policies/gitops/base/manifests/gitops-alerting/base/kustomization.yaml b/components/policies/gitops/base/manifests/gitops-alerting/base/kustomization.yaml new file mode 100644 index 0000000..b3323f2 --- /dev/null +++ b/components/policies/gitops/base/manifests/gitops-alerting/base/kustomization.yaml @@ -0,0 +1,4 @@ +namespace: openshift-gitops + +resources: +- prometheus-rules.yaml diff --git a/components/policies/gitops/base/manifests/gitops-alerting/base/prometheus-rules.yaml b/components/policies/gitops/base/manifests/gitops-alerting/base/prometheus-rules.yaml new file mode 100644 index 0000000..6c7ab28 --- /dev/null +++ b/components/policies/gitops/base/manifests/gitops-alerting/base/prometheus-rules.yaml @@ -0,0 +1,31 @@ +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: argocd-health-alerts + annotations: + policy.open-cluster-management.io/disable-templates: "true" +spec: + groups: + - name: ArgoCD + rules: + - alert: ArgoCDHealthAlert + annotations: + message: ArgoCD application {{ $labels.name }} is not healthy + expr: argocd_app_info{namespace="openshift-gitops", health_status!~"Healthy|Suspended|Progressing|Degraded"} > 0 + for: 5m + labels: + severity: warning + - alert: ArgoCDDegradedAlert + annotations: + message: ArgoCD application {{ $labels.name }} is degraded + expr: argocd_app_info{namespace="openshift-gitops", health_status="Degraded"} > 0 + for: 5m + labels: + severity: critical + - alert: ArgoCDStuckAlert + annotations: + message: ArgoCD application {{ $labels.name }} is stuck in progressing for more than 10m + expr: argocd_app_info{namespace="openshift-gitops", health_status="Progressing"} > 0 + for: 10m + labels: + severity: warning diff --git a/components/policies/gitops/base/manifests/gitops-bootstrap/base/bootstrap-app.yaml b/components/policies/gitops/base/manifests/gitops-bootstrap/base/bootstrap-app.yaml new file mode 100644 index 0000000..a98cbec --- /dev/null +++ b/components/policies/gitops/base/manifests/gitops-bootstrap/base/bootstrap-app.yaml @@ -0,0 +1,27 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: cluster-config-bootstrap + namespace: openshift-gitops + labels: + gitops.ownedBy: cluster-config +spec: + destination: + namespace: openshift-gitops + server: https://kubernetes.default.svc + project: bootstrap + source: + path: bootstrap/overlays/{{ fromClusterClaim "gitops" }} + repoURL: https://github.com/gnunn-gitops/cluster-config-pins.git + targetRevision: 'HEAD' + syncPolicy: + automated: + prune: false + selfHeal: false + ignoreDifferences: + - group: argoproj.io + kind: Application + managedFieldsManagers: + - argocd-server + jsonPointers: + - /spec/syncPolicy/automated diff --git a/components/policies/gitops/base/manifests/gitops-bootstrap/base/bootstrap-appproject.yaml b/components/policies/gitops/base/manifests/gitops-bootstrap/base/bootstrap-appproject.yaml new file mode 100644 index 0000000..bce3e9f --- /dev/null +++ b/components/policies/gitops/base/manifests/gitops-bootstrap/base/bootstrap-appproject.yaml @@ -0,0 +1,16 @@ +apiVersion: argoproj.io/v1alpha1 +kind: AppProject +metadata: + name: bootstrap + namespace: openshift-gitops +spec: + clusterResourceWhitelist: + - group: '*' + kind: '*' + description: Project for bootstrap cluster app + destinations: + - namespace: '*' + server: https://kubernetes.default.svc + sourceRepos: + - https://github.com/gnunn-gitops/cluster-config + - https://github.com/gnunn-gitops/cluster-config-pins diff --git a/components/policies/gitops/base/manifests/gitops-bootstrap/base/kustomization.yaml b/components/policies/gitops/base/manifests/gitops-bootstrap/base/kustomization.yaml new file mode 100644 index 0000000..ca4eb20 --- /dev/null +++ b/components/policies/gitops/base/manifests/gitops-bootstrap/base/kustomization.yaml @@ -0,0 +1,3 @@ +resources: +- bootstrap-appproject.yaml +- bootstrap-app.yaml \ No newline at end of file diff --git a/components/policies/gitops/base/manifests/gitops-instance/base/argocd.yaml b/components/policies/gitops/base/manifests/gitops-instance/base/argocd.yaml new file mode 100644 index 0000000..556fa4e --- /dev/null +++ b/components/policies/gitops/base/manifests/gitops-instance/base/argocd.yaml @@ -0,0 +1,389 @@ +apiVersion: argoproj.io/v1beta1 +kind: ArgoCD +metadata: + name: openshift-gitops + namespace: openshift-gitops +spec: + resourceTrackingMethod: annotation + applicationSet: {} + extraConfig: + exec.enabled: "true" + resource.respectRBAC: "normal" + resource.ignoreResourceUpdatesEnabled: 'true' + resource.compareoptions: | + ignoreAggregatedRoles: true + resource.customizations.ignoreResourceUpdates.external-secrets.io_ExternalSecret: | + jsonPointers: + - /status/refreshTime + resource.customizations.ignoreResourceUpdates.ocs.openshift.io_StorageCluster: | + jsonPointers: + - /status + - /metadata/resourceVersion + resource.customizations.ignoreResourceUpdates.ocs.openshift.io_StorageSystem: | + jsonPointers: + - /status + - /metadata/resourceVersion + resource.customizations.ignoreResourceUpdates.noobaa.io_Noobaa: | + jsonPointers: + - /status + - /metadata/resourceVersion + resource.customizations.ignoreResourceUpdates.noobaa.io_BackingStore: | + jsonPointers: + - /status + - /metadata/resourceVersion + accounts.admin: apiKey, login + ui.cssurl: 'https://gnunn-gitops.github.io/cluster-config/themes/{{ fromClusterClaim "gitops" }}/custom-cluster.css' + kustomizeBuildOptions: "--enable-helm --enable-alpha-plugins" + oidcConfig: | + name: Keycloak + issuer: https://sso.ocplab.com/realms/ocplab + clientID: argocd + clientSecret: $oidc.keycloak.clientSecret + requestedScopes: ["openid", "profile", "email", "groups"] + controller: + extraCommandArgs: + - '--persist-resource-health=false' + resources: + limits: + memory: 4Gi + requests: + cpu: 1000m + memory: 3Gi + monitoring: + enabled: true + repo: + sidecarContainers: + - name: setenv-cmp-plugin + command: [/var/run/argocd/argocd-cmp-server] + env: + - name: KUSTOMIZE_PLUGIN_HOME + value: /etc/kustomize/plugin + - name: INFRASTRUCTURE_ID + value: '{{ (lookup "config.openshift.io/v1" "Infrastructure" "" "cluster").status.infrastructureName }}' + - name: CLUSTER_ID + value: '{{ (lookup "config.openshift.io/v1" "ClusterVersion" "" "version").spec.clusterID }}' + - name: CLUSTER_GITOPS_NAME + value: '{{ fromClusterClaim "gitops" }}' + - name: CLUSTER_NAME + value: '{{ fromClusterClaim "name" }}' + - name: SUB_DOMAIN + value: '{{ (lookup "config.openshift.io/v1" "Ingress" "openshift-ingress" "cluster").spec.domain }}' + - name: BASE_DOMAIN + value: '{{ (lookup "config.openshift.io/v1" "DNS" "" "cluster").spec.baseDomain }}' + - name: COLOR + value: '{{ default "0066CC" (fromClusterClaim "color") }}' + image: quay.io/gnunn/tools:latest + imagePullPolicy: Always + securityContext: + runAsNonRoot: true + volumeMounts: + - mountPath: /var/run/argocd + name: var-files + - mountPath: /home/argocd/cmp-server/plugins + name: plugins + - mountPath: /tmp + name: tmp + - mountPath: /home/argocd/cmp-server/config/plugin.yaml + subPath: plugin.yaml + name: setenv-cmp-plugin + volumes: + - configMap: + name: setenv-cmp-plugin + name: setenv-cmp-plugin + resources: + limits: + cpu: '1' + memory: 1.5Gi + requests: + cpu: 250m + memory: 768Mi + redis: + resources: + limits: + cpu: 500m + memory: 512Mi + requests: + cpu: 250m + memory: 256Mi + server: + insecure: true + # host: 'openshift-gitops-server-openshift-gitops.{{ (lookup "config.openshift.io/v1" "Ingress" "openshift-ingress" "cluster").spec.domain }}' + route: + enabled: true + tls: + termination: edge + insecureEdgeTerminationPolicy: Redirect + notifications: + enabled: true + resourceActions: + - group: compliance.openshift.io + kind: ComplianceScan + action: | + discovery.lua: | + local actions = {} + local enabled = false + if obj.status ~= nil and obj.status.phase == "DONE" then + enabled = true + end + actions["rescan"] = {["disabled"] = not(enabled)} + return actions + definitions: + - name: rescan + action.lua: | + if obj.metadata.annotations == nil then + obj.metadata.annotations = {} + end + obj.metadata.annotations["compliance.openshift.io/rescan"] = "" + return obj + resourceHealthChecks: + - group: argoproj.io + kind: Application + check: | + hs = {} + hs.status = "Progressing" + hs.message = "" + if obj.status ~= nil then + if obj.status.health ~= nil then + hs.status = obj.status.health.status + hs.message = obj.status.health.message + end + end + return hs + - group: argoproj.io + kind: RolloutManager + check: | + hs = {} + if obj.status ~= nil then + if obj.status.conditions ~= nil then + for _, condition in ipairs(obj.status.conditions) do + hs.message = condition.message + break + end + end + if obj.status.phase ~= nil then + if obj.status.phase == "Failure" then + hs.status = "Degraded" + return hs + elseif obj.status.phase == "Available" then + hs.status = "Healthy" + return hs + elseif obj.status.phase == "Pending" then + hs.status = "Progressing" + return hs + end + end + hs.status = "Progressing" + hs.message = "Waiting for operator to update status" + return hs + end + - group: operators.coreos.com + kind: Subscription + check: | + health_status = {} + if obj.status ~= nil then + if obj.status.conditions ~= nil then + numDegraded = 0 + numPending = 0 + numSuspended = 0 + msg = "" + for i, condition in pairs(obj.status.conditions) do + msg = msg .. i .. ": " .. condition.type .. " | " .. condition.status .. " | " .. (condition.reason and condition.reason or '') .. "\n" + if condition.type == "InstallPlanPending" and condition.status == "True" then + if condition.reason == "RequiresApproval" then + numSuspended = numSuspended + 1 + else + numPending = numPending + 1 + end + elseif (condition.type == "InstallPlanMissing" and condition.reason ~= "ReferencedInstallPlanNotFound") then + numDegraded = numDegraded + 1 + elseif (condition.type == "CatalogSourcesUnhealthy" or condition.type == "InstallPlanFailed") and condition.status == "True" then + numDegraded = numDegraded + 1 + elseif (condition.type == "ResolutionFailed" and condition.reason ~= "ConstraintsNotSatisfiable") then + numDegraded = numDegraded + 1 + elseif (condition.type == 'ChannelDeprecated' and condition.status == "True") then + numDegraded = numDegraded + 1 + end + end + if numDegraded > 0 then + health_status.status = "Degraded" + health_status.message = msg + return health_status + elseif numSuspended > 0 then + health_status.status = "Suspended" + health_status.message = msg + return health_status + elseif numPending > 0 then + health_status.status = "Progressing" + health_status.message = "An install plan for a subscription is pending installation" + return health_status + else + health_status.status = "Healthy" + health_status.message = msg + return health_status + end + end + end + health_status.status = "Progressing" + health_status.message = "An install plan for a subscription is pending installation" + return health_status + - group: operators.coreos.com + kind: InstallPlan + check: | + hs = {} + if obj.status ~= nil then + if obj.status.phase ~= nil then + if obj.status.phase == "Complete" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + elseif obj.status.phase == "RequiresApproval" then + hs.status = "Suspended" + hs.message = obj.status.phase + return hs + else + hs.status = "Progressing" + hs.message = obj.status.phase + return hs + end + end + end + hs.status = "Progressing" + hs.message = "Waiting for InstallPlan to complete" + return hs + - group: platform.stackrox.io + kind: Central + check: | + hs = {} + if obj.status ~= nil and obj.status.conditions ~= nil then + for i, condition in ipairs(obj.status.conditions) do + if condition.status == "True" or condition.reason == "InstallSuccessful" or condition.reason == "UpgradeSuccessful" then + hs.status = "Healthy" + hs.message = "Install Successful" + return hs + end + end + end + hs.status = "Progressing" + hs.message = "Waiting for Central to deploy." + return hs + - group: image.openshift.io + kind: ImageStream + check: | + hs = {} + hs.status = "Progressing" + hs.message = "" + if obj.status ~= nil then + if obj.status.tags ~= nil then + numTags = 0 + for _ , item in pairs(obj.status.tags) do + numTags = numTags + 1 + numItems = 0 + if item.tags ~= nil then + for _ , item in pairs(item.tags) do + numItems = numItems + 1 + end + if numItems == 0 then + return hs + end + end + end + if numTags > 0 then + hs.status = "Healthy" + hs.message = "ImageStream has tags resolved" + return hs + end + end + end + return hs + - group: build.openshift.io + kind: Build + check: | + hs = {} + if obj.status ~= nil then + if obj.status.phase ~= nil then + if obj.status.phase == "Complete" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + end + end + end + hs.status = "Progressing" + hs.message = "Waiting for Build to complete" + return hs + - kind: PersistentVolumeClaim + check: | + hs = {} + if obj.status ~= nil then + if obj.status.phase ~= nil then + if obj.status.phase == "Pending" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + end + if obj.status.phase == "Bound" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + end + end + end + hs.status = "Progressing" + hs.message = "Waiting for PVC" + return hs + resourceIgnoreDifferences: + resourceIdentifiers: + - group: route.openshift.io + kind: Route + customization: + jsonPointers: + - /status/ingress + - /metadata/annotations + - group: quay.redhat.com + kind: QuayRegistry + customization: + jsonPointers: + - /status/ingress + - group: cluster.open-cluster-management.io + kind: ManagedCluster + customization: + jsonPointers: + - /spec/managedClusterClientConfigs + resourceExclusions: | + - apiGroups: + - tekton.dev + clusters: + - '*' + kinds: + - TaskRun + - PipelineRun + - apiGroups: + - operator.tekton.dev + clusters: + - '*' + kinds: + - TektonAddon + - TektonInstallerSet + - apiGroups: + - compliance.openshift.io + kinds: + - ComplianceCheckResult + - ComplianceRemediation + - apiGroups: + - policy.open-cluster-management.io + kinds: + - ConfigurationPolicy + - apiGroups: + - noobaa.io + kinds: + - NooBaa + - BucketClass + ha: + enabled: false + rbac: + defaultPolicy: 'role:none' + policy: | + p, role:none, *, *, */*, deny + g, system:cluster-admins, role:admin + g, cluster-admins, role:admin + scopes: "[groups]" diff --git a/components/policies/gitops/base/manifests/gitops-instance/base/kustomization.yaml b/components/policies/gitops/base/manifests/gitops-instance/base/kustomization.yaml new file mode 100644 index 0000000..8652851 --- /dev/null +++ b/components/policies/gitops/base/manifests/gitops-instance/base/kustomization.yaml @@ -0,0 +1,3 @@ +resources: +- setenv-cmp-plugin-cm.yaml +- argocd.yaml diff --git a/components/policies/gitops/base/manifests/gitops-instance/base/setenv-cmp-plugin-cm.yaml b/components/policies/gitops/base/manifests/gitops-instance/base/setenv-cmp-plugin-cm.yaml new file mode 100644 index 0000000..e375aeb --- /dev/null +++ b/components/policies/gitops/base/manifests/gitops-instance/base/setenv-cmp-plugin-cm.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: setenv-cmp-plugin + namespace: openshift-gitops +data: + plugin.yaml: | + apiVersion: argoproj.io/v1alpha1 + kind: ConfigManagementPlugin + metadata: + name: setenv-cmp-plugin + spec: + init: + command: [sh, -c, 'echo "Initializing setenv-plugin-cmp..."'] + generate: + command: + - sh + - "-c" + - "set -o pipefail && kustomize build --enable-helm --enable-alpha-plugins . | envsub" diff --git a/components/policies/gitops/base/manifests/gitops-notifications/base/kustomization.yaml b/components/policies/gitops/base/manifests/gitops-notifications/base/kustomization.yaml new file mode 100644 index 0000000..2fb0084 --- /dev/null +++ b/components/policies/gitops/base/manifests/gitops-notifications/base/kustomization.yaml @@ -0,0 +1,2 @@ +resources: +- notifications-config.yaml diff --git a/components/policies/gitops/base/manifests/gitops-notifications/base/notifications-cm.yaml b/components/policies/gitops/base/manifests/gitops-notifications/base/notifications-cm.yaml new file mode 100644 index 0000000..95ac995 --- /dev/null +++ b/components/policies/gitops/base/manifests/gitops-notifications/base/notifications-cm.yaml @@ -0,0 +1,256 @@ +# No longer needed with NotificationsConfig introduced in 1.12 +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + app.kubernetes.io/managed-by: openshift-gitops + app.kubernetes.io/name: argocd-notifications-cm + app.kubernetes.io/part-of: argocd + annotation: + policy.open-cluster-management.io/disable-templates: "true" + name: argocd-notifications-cm + namespace: openshift-gitops +data: + service.slack: | + token: $slack-token + template.app-deployed: |- + slack: + attachments: | + [{ + "title": "{{ .app.metadata.name}}", + "title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}", + "color": "#18be52", + "fields": [ + { + "title": "Sync Status", + "value": "{{.app.status.sync.status}}", + "short": true + }, + { + "title": "Repository", + "value": "{{.app.spec.source.repoURL}}", + "short": true + }, + { + "title": "Revision", + "value": "{{.app.status.sync.revision}}", + "short": true + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.type}}", + "value": "{{$c.message}}", + "short": true + } + {{end}} + ] + }] + deliveryPolicy: Post + groupingKey: "" + notifyBroadcast: false + template.app-health-degraded: |- + slack: + attachments: | + [{ + "title": "{{ .app.metadata.name}}", + "title_link": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}", + "color": "#f4c030", + "fields": [ + { + "title": "Health Status", + "value": "{{.app.status.health.status}}", + "short": true + }, + { + "title": "Repository", + "value": "{{.app.spec.source.repoURL}}", + "short": true + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.type}}", + "value": "{{$c.message}}", + "short": true + } + {{end}} + ] + }] + deliveryPolicy: Post + groupingKey: "" + notifyBroadcast: false + template.app-sync-failed: |- + slack: + attachments: | + [{ + "title": "{{ .app.metadata.name}}", + "title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}", + "color": "#E96D76", + "fields": [ + { + "title": "Sync Status", + "value": "{{.app.status.sync.status}}", + "short": true + }, + { + "title": "Repository", + "value": "{{.app.spec.source.repoURL}}", + "short": true + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.type}}", + "value": "{{$c.message}}", + "short": true + } + {{end}} + ] + }] + deliveryPolicy: Post + groupingKey: "" + notifyBroadcast: false + template.app-sync-running: |- + slack: + attachments: | + [{ + "title": "{{ .app.metadata.name}}", + "title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}", + "color": "#0DADEA", + "fields": [ + { + "title": "Sync Status", + "value": "{{.app.status.sync.status}}", + "short": true + }, + { + "title": "Repository", + "value": "{{.app.spec.source.repoURL}}", + "short": true + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.type}}", + "value": "{{$c.message}}", + "short": true + } + {{end}} + ] + }] + deliveryPolicy: Post + groupingKey: "" + notifyBroadcast: false + template.app-sync-status-unknown: |- + slack: + attachments: | + [{ + "title": "{{ .app.metadata.name}}", + "title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}", + "color": "#E96D76", + "fields": [ + { + "title": "Sync Status", + "value": "{{.app.status.sync.status}}", + "short": true + }, + { + "title": "Repository", + "value": "{{.app.spec.source.repoURL}}", + "short": true + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.type}}", + "value": "{{$c.message}}", + "short": true + } + {{end}} + ] + }] + deliveryPolicy: Post + groupingKey: "" + notifyBroadcast: false + template.app-sync-succeeded: |- + slack: + attachments: | + [{ + "title": "{{ .app.metadata.name}}", + "title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}", + "color": "#18be52", + "fields": [ + { + "title": "Sync Status", + "value": "{{.app.status.sync.status}}", + "short": true + }, + { + "title": "Repository", + "value": "{{.app.spec.source.repoURL}}", + "short": true + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.type}}", + "value": "{{$c.message}}", + "short": true + } + {{end}} + ] + }] + deliveryPolicy: Post + groupingKey: "" + notifyBroadcast: false + # trigger.on-created: |- + # - description: Application is created. + # oncePer: app.metadata.name + # send: + # - app-created + # when: "true" + # trigger.on-deleted: |- + # - description: Application is deleted. + # oncePer: app.metadata.name + # send: + # - app-deleted + # when: app.metadata.deletionTimestamp != nil + trigger.on-deployed: |- + - description: Application is synced and healthy. Triggered once per commit. + oncePer: app.status.operationState.syncResult.revision + send: + - app-deployed + when: app.status.operationState.phase in ['Succeeded'] and app.status.health.status + == 'Healthy' + trigger.on-health-degraded: |- + - description: Application has degraded + send: + - app-health-degraded + when: app.status.health.status == 'Degraded' + trigger.on-sync-failed: |- + - description: Application syncing has failed + send: + - app-sync-failed + when: app.status.operationState.phase in ['Error', 'Failed'] + trigger.on-sync-running: |- + - description: Application is being synced + send: + - app-sync-running + when: app.status.operationState.phase in ['Running'] + trigger.on-sync-status-unknown: |- + - description: Application status is 'Unknown' + end: + - app-sync-status-unknown + when: app.status.sync.status == 'Unknown' + trigger.on-sync-succeeded: |- + - description: Application syncing has succeeded + send: + - app-sync-succeeded + when: app.status.operationState.phase in ['Succeeded'] diff --git a/components/policies/gitops/base/manifests/gitops-notifications/base/notifications-config.yaml b/components/policies/gitops/base/manifests/gitops-notifications/base/notifications-config.yaml new file mode 100644 index 0000000..07281ce --- /dev/null +++ b/components/policies/gitops/base/manifests/gitops-notifications/base/notifications-config.yaml @@ -0,0 +1,540 @@ +apiVersion: argoproj.io/v1alpha1 +kind: NotificationsConfiguration +metadata: + name: default-notifications-configuration + namespace: openshift-gitops +spec: + services: + service.slack: | + token: $slack-token + templates: + template.app-created: |- + email: + subject: Application {{.app.metadata.name}} has been created. + message: Application {{.app.metadata.name}} has been created. + teams: + title: Application {{.app.metadata.name}} has been created. + template.app-deleted: |- + email: + subject: Application {{.app.metadata.name}} has been deleted. + message: Application {{.app.metadata.name}} has been deleted. + teams: + title: Application {{.app.metadata.name}} has been deleted. + template.app-deployed: |- + email: + subject: New version of an application {{.app.metadata.name}} is up and running. + message: | + {{if eq .serviceType "slack"}}:white_check_mark:{{end}} Application {{.app.metadata.name}} is now running new version of deployments manifests. + slack: + attachments: | + [{ + "title": "{{ .app.metadata.name}}", + "title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}", + "color": "#18be52", + "fields": [ + { + "title": "Sync Status", + "value": "{{.app.status.sync.status}}", + "short": true + }, + { + "title": "Repository", + "value": "{{.app.spec.source.repoURL}}", + "short": true + }, + { + "title": "Revision", + "value": "{{.app.status.sync.revision}}", + "short": true + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.type}}", + "value": "{{$c.message}}", + "short": true + } + {{end}} + ] + }] + deliveryPolicy: Post + groupingKey: "" + notifyBroadcast: false + teams: + facts: | + [{ + "name": "Sync Status", + "value": "{{.app.status.sync.status}}" + }, + { + "name": "Repository", + "value": "{{.app.spec.source.repoURL}}" + }, + { + "name": "Revision", + "value": "{{.app.status.sync.revision}}" + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "name": "{{$c.type}}", + "value": "{{$c.message}}" + } + {{end}} + ] + potentialAction: |- + [{ + "@type":"OpenUri", + "name":"Operation Application", + "targets":[{ + "os":"default", + "uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}" + }] + }, + { + "@type":"OpenUri", + "name":"Open Repository", + "targets":[{ + "os":"default", + "uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}" + }] + }] + themeColor: '#000080' + title: New version of an application {{.app.metadata.name}} is up and running. + template.app-health-degraded: |- + email: + subject: Application {{.app.metadata.name}} has degraded. + message: | + {{if eq .serviceType "slack"}}:exclamation:{{end}} Application {{.app.metadata.name}} has degraded. + Application details: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}. + slack: + attachments: | + [{ + "title": "{{ .app.metadata.name}}", + "title_link": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}", + "color": "#f4c030", + "fields": [ + { + "title": "Health Status", + "value": "{{.app.status.health.status}}", + "short": true + }, + { + "title": "Repository", + "value": "{{.app.spec.source.repoURL}}", + "short": true + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.type}}", + "value": "{{$c.message}}", + "short": true + } + {{end}} + ] + }] + deliveryPolicy: Post + groupingKey: "" + notifyBroadcast: false + teams: + facts: | + [{ + "name": "Health Status", + "value": "{{.app.status.health.status}}" + }, + { + "name": "Repository", + "value": "{{.app.spec.source.repoURL}}" + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "name": "{{$c.type}}", + "value": "{{$c.message}}" + } + {{end}} + ] + potentialAction: | + [{ + "@type":"OpenUri", + "name":"Open Application", + "targets":[{ + "os":"default", + "uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}" + }] + }, + { + "@type":"OpenUri", + "name":"Open Repository", + "targets":[{ + "os":"default", + "uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}" + }] + }] + themeColor: '#FF0000' + title: Application {{.app.metadata.name}} has degraded. + template.app-sync-failed: |- + email: + subject: Failed to sync application {{.app.metadata.name}}. + message: | + {{if eq .serviceType "slack"}}:exclamation:{{end}} The sync operation of application {{.app.metadata.name}} has failed at {{.app.status.operationState.finishedAt}} with the following error: {{.app.status.operationState.message}} + Sync operation details are available at: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true . + slack: + attachments: | + [{ + "title": "{{ .app.metadata.name}}", + "title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}", + "color": "#E96D76", + "fields": [ + { + "title": "Sync Status", + "value": "{{.app.status.sync.status}}", + "short": true + }, + { + "title": "Repository", + "value": "{{.app.spec.source.repoURL}}", + "short": true + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.type}}", + "value": "{{$c.message}}", + "short": true + } + {{end}} + ] + }] + deliveryPolicy: Post + groupingKey: "" + notifyBroadcast: false + teams: + facts: | + [{ + "name": "Sync Status", + "value": "{{.app.status.sync.status}}" + }, + { + "name": "Failed at", + "value": "{{.app.status.operationState.finishedAt}}" + }, + { + "name": "Repository", + "value": "{{.app.spec.source.repoURL}}" + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "name": "{{$c.type}}", + "value": "{{$c.message}}" + } + {{end}} + ] + potentialAction: |- + [{ + "@type":"OpenUri", + "name":"Open Operation", + "targets":[{ + "os":"default", + "uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true" + }] + }, + { + "@type":"OpenUri", + "name":"Open Repository", + "targets":[{ + "os":"default", + "uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}" + }] + }] + themeColor: '#FF0000' + title: Failed to sync application {{.app.metadata.name}}. + template.app-sync-running: |- + email: + subject: Start syncing application {{.app.metadata.name}}. + message: | + The sync operation of application {{.app.metadata.name}} has started at {{.app.status.operationState.startedAt}}. + Sync operation details are available at: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true . + slack: + attachments: | + [{ + "title": "{{ .app.metadata.name}}", + "title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}", + "color": "#0DADEA", + "fields": [ + { + "title": "Sync Status", + "value": "{{.app.status.sync.status}}", + "short": true + }, + { + "title": "Repository", + "value": "{{.app.spec.source.repoURL}}", + "short": true + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.type}}", + "value": "{{$c.message}}", + "short": true + } + {{end}} + ] + }] + deliveryPolicy: Post + groupingKey: "" + notifyBroadcast: false + teams: + facts: | + [{ + "name": "Sync Status", + "value": "{{.app.status.sync.status}}" + }, + { + "name": "Started at", + "value": "{{.app.status.operationState.startedAt}}" + }, + { + "name": "Repository", + "value": "{{.app.spec.source.repoURL}}" + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "name": "{{$c.type}}", + "value": "{{$c.message}}" + } + {{end}} + ] + potentialAction: |- + [{ + "@type":"OpenUri", + "name":"Open Operation", + "targets":[{ + "os":"default", + "uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true" + }] + }, + { + "@type":"OpenUri", + "name":"Open Repository", + "targets":[{ + "os":"default", + "uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}" + }] + }] + title: Start syncing application {{.app.metadata.name}}. + template.app-sync-status-unknown: |- + email: + subject: Application {{.app.metadata.name}} sync status is 'Unknown' + message: | + {{if eq .serviceType "slack"}}:exclamation:{{end}} Application {{.app.metadata.name}} sync is 'Unknown'. + Application details: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}. + {{if ne .serviceType "slack"}} + {{range $c := .app.status.conditions}} + * {{$c.message}} + {{end}} + {{end}} + slack: + attachments: | + [{ + "title": "{{ .app.metadata.name}}", + "title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}", + "color": "#E96D76", + "fields": [ + { + "title": "Sync Status", + "value": "{{.app.status.sync.status}}", + "short": true + }, + { + "title": "Repository", + "value": "{{.app.spec.source.repoURL}}", + "short": true + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.type}}", + "value": "{{$c.message}}", + "short": true + } + {{end}} + ] + }] + deliveryPolicy: Post + groupingKey: "" + notifyBroadcast: false + teams: + facts: | + [{ + "name": "Sync Status", + "value": "{{.app.status.sync.status}}" + }, + { + "name": "Repository", + "value": "{{.app.spec.source.repoURL}}" + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "name": "{{$c.type}}", + "value": "{{$c.message}}" + } + {{end}} + ] + potentialAction: |- + [{ + "@type":"OpenUri", + "name":"Open Application", + "targets":[{ + "os":"default", + "uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}" + }] + }, + { + "@type":"OpenUri", + "name":"Open Repository", + "targets":[{ + "os":"default", + "uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}" + }] + }] + title: Application {{.app.metadata.name}} sync status is 'Unknown' + template.app-sync-succeeded: |- + email: + subject: Application {{.app.metadata.name}} has been successfully synced. + message: | + {{if eq .serviceType "slack"}}:white_check_mark:{{end}} Application {{.app.metadata.name}} has been successfully synced at {{.app.status.operationState.finishedAt}}. + Sync operation details are available at: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true . + slack: + attachments: | + [{ + "title": "{{ .app.metadata.name}}", + "title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}", + "color": "#18be52", + "fields": [ + { + "title": "Sync Status", + "value": "{{.app.status.sync.status}}", + "short": true + }, + { + "title": "Repository", + "value": "{{.app.spec.source.repoURL}}", + "short": true + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.type}}", + "value": "{{$c.message}}", + "short": true + } + {{end}} + ] + }] + deliveryPolicy: Post + groupingKey: "" + notifyBroadcast: false + teams: + facts: | + [{ + "name": "Sync Status", + "value": "{{.app.status.sync.status}}" + }, + { + "name": "Synced at", + "value": "{{.app.status.operationState.finishedAt}}" + }, + { + "name": "Repository", + "value": "{{.app.spec.source.repoURL}}" + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "name": "{{$c.type}}", + "value": "{{$c.message}}" + } + {{end}} + ] + potentialAction: |- + [{ + "@type":"OpenUri", + "name":"Operation Details", + "targets":[{ + "os":"default", + "uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true" + }] + }, + { + "@type":"OpenUri", + "name":"Open Repository", + "targets":[{ + "os":"default", + "uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}" + }] + }] + themeColor: '#000080' + title: Application {{.app.metadata.name}} has been successfully synced + triggers: + trigger.on-created: |- + - description: Application is created. + oncePer: app.metadata.name + send: + - app-created + when: "true" + trigger.on-deleted: |- + - description: Application is deleted. + oncePer: app.metadata.name + send: + - app-deleted + when: app.metadata.deletionTimestamp != nil + trigger.on-deployed: |- + - description: Application is synced and healthy. Triggered once per commit. + oncePer: app.status.operationState.syncResult.revision + send: + - app-deployed + when: app.status.operationState.phase in ['Succeeded'] and app.status.health.status + == 'Healthy' + trigger.on-health-degraded: |- + - description: Application has degraded + send: + - app-health-degraded + when: app.status.health.status == 'Degraded' + trigger.on-sync-failed: |- + - description: Application syncing has failed + send: + - app-sync-failed + when: app.status.operationState.phase in ['Error', 'Failed'] + trigger.on-sync-running: |- + - description: Application is being synced + send: + - app-sync-running + when: app.status.operationState.phase in ['Running'] + trigger.on-sync-status-unknown: |- + - description: Application status is 'Unknown' + send: + - app-sync-status-unknown + when: app.status.sync.status == 'Unknown' + trigger.on-sync-succeeded: |- + - description: Application syncing has succeeded + send: + - app-sync-succeeded + when: app.status.operationState.phase in ['Succeeded'] diff --git a/components/policies/gitops/base/manifests/gitops-secrets/base/argocd-external-secret.yaml b/components/policies/gitops/base/manifests/gitops-secrets/base/argocd-external-secret.yaml new file mode 100644 index 0000000..5144c7b --- /dev/null +++ b/components/policies/gitops/base/manifests/gitops-secrets/base/argocd-external-secret.yaml @@ -0,0 +1,20 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: argocd-secret + namespace: openshift-gitops +spec: + data: + - remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: OIDC_ARGOCD + secretKey: oidc.keycloak.clientSecret + refreshInterval: 1h + secretStoreRef: + kind: ClusterSecretStore + name: doppler-cluster + target: + creationPolicy: Merge + deletionPolicy: Retain + name: argocd-secret \ No newline at end of file diff --git a/components/policies/gitops/base/manifests/gitops-secrets/base/kustomization.yaml b/components/policies/gitops/base/manifests/gitops-secrets/base/kustomization.yaml new file mode 100644 index 0000000..f37ad67 --- /dev/null +++ b/components/policies/gitops/base/manifests/gitops-secrets/base/kustomization.yaml @@ -0,0 +1,3 @@ +resources: +- argocd-external-secret.yaml +- notifications-secret.yaml diff --git a/components/policies/gitops/base/manifests/gitops-secrets/base/notifications-secret.yaml b/components/policies/gitops/base/manifests/gitops-secrets/base/notifications-secret.yaml new file mode 100644 index 0000000..2249b0f --- /dev/null +++ b/components/policies/gitops/base/manifests/gitops-secrets/base/notifications-secret.yaml @@ -0,0 +1,17 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: argocd-notifications-secret + namespace: openshift-gitops +spec: + secretStoreRef: + kind: ClusterSecretStore + name: doppler-cluster + target: + name: argocd-notifications-secret + creationPolicy: Merge + deletionPolicy: Retain + data: + - secretKey: slack-token + remoteRef: + key: GITOPS_SLACK_TOKEN \ No newline at end of file diff --git a/components/policies/gitops/base/manifests/gitops-subscription/base/cluster-admin-rolebinding.yaml b/components/policies/gitops/base/manifests/gitops-subscription/base/cluster-admin-rolebinding.yaml new file mode 100644 index 0000000..3e4a00d --- /dev/null +++ b/components/policies/gitops/base/manifests/gitops-subscription/base/cluster-admin-rolebinding.yaml @@ -0,0 +1,12 @@ +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: argocd-application-controller-cluster-admin +subjects: + - kind: ServiceAccount + name: openshift-gitops-argocd-application-controller + namespace: openshift-gitops +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin \ No newline at end of file diff --git a/components/policies/gitops/base/manifests/gitops-subscription/base/gitops-controller-rbac.yaml b/components/policies/gitops/base/manifests/gitops-subscription/base/gitops-controller-rbac.yaml new file mode 100644 index 0000000..a37c07d --- /dev/null +++ b/components/policies/gitops/base/manifests/gitops-subscription/base/gitops-controller-rbac.yaml @@ -0,0 +1,39 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + annotations: + rbac.authorization.kubernetes.io/autoupdate: "true" + name: gitops-controller +aggregationRule: + clusterRoleSelectors: + - matchLabels: + gitops/aggregate-to-controller: "true" +rules: [] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: gitops-controller-admin + labels: + gitops/aggregate-to-controller: "true" +aggregationRule: + clusterRoleSelectors: + - matchLabels: + rbac.authorization.k8s.io/aggregate-to-admin: "true" +rules: [] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: gitops-controller-view + labels: + gitops/aggregate-to-controller: "true" +rules: +- apiGroups: + - '*' + resources: + - '*' + verbs: + - get + - list + - watch diff --git a/components/policies/gitops/base/manifests/gitops-subscription/base/gitops-server-rbac.yaml b/components/policies/gitops/base/manifests/gitops-subscription/base/gitops-server-rbac.yaml new file mode 100644 index 0000000..d75279a --- /dev/null +++ b/components/policies/gitops/base/manifests/gitops-subscription/base/gitops-server-rbac.yaml @@ -0,0 +1,53 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: gitops-server +rules: +- verbs: + - get + - patch + - delete + apiGroups: + - '*' + resources: + - '*' +- verbs: + - create + - get + - list + - watch + - update + - patch + - delete + apiGroups: + - '' + resources: + - secrets + - configmaps +- verbs: + - create + - get + - list + - watch + - update + - delete + - patch + apiGroups: + - argoproj.io + resources: + - applications + - appprojects + - applicationsets +- verbs: + - create + - list + apiGroups: + - '' + resources: + - events +- apiGroups: + - "" + resources: + - pods/exec + verbs: + - create diff --git a/components/policies/gitops/base/manifests/gitops-subscription/base/kustomization.yaml b/components/policies/gitops/base/manifests/gitops-subscription/base/kustomization.yaml new file mode 100644 index 0000000..68df95e --- /dev/null +++ b/components/policies/gitops/base/manifests/gitops-subscription/base/kustomization.yaml @@ -0,0 +1,8 @@ +resources: +- sub-namespace.yaml +- sub-operatorgroup.yaml +- subscription.yaml +- namespace.yaml +- gitops-controller-rbac.yaml +- gitops-server-rbac.yaml +- cluster-admin-rolebinding.yaml diff --git a/components/policies/gitops/base/manifests/gitops-subscription/base/namespace.yaml b/components/policies/gitops/base/manifests/gitops-subscription/base/namespace.yaml new file mode 100644 index 0000000..6b876b7 --- /dev/null +++ b/components/policies/gitops/base/manifests/gitops-subscription/base/namespace.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Namespace +metadata: + labels: + openshift.io/cluster-monitoring: "true" + name: openshift-gitops diff --git a/components/policies/gitops/base/manifests/gitops-subscription/base/sub-namespace.yaml b/components/policies/gitops/base/manifests/gitops-subscription/base/sub-namespace.yaml new file mode 100644 index 0000000..909dfec --- /dev/null +++ b/components/policies/gitops/base/manifests/gitops-subscription/base/sub-namespace.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Namespace +metadata: + labels: + openshift.io/cluster-monitoring: "true" + name: openshift-gitops-operator diff --git a/components/policies/gitops/base/manifests/gitops-subscription/base/sub-operatorgroup.yaml b/components/policies/gitops/base/manifests/gitops-subscription/base/sub-operatorgroup.yaml new file mode 100644 index 0000000..1e83597 --- /dev/null +++ b/components/policies/gitops/base/manifests/gitops-subscription/base/sub-operatorgroup.yaml @@ -0,0 +1,7 @@ +apiVersion: operators.coreos.com/v1 +kind: OperatorGroup +metadata: + name: gitops-operators + namespace: openshift-gitops-operator +spec: + upgradeStrategy: Default diff --git a/components/policies/gitops/base/manifests/gitops-subscription/base/subscription.yaml b/components/policies/gitops/base/manifests/gitops-subscription/base/subscription.yaml new file mode 100644 index 0000000..351b2ab --- /dev/null +++ b/components/policies/gitops/base/manifests/gitops-subscription/base/subscription.yaml @@ -0,0 +1,19 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: openshift-gitops-operator + namespace: openshift-gitops-operator +spec: + config: + env: + - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES + value: openshift-gitops, gitops + - name: CONTROLLER_CLUSTER_ROLE + value: gitops-controller + - name: SERVER_CLUSTER_ROLE + value: gitops-server + channel: gitops-1.15 + installPlanApproval: Automatic + name: openshift-gitops-operator + source: redhat-operators + sourceNamespace: openshift-marketplace diff --git a/components/policies/gitops/base/placement.yaml b/components/policies/gitops/base/placement.yaml new file mode 100644 index 0000000..d173a04 --- /dev/null +++ b/components/policies/gitops/base/placement.yaml @@ -0,0 +1,28 @@ +apiVersion: cluster.open-cluster-management.io/v1beta1 +kind: Placement +metadata: + name: placement-policy-gitops + namespace: acm-policies +spec: + clusterSets: + - global + predicates: + - requiredClusterSelector: + labelSelector: + matchExpressions: + - key: gitops + operator: Exists +--- +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: binding-policy-gitops + namespace: acm-policies +placementRef: + apiGroup: cluster.open-cluster-management.io + kind: Placement + name: placement-policy-gitops +subjects: +- apiGroup: policy.open-cluster-management.io + kind: PolicySet + name: gitops \ No newline at end of file diff --git a/components/policies/gitops/base/policy-generator-config.yaml b/components/policies/gitops/base/policy-generator-config.yaml new file mode 100644 index 0000000..52e1919 --- /dev/null +++ b/components/policies/gitops/base/policy-generator-config.yaml @@ -0,0 +1,60 @@ +apiVersion: policy.open-cluster-management.io/v1 +kind: PolicyGenerator +metadata: + name: gitops-policy-generator +policyDefaults: + namespace: acm-policies + remediationAction: enforce +placementBindingDefaults: + name: "binding-policy-gitops" +policies: + - name: policy-eso-secret-store + configurationPolicyAnnotations: + apps.open-cluster-management.io/reconcile-option: replace + manifests: + - path: manifests/eso/base/ + - name: policy-gitops-subscription + remediationAction: enforce + manifests: + - path: manifests/gitops-subscription/base/ + - name: policy-gitops-instance + # Needed to fix issue with merging lists resulting in duplicates + configurationPolicyAnnotations: + apps.open-cluster-management.io/reconcile-option: replace + complianceType: "mustonlyhave" + manifests: + - path: manifests/gitops-instance/base/ + - name: policy-gitops-bootstrap + manifests: + - path: manifests/gitops-bootstrap/base/ + - name: policy-gitops-notifications + remediationAction: enforce + manifests: + - path: manifests/gitops-notifications/base/ + configurationPolicyAnnotations: + policy.open-cluster-management.io/disable-templates: "true" + - name: policy-gitops-alerting + remediationAction: enforce + manifests: + - path: manifests/gitops-alerting/base/ + configurationPolicyAnnotations: + policy.open-cluster-management.io/disable-templates: "true" + # Put ESO secrets into separate policy since it's chicken and egg + # Not being used since I have a global policy that does this but included for example + # - name: policy-gitops-secrets + # remediationAction: enforce + # manifests: + # - path: manifests/gitops-secrets/base/ +policySets: + - name: "gitops" + description: "Policy for bootstrapping cluster with gitops" + policies: + - policy-eso-secret-store + - policy-gitops-subscription + - policy-gitops-instance + - policy-gitops-bootstrap + - policy-gitops-notifications + - policy-gitops-alerting + generatePolicySetPlacement: false + placement: + name: placement-policy-gitops diff --git a/components/policies/opa/gatekeeper-probes-livenessnotset.yaml b/components/policies/opa/gatekeeper-probes-livenessnotset.yaml new file mode 100644 index 0000000..1871622 --- /dev/null +++ b/components/policies/opa/gatekeeper-probes-livenessnotset.yaml @@ -0,0 +1,459 @@ +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: policy-gatekeeper-livenessprobe + annotations: + policy.open-cluster-management.io/standards: NIST SP 800-53 + policy.open-cluster-management.io/categories: CM Configuration Management + policy.open-cluster-management.io/controls: CM-2 Baseline Configuration +spec: + remediationAction: enforce + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: policy-gatekeeper-containerlivenessprobenotset + spec: + remediationAction: enforce + severity: low + object-templates: + - complianceType: musthave + objectDefinition: + apiVersion: templates.gatekeeper.sh/v1beta1 + kind: ConstraintTemplate + metadata: + creationTimestamp: null + name: containerlivenessprobenotset + spec: + crd: + spec: + names: + kind: ContainerLivenessprobeNotset + targets: + - libs: + - | + package lib.konstraint + + default is_gatekeeper = false + + is_gatekeeper { + has_field(input, "review") + has_field(input.review, "object") + } + + object = input { + not is_gatekeeper + } + + object = input.review.object { + is_gatekeeper + } + + format(msg) = gatekeeper_format { + is_gatekeeper + gatekeeper_format = {"msg": msg} + } + + format(msg) = msg { + not is_gatekeeper + } + + name = object.metadata.name + + kind = object.kind + + has_field(obj, field) { + obj[field] + } + + missing_field(obj, field) = true { + obj[field] == "" + } + + missing_field(obj, field) = true { + not has_field(obj, field) + } + + is_service { + lower(kind) == "service" + } + + is_statefulset { + lower(kind) == "statefulset" + } + + is_daemonset { + lower(kind) == "daemonset" + } + + is_deployment { + lower(kind) == "deployment" + } + + is_pod { + lower(kind) == "pod" + } + + is_namespace { + lower(kind) == "namespace" + } + + is_workload { + containers[_] + } + + pod_containers(pod) = all_containers { + keys = {"containers", "initContainers"} + all_containers = [c | keys[k]; c = pod.spec[k][_]] + } + + containers[container] { + pods[pod] + all_containers = pod_containers(pod) + container = all_containers[_] + } + + containers[container] { + all_containers = pod_containers(object) + container = all_containers[_] + } + + container_images[image] { + containers[container] + image = container.image + } + + container_images[image] { + image = object.spec.image + } + + split_image(image) = [image, "latest"] { + not contains(image, ":") + } + + split_image(image) = [image_name, tag] { + [image_name, tag] = split(image, ":") + } + + pods[pod] { + is_statefulset + pod = object.spec.template + } + + pods[pod] { + is_daemonset + pod = object.spec.template + } + + pods[pod] { + is_deployment + pod = object.spec.template + } + + pods[pod] { + is_pod + pod = object + } + + volumes[volume] { + pods[pod] + volume = pod.spec.volumes[_] + } + + mem_multiple("E") = 1000000000000000000000 { true } + + mem_multiple("P") = 1000000000000000000 { true } + + mem_multiple("T") = 1000000000000000 { true } + + mem_multiple("G") = 1000000000000 { true } + + mem_multiple("M") = 1000000000 { true } + + mem_multiple("k") = 1000000 { true } + + mem_multiple("") = 1000 { true } + + mem_multiple("m") = 1 { true } + + mem_multiple("Ki") = 1024000 { true } + + mem_multiple("Mi") = 1048576000 { true } + + mem_multiple("Gi") = 1073741824000 { true } + + mem_multiple("Ti") = 1099511627776000 { true } + + mem_multiple("Pi") = 1125899906842624000 { true } + + mem_multiple("Ei") = 1152921504606846976000 { true } + + get_suffix(mem) = suffix { + not is_string(mem) + suffix := "" + } + + get_suffix(mem) = suffix { + is_string(mem) + count(mem) > 0 + suffix := substring(mem, count(mem) - 1, -1) + mem_multiple(suffix) + } + + get_suffix(mem) = suffix { + is_string(mem) + count(mem) > 1 + suffix := substring(mem, count(mem) - 2, -1) + mem_multiple(suffix) + } + + get_suffix(mem) = suffix { + is_string(mem) + count(mem) > 1 + not mem_multiple(substring(mem, count(mem) - 1, -1)) + not mem_multiple(substring(mem, count(mem) - 2, -1)) + suffix := "" + } + + get_suffix(mem) = suffix { + is_string(mem) + count(mem) == 1 + not mem_multiple(substring(mem, count(mem) - 1, -1)) + suffix := "" + } + + get_suffix(mem) = suffix { + is_string(mem) + count(mem) == 0 + suffix := "" + } + + canonify_mem(orig) = new { + is_number(orig) + new := orig * 1000 + } + + canonify_mem(orig) = new { + not is_number(orig) + suffix := get_suffix(orig) + raw := replace(orig, suffix, "") + re_match("^[0-9]+$", raw) + new := to_number(raw) * mem_multiple(suffix) + } + + canonify_storage(orig) = new { + is_number(orig) + new := orig + } + + canonify_storage(orig) = new { + not is_number(orig) + suffix := get_suffix(orig) + raw := replace(orig, suffix, "") + re_match("^[0-9]+$", raw) + new := to_number(raw) * mem_multiple(suffix) + } + + canonify_cpu(orig) = new { + is_number(orig) + new := orig * 1000 + } + + canonify_cpu(orig) = new { + not is_number(orig) + endswith(orig, "m") + new := to_number(replace(orig, "m", "")) + } + + canonify_cpu(orig) = new { + not is_number(orig) + not endswith(orig, "m") + re_match("^[0-9]+$", orig) + new := to_number(orig) * 1000 + } + + dropped_capability(container, cap) { + container.securityContext.capabilities.drop[_] == cap + } + + added_capability(container, cap) { + container.securityContext.capabilities.add[_] == cap + } + + no_read_only_filesystem(c) { + not has_field(c, "securityContext") + } + + no_read_only_filesystem(c) { + has_field(c, "securityContext") + not has_field(c.securityContext, "readOnlyRootFilesystem") + } + + priviledge_escalation_allowed(c) { + not has_field(c, "securityContext") + } + + priviledge_escalation_allowed(c) { + has_field(c, "securityContext") + has_field(c.securityContext, "allowPrivilegeEscalation") + } + - |- + package lib.openshift + + import data.lib.konstraint + + is_deploymentconfig { + lower(konstraint.object.apiVersion) == "apps.openshift.io/v1" + lower(konstraint.object.kind) == "deploymentconfig" + } + + is_route { + lower(konstraint.object.apiVersion) == "route.openshift.io/v1" + lower(konstraint.object.kind) == "route" + } + + is_workload_kind { + is_deploymentconfig + } + + is_workload_kind { + konstraint.is_statefulset + } + + is_workload_kind { + konstraint.is_daemonset + } + + is_workload_kind { + konstraint.is_deployment + } + + is_all_kind { + is_workload_kind + } + + is_all_kind { + konstraint.is_service + } + + is_all_kind { + is_route + } + + pods[pod] { + is_deploymentconfig + pod = konstraint.object.spec.template + } + + pods[pod] { + pod = konstraint.pods[_] + } + + containers[container] { + pods[pod] + all_containers = konstraint.pod_containers(pod) + container = all_containers[_] + } + + containers[container] { + container = konstraint.containers[_] + } + rego: |- + package ocp.bestpractices.container_livenessprobe_notset + + import data.lib.konstraint + import data.lib.openshift + + violation[msg] { + openshift.is_workload_kind + + container := openshift.containers[_] + + konstraint.missing_field(container, "livenessProbe") + obj := konstraint.object + + msg := konstraint.format(sprintf("%s/%s: container '%s' has no livenessProbe. See: https://docs.openshift.com/container-platform/latest/applications/application-health.html", [obj.kind, obj.metadata.name, container.name])) + } + target: admission.k8s.gatekeeper.sh + - complianceType: musthave + objectDefinition: + apiVersion: constraints.gatekeeper.sh/v1beta1 + kind: ContainerLivenessprobeNotset + metadata: + name: containerlivenessprobenotset + spec: + enforcementAction: dryrun + match: + kinds: + - apiGroups: + - apps.openshift.io + - apps + kinds: + - DeploymentConfig + - DaemonSet + - Deployment + - StatefulSet + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: policy-gatekeeper-audit-liveness + spec: + remediationAction: inform # will be overridden by remediationAction in parent policy + severity: low + object-templates: + - complianceType: musthave + objectDefinition: + apiVersion: constraints.gatekeeper.sh/v1beta1 + kind: ContainerLivenessprobeNotset + metadata: + name: containerlivenessprobenotset + status: + totalViolations: 0 + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: policy-gatekeeper-admission-liveness + spec: + remediationAction: inform # will be overridden by remediationAction in parent policy + severity: low + object-templates: + - complianceType: mustnothave + objectDefinition: + apiVersion: v1 + kind: Event + metadata: + namespace: openshift-gatekeeper-system # set it to the actual namespace where gatekeeper is running if different + annotations: + constraint_action: deny + constraint_kind: ContainerLivenessprobeNotset + constraint_name: containerlivenessprobenotset + event_type: violation +--- +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: binding-policy-gatekeeper-containerlivenessprobenotset +placementRef: + name: placement-policy-gatekeeper-containerlivenessprobenotset + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: policy-gatekeeper-livenessprobe + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: placement-policy-gatekeeper-containerlivenessprobenotset +spec: + clusterConditions: + - status: "True" + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - { key: policy, operator: In, values: ["opa"] } \ No newline at end of file diff --git a/components/policies/opa/gatekeeper-probes-readinessnotset.yaml b/components/policies/opa/gatekeeper-probes-readinessnotset.yaml new file mode 100644 index 0000000..3b1386d --- /dev/null +++ b/components/policies/opa/gatekeeper-probes-readinessnotset.yaml @@ -0,0 +1,459 @@ +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: policy-gatekeeper-readinessprobe + annotations: + policy.open-cluster-management.io/standards: NIST SP 800-53 + policy.open-cluster-management.io/categories: CM Configuration Management + policy.open-cluster-management.io/controls: CM-2 Baseline Configuration +spec: + remediationAction: enforce + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: policy-gatekeeper-containerreadinessprobenotset + spec: + remediationAction: enforce + severity: low + object-templates: + - complianceType: musthave + objectDefinition: + apiVersion: templates.gatekeeper.sh/v1beta1 + kind: ConstraintTemplate + metadata: + creationTimestamp: null + name: containerreadinessprobenotset + spec: + crd: + spec: + names: + kind: ContainerReadinessprobeNotset + targets: + - libs: + - | + package lib.konstraint + + default is_gatekeeper = false + + is_gatekeeper { + has_field(input, "review") + has_field(input.review, "object") + } + + object = input { + not is_gatekeeper + } + + object = input.review.object { + is_gatekeeper + } + + format(msg) = gatekeeper_format { + is_gatekeeper + gatekeeper_format = {"msg": msg} + } + + format(msg) = msg { + not is_gatekeeper + } + + name = object.metadata.name + + kind = object.kind + + has_field(obj, field) { + obj[field] + } + + missing_field(obj, field) = true { + obj[field] == "" + } + + missing_field(obj, field) = true { + not has_field(obj, field) + } + + is_service { + lower(kind) == "service" + } + + is_statefulset { + lower(kind) == "statefulset" + } + + is_daemonset { + lower(kind) == "daemonset" + } + + is_deployment { + lower(kind) == "deployment" + } + + is_pod { + lower(kind) == "pod" + } + + is_namespace { + lower(kind) == "namespace" + } + + is_workload { + containers[_] + } + + pod_containers(pod) = all_containers { + keys = {"containers", "initContainers"} + all_containers = [c | keys[k]; c = pod.spec[k][_]] + } + + containers[container] { + pods[pod] + all_containers = pod_containers(pod) + container = all_containers[_] + } + + containers[container] { + all_containers = pod_containers(object) + container = all_containers[_] + } + + container_images[image] { + containers[container] + image = container.image + } + + container_images[image] { + image = object.spec.image + } + + split_image(image) = [image, "latest"] { + not contains(image, ":") + } + + split_image(image) = [image_name, tag] { + [image_name, tag] = split(image, ":") + } + + pods[pod] { + is_statefulset + pod = object.spec.template + } + + pods[pod] { + is_daemonset + pod = object.spec.template + } + + pods[pod] { + is_deployment + pod = object.spec.template + } + + pods[pod] { + is_pod + pod = object + } + + volumes[volume] { + pods[pod] + volume = pod.spec.volumes[_] + } + + mem_multiple("E") = 1000000000000000000000 { true } + + mem_multiple("P") = 1000000000000000000 { true } + + mem_multiple("T") = 1000000000000000 { true } + + mem_multiple("G") = 1000000000000 { true } + + mem_multiple("M") = 1000000000 { true } + + mem_multiple("k") = 1000000 { true } + + mem_multiple("") = 1000 { true } + + mem_multiple("m") = 1 { true } + + mem_multiple("Ki") = 1024000 { true } + + mem_multiple("Mi") = 1048576000 { true } + + mem_multiple("Gi") = 1073741824000 { true } + + mem_multiple("Ti") = 1099511627776000 { true } + + mem_multiple("Pi") = 1125899906842624000 { true } + + mem_multiple("Ei") = 1152921504606846976000 { true } + + get_suffix(mem) = suffix { + not is_string(mem) + suffix := "" + } + + get_suffix(mem) = suffix { + is_string(mem) + count(mem) > 0 + suffix := substring(mem, count(mem) - 1, -1) + mem_multiple(suffix) + } + + get_suffix(mem) = suffix { + is_string(mem) + count(mem) > 1 + suffix := substring(mem, count(mem) - 2, -1) + mem_multiple(suffix) + } + + get_suffix(mem) = suffix { + is_string(mem) + count(mem) > 1 + not mem_multiple(substring(mem, count(mem) - 1, -1)) + not mem_multiple(substring(mem, count(mem) - 2, -1)) + suffix := "" + } + + get_suffix(mem) = suffix { + is_string(mem) + count(mem) == 1 + not mem_multiple(substring(mem, count(mem) - 1, -1)) + suffix := "" + } + + get_suffix(mem) = suffix { + is_string(mem) + count(mem) == 0 + suffix := "" + } + + canonify_mem(orig) = new { + is_number(orig) + new := orig * 1000 + } + + canonify_mem(orig) = new { + not is_number(orig) + suffix := get_suffix(orig) + raw := replace(orig, suffix, "") + re_match("^[0-9]+$", raw) + new := to_number(raw) * mem_multiple(suffix) + } + + canonify_storage(orig) = new { + is_number(orig) + new := orig + } + + canonify_storage(orig) = new { + not is_number(orig) + suffix := get_suffix(orig) + raw := replace(orig, suffix, "") + re_match("^[0-9]+$", raw) + new := to_number(raw) * mem_multiple(suffix) + } + + canonify_cpu(orig) = new { + is_number(orig) + new := orig * 1000 + } + + canonify_cpu(orig) = new { + not is_number(orig) + endswith(orig, "m") + new := to_number(replace(orig, "m", "")) + } + + canonify_cpu(orig) = new { + not is_number(orig) + not endswith(orig, "m") + re_match("^[0-9]+$", orig) + new := to_number(orig) * 1000 + } + + dropped_capability(container, cap) { + container.securityContext.capabilities.drop[_] == cap + } + + added_capability(container, cap) { + container.securityContext.capabilities.add[_] == cap + } + + no_read_only_filesystem(c) { + not has_field(c, "securityContext") + } + + no_read_only_filesystem(c) { + has_field(c, "securityContext") + not has_field(c.securityContext, "readOnlyRootFilesystem") + } + + priviledge_escalation_allowed(c) { + not has_field(c, "securityContext") + } + + priviledge_escalation_allowed(c) { + has_field(c, "securityContext") + has_field(c.securityContext, "allowPrivilegeEscalation") + } + - |- + package lib.openshift + + import data.lib.konstraint + + is_deploymentconfig { + lower(konstraint.object.apiVersion) == "apps.openshift.io/v1" + lower(konstraint.object.kind) == "deploymentconfig" + } + + is_route { + lower(konstraint.object.apiVersion) == "route.openshift.io/v1" + lower(konstraint.object.kind) == "route" + } + + is_workload_kind { + is_deploymentconfig + } + + is_workload_kind { + konstraint.is_statefulset + } + + is_workload_kind { + konstraint.is_daemonset + } + + is_workload_kind { + konstraint.is_deployment + } + + is_all_kind { + is_workload_kind + } + + is_all_kind { + konstraint.is_service + } + + is_all_kind { + is_route + } + + pods[pod] { + is_deploymentconfig + pod = konstraint.object.spec.template + } + + pods[pod] { + pod = konstraint.pods[_] + } + + containers[container] { + pods[pod] + all_containers = konstraint.pod_containers(pod) + container = all_containers[_] + } + + containers[container] { + container = konstraint.containers[_] + } + rego: |- + package ocp.bestpractices.container_readinessprobe_notset + + import data.lib.konstraint + import data.lib.openshift + + violation[msg] { + openshift.is_workload_kind + + container := openshift.containers[_] + + konstraint.missing_field(container, "readinessProbe") + obj := konstraint.object + + msg := konstraint.format(sprintf("%s/%s: container '%s' has no readinessProbe. See: https://docs.openshift.com/container-platform/4.4/applications/application-health.html", [obj.kind, obj.metadata.name, container.name])) + } + target: admission.k8s.gatekeeper.sh + - complianceType: musthave + objectDefinition: + apiVersion: constraints.gatekeeper.sh/v1beta1 + kind: ContainerReadinessprobeNotset + metadata: + name: containerreadinessprobenotset + spec: + enforcementAction: dryrun + match: + kinds: + - apiGroups: + - apps.openshift.io + - apps + kinds: + - DeploymentConfig + - DaemonSet + - Deployment + - StatefulSet + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: policy-gatekeeper-audit-readiness + spec: + remediationAction: inform # will be overridden by remediationAction in parent policy + severity: low + object-templates: + - complianceType: musthave + objectDefinition: + apiVersion: constraints.gatekeeper.sh/v1beta1 + kind: ContainerReadinessprobeNotset + metadata: + name: containerreadinessprobenotset + status: + totalViolations: 0 + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: policy-gatekeeper-admission-readiness + spec: + remediationAction: inform # will be overridden by remediationAction in parent policy + severity: low + object-templates: + - complianceType: mustnothave + objectDefinition: + apiVersion: v1 + kind: Event + metadata: + namespace: openshift-gatekeeper-system # set it to the actual namespace where gatekeeper is running if different + annotations: + constraint_action: deny + constraint_kind: ContainerReadinessprobeNotset + constraint_name: containerreadinessprobenotset + event_type: violation +--- +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: binding-policy-gatekeeper-containerreadinessprobenotset +placementRef: + name: placement-policy-gatekeeper-containerreadinessprobenotset + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: policy-gatekeeper-readinessprobe + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: placement-policy-gatekeeper-containerreadinessprobenotset +spec: + clusterConditions: + - status: "True" + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - { key: policy, operator: In, values: ["opa"] } \ No newline at end of file