apiVersion: v1
kind: Secret
metadata:
  name: kvoltoweb-harbor-secret-c830efec
immutable: false
stringData:
  .dockerconfigjson: |-
    {
        "auths": {
            "vcharbor.zamg.ac.at": {
                "auth": "cm9ib3QkaG9tZXBhZ2U6NHZIV1FXejB6M2IyYUZPcVppY1MxZ2s2a1JPWDdyeFQ="
            }
        }
    }
type: kubernetes.io/dockerconfigjson
---
apiVersion: acid.zalan.do/v1
kind: postgresql
metadata:
  labels:
    app.kubernetes.io/component: database
    app.kubernetes.io/instance: postgresql
    app.kubernetes.io/name: plone-postgresql
    app.kubernetes.io/part-of: plone
  name: kvoltoweb-db-c8d1911b
spec:
  allowedSourceRanges:
    - 10.0.0.0/8
  databases:
    plone: plone
  numberOfInstances: 2
  postgresql:
    version: "15"
  resources:
    limits:
      cpu: 1000m
      memory: 1Gi
    requests:
      cpu: 300m
      memory: 400Mi
  teamId: plone
  users:
    plone:
      - superuser
      - createdb
  volume:
    size: 1Gi
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  labels:
    app.kubernetes.io/component: kvoltoweb-opensearch-cluster-master
    app.kubernetes.io/instance: kvoltoweb-opensearch-c854d335
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: opensearch
    app.kubernetes.io/version: 2.16.0
    helm.sh/chart: opensearch-2.22.0
  name: kvoltoweb-opensearch-cluster-master-pdb
spec:
  maxUnavailable: 1
  selector:
    matchLabels:
      app.kubernetes.io/instance: kvoltoweb-opensearch-c854d335
      app.kubernetes.io/name: opensearch
---
apiVersion: v1
kind: ConfigMap
metadata:
  labels:
    app.kubernetes.io/component: kvoltoweb-opensearch-cluster-master
    app.kubernetes.io/instance: kvoltoweb-opensearch-c854d335
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: opensearch
    app.kubernetes.io/version: 2.16.0
    helm.sh/chart: opensearch-2.22.0
  name: kvoltoweb-opensearch-cluster-master-config
data:
  opensearch.yml: |
    cluster.name: opensearch-cluster

    # Bind to all interfaces because we don't know what IP address Docker will assign to us.
    network.host: 0.0.0.0

    # Setting network.host to a non-loopback address enables the annoying bootstrap checks. "Single-node" mode disables them again.
    # Implicitly done if ".singleNode" is set to "true".
    # discovery.type: single-node

    # Start OpenSearch Security Demo Configuration
    # WARNING: revise all the lines below before you go into production
    plugins:
      security:
        ssl:
          transport:
            pemcert_filepath: esnode.pem
            pemkey_filepath: esnode-key.pem
            pemtrustedcas_filepath: root-ca.pem
            enforce_hostname_verification: false
          http:
            enabled: true
            pemcert_filepath: esnode.pem
            pemkey_filepath: esnode-key.pem
            pemtrustedcas_filepath: root-ca.pem
        allow_unsafe_democertificates: true
        allow_default_init_securityindex: true
        authcz:
          admin_dn:
            - CN=kirk,OU=client,O=client,L=test,C=de
        audit.type: internal_opensearch
        enable_snapshot_restore_privilege: true
        check_snapshot_restore_write_privileges: true
        restapi:
          roles_enabled: ["all_access", "security_rest_api_access"]
        system_indices:
          enabled: true
          indices:
            [
              ".opendistro-alerting-config",
              ".opendistro-alerting-alert*",
              ".opendistro-anomaly-results*",
              ".opendistro-anomaly-detector*",
              ".opendistro-anomaly-checkpoints",
              ".opendistro-anomaly-detection-state",
              ".opendistro-reports-*",
              ".opendistro-notifications-*",
              ".opendistro-notebooks",
              ".opendistro-asynchronous-search-response*",
            ]
    ######## End OpenSearch Security Demo Configuration ########
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/component: kvoltoweb-opensearch-cluster-master
    app.kubernetes.io/instance: kvoltoweb-opensearch-c854d335
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: opensearch
    app.kubernetes.io/version: 2.16.0
    helm.sh/chart: opensearch-2.22.0
  name: opensearch-cluster-master
spec:
  ports:
    - name: http
      port: 9200
      protocol: TCP
    - name: transport
      port: 9300
      protocol: TCP
  selector:
    app.kubernetes.io/instance: kvoltoweb-opensearch-c854d335
    app.kubernetes.io/name: opensearch
  type: ClusterIP
---
apiVersion: v1
kind: Service
metadata:
  annotations:
    service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
  labels:
    app.kubernetes.io/component: kvoltoweb-opensearch-cluster-master
    app.kubernetes.io/instance: kvoltoweb-opensearch-c854d335
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: opensearch
    app.kubernetes.io/version: 2.16.0
    helm.sh/chart: opensearch-2.22.0
  name: opensearch-cluster-master-headless
spec:
  clusterIP: None
  ports:
    - name: http
      port: 9200
    - name: transport
      port: 9300
    - name: metrics
      port: 9600
  publishNotReadyAddresses: true
  selector:
    app.kubernetes.io/instance: kvoltoweb-opensearch-c854d335
    app.kubernetes.io/name: opensearch
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  annotations:
    majorVersion: "2"
  labels:
    app.kubernetes.io/component: kvoltoweb-opensearch-cluster-master
    app.kubernetes.io/instance: kvoltoweb-opensearch-c854d335
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: opensearch
    app.kubernetes.io/version: 2.16.0
    helm.sh/chart: opensearch-2.22.0
  name: kvoltoweb-opensearch-cluster-master
spec:
  podManagementPolicy: Parallel
  replicas: 3
  selector:
    matchLabels:
      app.kubernetes.io/instance: kvoltoweb-opensearch-c854d335
      app.kubernetes.io/name: opensearch
  serviceName: opensearch-cluster-master-headless
  template:
    metadata:
      annotations:
        configchecksum: be6f1fa2bf7f9cd924969986c83603db72d708e9af3e069cfa62a4cf5188eb5
      labels:
        app.kubernetes.io/component: kvoltoweb-opensearch-cluster-master
        app.kubernetes.io/instance: kvoltoweb-opensearch-c854d335
        app.kubernetes.io/managed-by: Helm
        app.kubernetes.io/name: opensearch
        app.kubernetes.io/version: 2.16.0
        helm.sh/chart: opensearch-2.22.0
      name: kvoltoweb-opensearch-cluster-master
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - podAffinityTerm:
                labelSelector:
                  matchExpressions:
                    - key: app.kubernetes.io/instance
                      operator: In
                      values:
                        - kvoltoweb-opensearch-c854d335
                    - key: app.kubernetes.io/name
                      operator: In
                      values:
                        - opensearch
                topologyKey: kubernetes.io/hostname
              weight: 1
      automountServiceAccountToken: false
      containers:
        - command:
            - sh
            - -c
            - |
              #!/usr/bin/env bash
              set -euo pipefail
              ./bin/opensearch-plugin install -b ingest-attachment

              bash opensearch-docker-entrypoint.sh
          env:
            - name: node.name
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: cluster.initial_master_nodes
              value: kvoltoweb-opensearch-cluster-master-0,kvoltoweb-opensearch-cluster-master-1,kvoltoweb-opensearch-cluster-master-2,
            - name: discovery.seed_hosts
              value: opensearch-cluster-master-headless
            - name: cluster.name
              value: kvoltoweb-opensearch-cluster
            - name: network.host
              value: 0.0.0.0
            - name: OPENSEARCH_JAVA_OPTS
              value: -Xmx512M -Xms512M
            - name: node.roles
              value: master,ingest,data,remote_cluster_client,
            - name: OPENSEARCH_INITIAL_ADMIN_PASSWORD
              value: nachou7A-ahL0Ao4m-Ohx4aiCh
          image: opensearchproject/opensearch:2
          imagePullPolicy: IfNotPresent
          name: opensearch
          ports:
            - containerPort: 9200
              name: http
            - containerPort: 9300
              name: transport
            - containerPort: 9600
              name: metrics
          readinessProbe:
            failureThreshold: 3
            periodSeconds: 5
            tcpSocket:
              port: 9200
            timeoutSeconds: 3
          resources:
            limits:
              cpu: 500m
              memory: 1Gi
            requests:
              cpu: 100m
              memory: 100Mi
          securityContext:
            capabilities:
              drop:
                - ALL
            runAsNonRoot: true
            runAsUser: 1000
          startupProbe:
            failureThreshold: 30
            initialDelaySeconds: 5
            periodSeconds: 10
            tcpSocket:
              port: 9200
            timeoutSeconds: 3
          volumeMounts:
            - mountPath: /usr/share/opensearch/data
              name: kvoltoweb-opensearch-cluster-master
            - mountPath: /usr/share/opensearch/config/opensearch.yml
              name: config-emptydir
              subPath: opensearch.yml
      enableServiceLinks: true
      initContainers:
        - args:
            - chown -R 1000:1000 /usr/share/opensearch/data
          command:
            - sh
            - -c
          image: busybox:latest
          imagePullPolicy: IfNotPresent
          name: fsgroup-volume
          resources:
            limits:
              cpu: 200m
              memory: 1Gi
            requests:
              cpu: 50m
              memory: 100Mi
          securityContext:
            runAsUser: 0
          volumeMounts:
            - mountPath: /usr/share/opensearch/data
              name: kvoltoweb-opensearch-cluster-master
        - command:
            - sh
            - -c
            - |
              #!/usr/bin/env bash
              cp -r /tmp/configfolder/*  /tmp/config/
          image: opensearchproject/opensearch:2
          imagePullPolicy: IfNotPresent
          name: configfile
          resources:
            limits:
              cpu: 200m
              memory: 1Gi
            requests:
              cpu: 50m
              memory: 100Mi
          volumeMounts:
            - mountPath: /tmp/config/
              name: config-emptydir
            - mountPath: /tmp/configfolder/opensearch.yml
              name: config
              subPath: opensearch.yml
      securityContext:
        fsGroup: 1000
        runAsUser: 1000
      terminationGracePeriodSeconds: 120
      volumes:
        - configMap:
            name: kvoltoweb-opensearch-cluster-master-config
          name: config
        - emptyDir: {}
          name: config-emptydir
  updateStrategy:
    type: RollingUpdate
  volumeClaimTemplates:
    - metadata:
        name: kvoltoweb-opensearch-cluster-master
      spec:
        accessModes:
          - ReadWriteOnce
        resources:
          requests:
            storage: 8Gi
---
apiVersion: v1
kind: ConfigMap
metadata:
  labels:
    app.kubernetes.io/instance: kvoltoweb-valkey-c854d335
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: valkey
    app.kubernetes.io/version: 7.2.6
    helm.sh/chart: valkey-1.0.2
  name: kvoltoweb-valkey-c854d335-scripts
data:
  init.sh: |
    #!/bin/bash
    VALKEY_CONFIG=/data/conf/valkey.conf
    SENTINEL_CONFIG=/data/conf/sentinel.conf
    if [ -f "/data/init.log" ]; then
      echo "Detected restart of this instance ($HOSTNAME)"
      echo "## This was the previous log:"
      cat /data/init.log
      echo "## End of previous log"
    fi

    # Log a message during initialization phase
    # $1 - the log message
    log() {
      echo "$(date) $1"
      echo "$(date) $1" >>/data/init.log
    }

    # Creating valkey base configuration
    configure_valkey_base() {
      log "Creating valkey base configuration"
      mkdir -p /data/conf
      rm -f $VALKEY_CONFIG

      log "Setting valkey server defaults"
      echo "port 6379" >>$VALKEY_CONFIG
      echo "protected-mode no" >>$VALKEY_CONFIG
      echo "bind 0.0.0.0" >>$VALKEY_CONFIG
      echo "dir /data" >>$VALKEY_CONFIG
      log "Finished creating base configuration"
    }

    configure_valkey_ext() {
      if [ -f /usr/local/etc/valkey/valkey.conf ]; then
          log "Adding optional valkey configuration"
          cat /usr/local/etc/valkey/valkey.conf >>$VALKEY_CONFIG
      fi
      if [ -d /extravalkeyconfigs ]; then
        log "Adding extra valkey configs to valkey configuration"
        cat /extravalkeyconfigs/* >>$VALKEY_CONFIG
      fi
    }

    test_master_alive() {
      TEST="$(timeout 2s valkey-cli -h $MASTER -p 6379 ping)"
      if [ -z "$TEST" ]; then
        log "Master is not alive"
        return 1
      fi
      log "Master is alive"
      return 0
    }

    test_valid_dns() {
      KNOWN_HOSTS=($(getent hosts kvoltoweb-valkey-c854d335-headless.mxplone.svc.cluster.local | awk '{ print $1 }'))
      log "## Known hosts for headless service kvoltoweb-valkey-c854d335-headless.mxplone.svc.cluster.local:"
      for AHOSTIP in "${KNOWN_HOSTS[@]}"; do
        AHOSTNAME=$(getent hosts $AHOSTIP | awk '{print $2}')
        log "${AHOSTIP} ${AHOSTNAME}"
      done
      log "#####"
      MASTERENTRY="$(getent hosts $MASTER | awk '{ print $1 }')"
    }

    configure_sentinel() {
      log "Configuring sentinel server..."
      rm -f $SENTINEL_CONFIG

      log "Setting sentinel defaults"
      if [ -z "$MASTER" ]; then
        MASTER="$(getent hosts $HOSTNAME | awk '{ print $1 }')"
        log "No master found - Configuring sentinel for master $HOSTNAME with address $MASTER"
        echo "sentinel monitor valkeyha $MASTER 6379 2" >>$SENTINEL_CONFIG
      else
        log "Valkey master was found - Configuring sentinel for master address $MASTER"
        echo "sentinel monitor valkeyha $MASTER 6379 2" >>$SENTINEL_CONFIG
      fi
      echo "sentinel down-after-milliseconds valkeyha 30000" >>$SENTINEL_CONFIG
      echo "sentinel failover-timeout valkeyha 180000" >>$SENTINEL_CONFIG
    }

    configure_sentinel_ext() {
      if [ -f /usr/local/etc/valkey/sentinel.conf ]; then
          log "Adding optional sentinel configuration settings"
          cat /usr/local/etc/valkey/sentinel.conf >>$SENTINEL_CONFIG
      fi
      if [ -d /extrasentinelconfigs ]; then
        log "Adding extra sentinel configs to sentinel configuration"
        cat /extrasentinelconfigs/* >>$SENTINEL_CONFIG
      fi
      log "Configuring sentinel server finished."
    }

    configure_valkey_cluster() {
      log "Try to resolve cluster service.."
      SERVICE="$(getent hosts kvoltoweb-valkey-c854d335)"
      if [ -z "$SERVICE" ]; then
        log "Can't resolve service - Will restart after DNS failure wait"
        sleep 15
        log "Restart"
        exit 1
      else
        log "Service resolved: ${SERVICE}"
      fi
      log "Try to detect cluster master.."
      MASTER="$(timeout 2s valkey-cli -h kvoltoweb-valkey-c854d335 -p 26379 sentinel get-master-addr-by-name valkeyha | head -n 1)"
      if [ -z "$MASTER" ]; then
        log "No master found - This instance ($HOSTNAME) will be master now"
      else
        log "Valkey master was found with address $MASTER - Checking host dns entry"
        test_valid_dns
        if [ -z "$MASTERENTRY" ]; then
          log "No valid DNS entry found!"
          if [ -f "/data/failover_restart" ]; then
            rm /data/failover_restart
            log "Forcing failover now"
            valkey-cli -h kvoltoweb-valkey-c854d335 -p 26379 sentinel failover valkeyha
          else
            log "Waiting for failover before restart"
            sleep 35
            touch /data/failover_restart
          fi
          log "Restart"
          exit 1
        else
          MASTER=$MASTERENTRY
          log "$MASTER has valid DNS entry"
          log "Checking if master is alive"
          test_master_alive
          if [ "$?" -eq "1" ]; then
            if [ -f "/data/failover_restart" ]; then
              rm /data/failover_restart
              log "Master is still dead! - forcing failover and retry pod initialization"
              valkey-cli -h kvoltoweb-valkey-c854d335 -p 26379 sentinel failover valkeyha
            else
              log "Dead master at address $MASTER detected! - waiting for failover"
              sleep 35
              touch /data/failover_restart
            fi
            log "Restart"
            exit 1
          else
            rm -f /data/failover_restart
            log "Setting this instance ($HOSTNAME) as replicaof $MASTER"
            echo "replicaof $MASTER 6379" >>$VALKEY_CONFIG
          fi
        fi
      fi
    }

    log "Creating configuration..."
    configure_valkey_base
    configure_valkey_ext
    log "Done."
    rm -f /data/init.log
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/instance: kvoltoweb-valkey-c854d335
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: valkey
    app.kubernetes.io/version: 7.2.6
    helm.sh/chart: valkey-1.0.2
  name: kvoltoweb-valkey-c854d335-headless
spec:
  clusterIP: None
  ports:
    - name: valkey
      port: 6379
      protocol: TCP
      targetPort: valkey
  publishNotReadyAddresses: true
  selector:
    app.kubernetes.io/instance: kvoltoweb-valkey-c854d335
    app.kubernetes.io/name: valkey
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/instance: kvoltoweb-valkey-c854d335
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: valkey
    app.kubernetes.io/version: 7.2.6
    helm.sh/chart: valkey-1.0.2
  name: kvoltoweb-valkey-c854d335
spec:
  ports:
    - name: valkey
      port: 6379
      protocol: TCP
      targetPort: valkey
  selector:
    app.kubernetes.io/instance: kvoltoweb-valkey-c854d335
    app.kubernetes.io/name: valkey
  type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/instance: kvoltoweb-valkey-c854d335
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: valkey
    app.kubernetes.io/version: 7.2.6
    helm.sh/chart: valkey-1.0.2
  name: kvoltoweb-valkey-c854d335
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/instance: kvoltoweb-valkey-c854d335
      app.kubernetes.io/name: valkey
  strategy:
    type: Recreate
  template:
    metadata:
      annotations:
        checksum/customconfig: 01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b
        checksum/scripts: 4f088a92638c57bc941e026fd9fe2eb527effe1bb7132edde88ba7f0da009133
      labels:
        app.kubernetes.io/instance: kvoltoweb-valkey-c854d335
        app.kubernetes.io/name: valkey
    spec:
      containers:
        - args:
            - /data/conf/valkey.conf
          command:
            - valkey-server
          image: docker.io/valkey/valkey:7
          imagePullPolicy: IfNotPresent
          livenessProbe:
            exec:
              command:
                - sh
                - -c
                - valkey-cli ping
            failureThreshold: 3
            initialDelaySeconds: 15
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 5
          name: valkey-server
          ports:
            - containerPort: 6379
              name: valkey
              protocol: TCP
          readinessProbe:
            exec:
              command:
                - sh
                - -c
                - valkey-cli ping
            failureThreshold: 3
            initialDelaySeconds: 15
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 5
          resources:
            limits:
              cpu: 500m
              memory: 400Mi
            requests:
              cpu: 100m
              memory: 100Mi
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop:
                - ALL
            privileged: false
            readOnlyRootFilesystem: true
            runAsGroup: 999
            runAsNonRoot: true
            runAsUser: 999
          startupProbe:
            exec:
              command:
                - sh
                - -c
                - valkey-cli ping
            failureThreshold: 30
            initialDelaySeconds: 10
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 5
          volumeMounts:
            - mountPath: /data
              name: valkey-data
      initContainers:
        - command:
            - /scripts/init.sh
          image: docker.io/valkey/valkey:7
          imagePullPolicy: IfNotPresent
          name: valkey-init
          resources:
            limits:
              cpu: 500m
              memory: 400Mi
            requests:
              cpu: 100m
              memory: 100Mi
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop:
                - ALL
            privileged: false
            readOnlyRootFilesystem: true
            runAsGroup: 999
            runAsNonRoot: true
            runAsUser: 999
          volumeMounts:
            - mountPath: /data
              name: valkey-data
            - mountPath: /scripts
              name: scripts
      securityContext:
        fsGroup: 999
        supplementalGroups:
          - 999
      serviceAccountName: default
      volumes:
        - configMap:
            defaultMode: 365
            name: kvoltoweb-valkey-c854d335-scripts
          name: scripts
        - emptyDir: {}
          name: valkey-data
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/component: backend
    app.kubernetes.io/name: plone-backend-deployment
  name: kvoltoweb-plone-backend-deployment-c884a954
spec:
  replicas: 2
  selector:
    matchLabels:
      app: kvoltoweb-plone-backend-c89f8002
  template:
    metadata:
      labels:
        app: kvoltoweb-plone-backend-c89f8002
        app.kubernetes.io/component: backend
        app.kubernetes.io/managed-by: cdk8s-plone
        app.kubernetes.io/name: plone-backend
        app.kubernetes.io/part-of: plone
        app.kubernetes.io/version: backend-latest_frontend-latest
    spec:
      containers:
        - env:
            - name: SECRET_POSTGRESQL_USERNAME
              valueFrom:
                secretKeyRef:
                  key: username
                  name: plone.kvoltoweb-db-c8d1911b.credentials.postgresql.acid.zalan.do
            - name: SECRET_POSTGRESQL_PASSWORD
              valueFrom:
                secretKeyRef:
                  key: password
                  name: plone.kvoltoweb-db-c8d1911b.credentials.postgresql.acid.zalan.do
            - name: INDEX_SERVER
              value: opensearch-cluster-master:9200
            - name: INDEX_USE_SSL
              value: "1"
            - name: INDEX_OPENSEARCH
              value: "1"
            - name: INDEX_PASSWORD
              value: nachou7A-ahL0Ao4m-Ohx4aiCh
            - name: CELERY_BROKER
              value: redis://kvoltoweb-valkey-c854d335:6379/0
            - name: INSTANCE_db_storage
              value: relstorage
            - name: INSTANCE_db_blob_mode
              value: cache
            - name: INSTANCE_db_cache_size
              value: "5000"
            - name: INSTANCE_db_cache_size_bytes
              value: 1500MB
            - name: INSTANCE_db_relstorage
              value: postgresql
            - name: INSTANCE_db_relstorage_postgresql_dsn
              value: host='kvoltoweb-db-c8d1911b' dbname='plone' user='$(SECRET_POSTGRESQL_USERNAME)' password='$(SECRET_POSTGRESQL_PASSWORD)'
            - name: INSTANCE_db_relstorage_cache_local_mb
              value: "800"
          envFrom: []
          image: vcharbor.zamg.ac.at/homepage/backend:latest
          imagePullPolicy: Always
          livenessProbe:
            failureThreshold: 3
            httpGet:
              path: /
              port: 8080
            initialDelaySeconds: 30
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 5
          name: backend-container
          readinessProbe:
            failureThreshold: 3
            httpGet:
              path: /
              port: 8080
            initialDelaySeconds: 10
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 15
          resources:
            limits:
              cpu: 500m
              memory: 512Mi
            requests:
              cpu: 200m
              memory: 256Mi
      imagePullSecrets:
        - name: kvoltoweb-harbor-secret-c830efec
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  labels:
    app.kubernetes.io/managed-by: cdk8s-plone
    app.kubernetes.io/part-of: plone
  name: kvoltoweb-plone-backend-pdb-c83da71e
spec:
  minAvailable: 1
  selector:
    matchLabels:
      app: kvoltoweb-plone-backend-c89f8002
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/component: service
    app.kubernetes.io/managed-by: cdk8s-plone
    app.kubernetes.io/name: plone-backend-service
    app.kubernetes.io/part-of: plone
  name: kvoltoweb-plone-backend-service-c8892406
spec:
  ports:
    - name: backend-http
      port: 8080
      targetPort: 8080
  selector:
    app: kvoltoweb-plone-backend-c89f8002
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/component: frontend
    app.kubernetes.io/name: plone-frontend-deployment
  name: kvoltoweb-plone-frontend-deployment-c86487e8
spec:
  replicas: 2
  selector:
    matchLabels:
      app: kvoltoweb-plone-frontend-c8a78511
  template:
    metadata:
      labels:
        app: kvoltoweb-plone-frontend-c8a78511
        app.kubernetes.io/component: frontend
        app.kubernetes.io/managed-by: cdk8s-plone
        app.kubernetes.io/name: plone-frontend
        app.kubernetes.io/part-of: plone
        app.kubernetes.io/version: backend-latest_frontend-latest
    spec:
      containers:
        - env:
            - name: RAZZLE_INTERNAL_API_PATH
              value: http://kvoltoweb-plone-backend-service-c8892406:8080/Plone
          envFrom: []
          image: vcharbor.zamg.ac.at/homepage/frontend:latest
          imagePullPolicy: Always
          livenessProbe:
            failureThreshold: 3
            httpGet:
              path: /
              port: 3000
            initialDelaySeconds: 30
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 5
          name: frontend-container
          readinessProbe:
            failureThreshold: 3
            httpGet:
              path: /
              port: 3000
            initialDelaySeconds: 10
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 15
          resources:
            limits:
              cpu: 500m
              memory: 1Gi
            requests:
              cpu: 200m
              memory: 256Mi
      imagePullSecrets:
        - name: kvoltoweb-harbor-secret-c830efec
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  labels:
    app.kubernetes.io/managed-by: cdk8s-plone
    app.kubernetes.io/part-of: plone
  name: kvoltoweb-plone-frontend-pdb-c8e45e74
spec:
  minAvailable: 1
  selector:
    matchLabels:
      app: kvoltoweb-plone-frontend-c8a78511
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/component: service
    app.kubernetes.io/managed-by: cdk8s-plone
    app.kubernetes.io/name: plone-frontend-service
    app.kubernetes.io/part-of: plone
  name: kvoltoweb-plone-frontend-service-c8020d45
spec:
  ports:
    - name: backend-http
      port: 3000
      targetPort: 3000
  selector:
    app: kvoltoweb-plone-frontend-c8a78511
---
apiVersion: v1
kind: ConfigMap
metadata:
  labels:
    app.kubernetes.io/component: kvoltoweb-ingest
    app.kubernetes.io/name: kvoltoweb-ingest-config
  name: kvoltoweb-ingest-config-c88fd2f1
data:
  mappings.json: |
    {
      "behaviors/plone.basic/title": {
        "type": "text",
        "fields": {
          "de": {
            "type": "text",
            "analyzer": "german"
          },
          "en": {
            "type": "text",
            "analyzer": "english"
          },
          "keyword": {
            "type": "keyword"
          }
        }
      },
      "behaviors/plone.basic/description": {
        "type": "text",
        "fields": {
          "de": {
            "type": "text",
            "analyzer": "german"
          },
          "en": {
            "type": "text",
            "analyzer": "english"
          }
        }
      },
      "behaviors/plone.categorization/subjects": {
        "type": "text",
        "fields": {
          "de": {
            "type": "text",
            "analyzer": "german"
          },
          "en": {
            "type": "text",
            "analyzer": "english"
          },
          "keyword": {
            "type": "keyword"
          }
        }
      },
      "behaviors/plone.allowdiscussion/allow_discussion": {
        "type": "boolean"
      },
      "behaviors/plone.categorization/language": {
        "type": "keyword"
      },
      "additional/preprocessed/blocks_plaintext": {
        "type": "text",
        "fields": {
          "de": {
            "type": "text",
            "analyzer": "german"
          },
          "en": {
            "type": "text",
            "analyzer": "english"
          }
        }
      },
      "plone.app.textfield.RichText": {
        "type": "nested",
        "dynamic": false,
        "include_in_root": true,
        "properties": {
          "data": {
            "type": "text",
            "fields": {
              "de": {
                "type": "text",
                "analyzer": "german"
              },
              "en": {
                "type": "text",
                "analyzer": "english"
              }
            }
          },
          "content-type": {
            "type": "keyword"
          },
          "encoding": {
            "type": "keyword"
          }
        }
      },
      "plone.namedfile.field.NamedBlobFile": {
        "pipeline": {
          "source": "{name}__data",
          "target": "{name}__extracted",
          "processors": [
            {
              "attachment": {
                "field": "{source}",
                "target_field": "{target}",
                "ignore_missing": true
              }
            },
            {
              "remove": {
                "field": "{source}",
                "ignore_missing": true
              }
            }
          ],
          "type": {
            "type": "nested",
            "dynamic": false,
            "include_in_root": true,
            "properties": {
              "author": {
                "type": "text"
              },
              "content": {
                "type": "text",
                "fields": {
                  "de": {
                    "type": "text",
                    "analyzer": "german"
                  },
                  "en": {
                    "type": "text",
                    "analyzer": "english"
                  }
                }
              },
              "content_length": {
                "type": "long"
              },
              "content_type": {
                "type": "keyword"
              },
              "date": {
                "type": "date"
              },
              "keywords": {
                "type": "keyword"
              },
              "language": {
                "type": "keyword"
              },
              "name": {
                "type": "text"
              },
              "title": {
                "type": "text",
                "fields": {
                  "de": {
                    "type": "text",
                    "analyzer": "german"
                  },
                  "en": {
                    "type": "text",
                    "analyzer": "english"
                  }
                }
              }
            }
          },
          "expansion": {
            "method": "fetch",
            "field": "download"
          }
        },
        "definition": {
          "type": "nested",
          "dynamic": false,
          "properties": {
            "content-type": {
              "type": "keyword"
            },
            "download": {
              "type": "text"
            },
            "filename": {
              "type": "text"
            },
            "size": {
              "type": "long"
            }
          }
        }
      },
      "plone.namedfile.field.NamedBlobImage": {
        "pipeline": {
          "source": "{name}__data",
          "target": "{name}__extracted",
          "processors": [
            {
              "attachment": {
                "field": "{source}",
                "target_field": "{target}",
                "ignore_missing": true
              }
            },
            {
              "remove": {
                "field": "{source}",
                "ignore_missing": true
              }
            }
          ],
          "type": {
            "type": "nested",
            "dynamic": false,
            "include_in_root": true,
            "properties": {
              "author": {
                "type": "text"
              },
              "content": {
                "type": "text",
                "fields": {
                  "de": {
                    "type": "text",
                    "analyzer": "german"
                  },
                  "en": {
                    "type": "text",
                    "analyzer": "english"
                  }
                }
              },
              "content_length": {
                "type": "long"
              },
              "content_type": {
                "type": "keyword"
              },
              "date": {
                "type": "date"
              },
              "keywords": {
                "type": "keyword"
              },
              "language": {
                "type": "keyword"
              },
              "name": {
                "type": "text"
              },
              "title": {
                "type": "text"
              }
            }
          },
          "expansion": {
            "method": "fetch",
            "field": "download"
          }
        },
        "definition": {
          "type": "nested",
          "dynamic": false,
          "properties": {
            "content-type": {
              "type": "keyword"
            },
            "download": {
              "type": "text"
            },
            "filename": {
              "type": "text"
            },
            "size": {
              "type": "long"
            },
            "height": {
              "type": "long"
            },
            "width": {
              "type": "long"
            },
            "scales": {
              "type": "nested",
              "dynamic": false,
              "properties": {
                "download": {
                  "type": "text"
                },
                "height": {
                  "type": "long"
                },
                "width": {
                  "type": "long"
                }
              }
            }
          }
        }
      },
      "plone.schema.jsonfield.JSONField": {
        "type": "text"
      },
      "plone.app.blocks.layoutbehavior.LayoutField": {
        "type": "text",
        "fields": {
          "de": {
            "type": "text",
            "analyzer": "german"
          },
          "en": {
            "type": "text",
            "analyzer": "english"
          }
        }
      },
      "z3c.relationfield.schema.RelationList": {
        "type": "nested",
        "dynamic": false,
        "properties": {
          "@id": {
            "type": "keyword"
          },
          "@type": {
            "type": "keyword"
          },
          "description": {
            "type": "text"
          },
          "review_state": {
            "type": "keyword"
          },
          "title": {
            "type": "text"
          }
        }
      },
      "z3c.relationfield.schema.RelationChoice": {
        "type": "nested",
        "dynamic": false,
        "properties": {
          "@id": {
            "type": "keyword"
          },
          "@type": {
            "type": "keyword"
          },
          "description": {
            "type": "text"
          },
          "review_state": {
            "type": "keyword"
          },
          "title": {
            "type": "text"
          }
        }
      },
      "zope.schema._bootstrapfields.Bool": {
        "type": "boolean"
      },
      "zope.schema._bootstrapfields.Int": {
        "type": "long"
      },
      "zope.schema._bootstrapfields.Text": {
        "type": "text",
        "fields": {
          "de": {
            "type": "text",
            "analyzer": "german"
          },
          "en": {
            "type": "text",
            "analyzer": "english"
          }
        }
      },
      "zope.schema._bootstrapfields.TextLine": {
        "type": "text",
        "fields": {
          "de": {
            "type": "text",
            "analyzer": "german"
          },
          "en": {
            "type": "text",
            "analyzer": "english"
          },
          "keyword": {
            "type": "keyword"
          }
        }
      },
      "zope.schema._field.ASCIILine": {
        "type": "keyword"
      },
      "zope.schema._field.Choice": {
        "type": "keyword"
      },
      "zope.schema._field.Datetime": {
        "type": "date"
      },
      "zope.schema._field.Dict": {
        "type": "object"
      },
      "zope.schema._field.Float": {
        "type": "double"
      },
      "zope.schema._field.List": {
        "type": "keyword"
      },
      "zope.schema._field.Tuple": {
        "type": "keyword"
      },
      "zope.schema._field.Set": {
        "type": "keyword"
      },
      "zope.schema._field.URI": {
        "type": "text"
      }
    }
  preprocessings.json: |
    [
      {
        "comment": "Remove all empty fields.",
        "action": "remove_empty"
      },
      {
        "comment": "Transform vocabularies to it token only form.",
        "action": "strip_vocabulary_term_titles"
      },
      {
        "comment": "Add section to content. Be careful with this, see comment in docstring ofmthis action.",
        "action": "enrich_with_section"
      },
      {
        "comment": "ProxyIndex needs this information, essential rewrite, do not remove",
        "action": "rewrite",
        "configuration": {
          "source": "@components/collectiveelastic/catalog_rid",
          "target": "rid",
          "enforce": true
        }
      },
      {
        "comment": "Schema for above rid, do not remove",
        "action": "additional_schema",
        "configuration": {
          "name": "rid",
          "field": "zope.schema._field.ASCIILine"
        }
      },
      {
        "comment": "Schema for above allowedRolesAndUsers, do not remove",
        "action": "additional_schema",
        "configuration": {
          "name": "allowedRolesAndUsers",
          "field": "zope.schema._field.List"
        }
      },
      {
        "comment": "CESP Restapi Volto endpoint needs this information, essential rewrite, do not remove",
        "action": "rewrite",
        "configuration": {
          "source": "@components/collectiveelastic/allowedRolesAndUsers",
          "target": "allowedRolesAndUsers",
          "enforce": true
        }
      },
      {
        "comment": "Remove plone.restapi parent information",
        "action": "remove",
        "configuration": {
          "target": "parent"
        }
      },
      {
        "comment": "Remove plone.restapi batching information",
        "action": "remove",
        "configuration": {
          "target": "batching"
        }
      },
      {
        "comment": "Remove plone.restapi lock information",
        "action": "remove",
        "configuration": {
          "target": "lock"
        }
      },
      {
        "comment": "If Volto is available, this is important for full text search, do not remove unless in Classic UI only environments",
        "action": "additional_schema",
        "configuration": {
          "name": "blocks_plaintext",
          "field": "zope.schema._bootstrapfields.Text"
        }
      },
      {
        "comment": "If Volto is available, this is important for full text search, do not remove unless in Classic UI only environments",
        "action": "rewrite",
        "configuration": {
          "source": "@components/collectiveelastic/blocks_plaintext",
          "target": "blocks_plaintext",
          "enforce": false
        }
      },
      {
        "comment": "If volto.blocks is available, remove all its fields.",
        "action": "full_remove",
        "configuration": {
          "section": "behaviors",
          "name": "volto.blocks"
        }
      },
      {
        "comment": "If volto.blocks.editable.layout is available, remove all its fields.",
        "action": "full_remove",
        "configuration": {
          "section": "behaviors",
          "name": "volto.blocks.editable.layout"
        }
      },
      {
        "comment": "We want the field to be called portal_type, not @type, so we rewrite it.",
        "action": "rewrite",
        "configuration": {
          "source": "@type",
          "target": "portal_type"
        }
      },
      {
        "comment": "Schema for above portal_type",
        "action": "additional_schema",
        "configuration": {
          "name": "portal_type",
          "field": "zope.schema._field.ASCIILine"
        }
      },
      {
        "comment": "After all the rewrites, we want to remove the @components field, as it is not needed anymore.",
        "action": "remove",
        "configuration": {
          "target": "@components"
        }
      },
      {
        "comment": "No need for restapi specific folder/collection information.",
        "action": "remove",
        "configuration": {
          "target": "items"
        }
      },
      {
        "comment": "No need for restapi specific information.",
        "action": "remove",
        "configuration": {
          "target": "items_total"
        }
      },
      {
        "comment": "No need for restapi specific information.",
        "action": "remove",
        "configuration": {
          "target": "previous_item"
        }
      },
      {
        "comment": "No need for restapi specific information.",
        "action": "remove",
        "configuration": {
          "target": "next_item"
        }
      },
      {
        "comment": "No need for restapi versioning related information.",
        "action": "remove",
        "configuration": {
          "target": "version"
        }
      },
      {
        "comment": "No need for plone.versioning related information.",
        "action": "full_remove",
        "configuration": {
          "section": "behaviors",
          "name": "plone.versioning"
        }
      },
      {
        "comment": "No need for plone.collection related information.",
        "action": "full_remove",
        "configuration": {
          "section": "behaviors",
          "name": "plone.collection"
        }
      },
      {
        "comment": "No need for plone.thumb_icon related information.",
        "action": "full_remove",
        "configuration": {
          "section": "behaviors",
          "name": "plone.thumb_icon"
        }
      },
      {
        "comment": "No need for plone.tableofcontents related information.",
        "action": "full_remove",
        "configuration": {
          "section": "behaviors",
          "name": "plone.tableofcontents"
        }
      }
    ]
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: kvoltoweb-ingest
    app.kubernetes.io/component: kvoltoweb-ingest
    app.kubernetes.io/name: kvoltoweb-ingest-deployment
    app.kubernetes.io/version: latest
  name: kvoltoweb-ingest-c8facb37
spec:
  replicas: 2
  selector:
    matchLabels:
      app: kvoltoweb-ingest
  template:
    metadata:
      labels:
        app: kvoltoweb-ingest
        app.kubernetes.io/component: kvoltoweb-ingest
        app.kubernetes.io/managed-by: cdk8s-plone
        app.kubernetes.io/name: kvoltoweb-ingest-deployment
        app.kubernetes.io/part-of: plone
        app.kubernetes.io/version: latest
    spec:
      containers:
        - env:
            - name: INDEX_SERVER
              value: opensearch-cluster-master:9200
            - name: INDEX_USE_SSL
              value: "1"
            - name: INDEX_OPENSEARCH
              value: "1"
            - name: INDEX_LOGIN
              value: admin
            - name: INDEX_PASSWORD
              value: nachou7A-ahL0Ao4m-Ohx4aiCh
            - name: PLONE_SERVICE
              value: http://kvoltoweb-plone-backend-service-c8892406:8080
            - name: PLONE_SITE_PREFIX_PATH
              value: Plone
            - name: PLONE_USER
              value: admin
            - name: PLONE_PASSWORD
              value: admin
            - name: CELERY_BROKER
              value: redis://kvoltoweb-valkey-c854d335:6379/0
            - name: MAPPINGS_FILE
              value: /config/mappings.json
            - name: PREPROCESSINGS_FILE
              value: /config/preprocessings.json
          image: ghcr.io/collective/collective.elastic.ingest:2
          imagePullPolicy: Always
          name: kvoltoweb-container
          resources:
            limits:
              cpu: 500m
              memory: 500Mi
            requests:
              cpu: 100m
              memory: 150Mi
          volumeMounts:
            - mountPath: /config
              name: config
      volumes:
        - configMap:
            name: kvoltoweb-ingest-config-c88fd2f1
          name: config
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  labels:
    app.kubernetes.io/instance: kvoltoweb-httpcache-c8732c11
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: kube-httpcache
    app.kubernetes.io/version: v0.8.1
    helm.sh/chart: kube-httpcache-0.8.1
  name: kvoltoweb-httpcache-c8732c11-kube-httpcache
spec:
  maxUnavailable: 1
  selector:
    matchLabels:
      app.kubernetes.io/instance: kvoltoweb-httpcache-c8732c11
      app.kubernetes.io/name: kube-httpcache
---
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    app.kubernetes.io/instance: kvoltoweb-httpcache-c8732c11
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: kube-httpcache
    app.kubernetes.io/version: v0.8.1
    helm.sh/chart: kube-httpcache-0.8.1
  name: kvoltoweb-httpcache-c8732c11-kube-httpcache
---
apiVersion: v1
kind: Secret
metadata:
  labels:
    app.kubernetes.io/instance: kvoltoweb-httpcache-c8732c11
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: kube-httpcache
    app.kubernetes.io/version: v0.8.1
    helm.sh/chart: kube-httpcache-0.8.1
  name: kvoltoweb-httpcache-c8732c11-kube-httpcache
data:
  secret: QkF4Y1duMVgzNDJEbVJhTU9teElZenVSVENQbXNURVo=
type: Opaque
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: kvoltoweb-httpcache-c8732c11-kube-httpcache
data:
  default.vcl.tmpl: |
    vcl 4.0;

    import std;
    import directors;

    probe ploneBackendProbe {
        .url = "/ok";
        .timeout = 5s;
        .interval = 15s;
        .window = 10;
        .threshold = 8;
        # .initial = 3;
    }
    backend ploneBackend {
        .host = "{{ .Env.BACKEND_SERVICE_NAME }}";
        .port = "{{ .Env.BACKEND_SERVICE_PORT }}";
        .probe = ploneBackendProbe;
        .connect_timeout = 0.5s;
        .first_byte_timeout = 120s;
        .between_bytes_timeout = 60s;
    }

    probe ploneFrontendProbe {
        .url = "/ok";
        .timeout = 5s;
        .interval = 15s;
        .window = 10;
        .threshold = 8;
        # .initial = 3;
    }
    backend ploneFrontend {
        .host = "{{ .Env.FRONTEND_SERVICE_NAME }}";
        .port = "{{ .Env.FRONTEND_SERVICE_PORT }}";
        .probe = ploneFrontendProbe;
        .connect_timeout = 0.5s;
        .first_byte_timeout = 120s;
        .between_bytes_timeout = 60s;
    }

    /* Only allow PURGE from kubernetes network */
    acl purge {
      "10.0.0.0/8";
    }

    sub detect_debug{
      # Requests with X-Varnish-Debug will display additional
      # information about requests
      unset req.http.x-vcl-debug;
      # Should be changed after switch to live
      #if (req.http.x-varnish-debug) {
      #    set req.http.x-vcl-debug = false;
      #}
      set req.http.x-vcl-debug = true;
    }

    sub detect_auth{
      unset req.http.x-auth;
      if (
          (req.http.Cookie && (
            req.http.Cookie ~ "__ac(_(name|password|persistent))?=" || req.http.Cookie ~ "_ZopeId" || req.http.Cookie ~ "auth_token")) ||
          (req.http.Authenticate) ||
          (req.http.Authorization)
      ) {
        set req.http.x-auth = true;
      }
    }

    sub detect_requesttype{
      unset req.http.x-varnish-reqtype;
      set req.http.x-varnish-reqtype = "Default";
      if (req.http.x-auth){
        set req.http.x-varnish-reqtype = "auth";
      } elseif (req.url ~ "\/@@(images|download|)\/?(.*)?$"){
        set req.http.x-varnish-reqtype = "blob";
      } elseif (req.url ~ "\/\+\+api\+\+/?(.*)?$") {
        set req.http.x-varnish-reqtype = "api";
      } else {
        set req.http.x-varnish-reqtype = "express";
      }
    }

    sub process_redirects{
      if (req.http.x-redirect-to) {
        return (synth(301, req.http.x-redirect-to));
      }
    }

    sub vcl_init {
      new lbPloneBackend = directors.round_robin();
      lbPloneBackend.add_backend(ploneBackend);

      new lbPloneFrontend = directors.round_robin();
      lbPloneFrontend.add_backend(ploneFrontend);
    }

    sub vcl_recv {
      # Annotate request with x-vcl-debug
      call detect_debug;

      # Annotate request with x-auth indicating if request is authenticated or not
      call detect_auth;

      # Annotate request with x-varnish-reqtype with a classification for the request
      call detect_requesttype;

      # Process redirects
      call process_redirects;

      # Routing: set the current Varnish backend to the matching Plone backend
      # Attention:
      # Confusing wording, we have two possible Varnish backends: the Plone frontend and the Plone backend *sigh*
      if ((req.url ~ "^/\+\+api\+\+") || (req.http.x-varnish-reqtype ~ "blob")) {
        set req.http.x-vcl-plone = "Backend";
        set req.backend_hint = lbPloneBackend.backend();
        # here we need a rewrite to add the virtualhost part of the URL for the Plone Backend
        set req.http.x-vcl-proto = "http";
        if (req.http.X-Forwarded-Proto) {
          set req.http.x-vcl-proto = req.http.X-Forwarded-Proto;
        }
        set req.url = "/VirtualHostBase/" + req.http.x-vcl-proto + "/" + req.http.host + "/Plone/VirtualHostRoot" + req.url;
      } else {
        set req.http.x-vcl-plone = "Frontend";
        set req.backend_hint = lbPloneFrontend.backend();
      }

      # short cut authenticated requests to pass
      if (req.http.x-auth) {
        return(pass);
      }

      # Sanitize cookies so they do not needlessly destroy cacheability for anonymous pages
      if (req.http.Cookie) {
        set req.http.Cookie = ";" + req.http.Cookie;
        set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";");
        set req.http.Cookie = regsuball(req.http.Cookie, ";(sticky|I18N_LANGUAGE|statusmessages|__ac|_ZopeId|__cp|beaker\.session|authomatic|serverid|__rf|auth_token)=", "; \1=");
        set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", "");
        set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", "");

        if (req.http.Cookie == "") {
            unset req.http.Cookie;
        }
      }

      # Handle the different request types
      if (req.method == "PURGE") {
          if (!client.ip ~ purge) {
              return (synth(405, "Not allowed."));
          } else {
              ban("req.url == " + req.url);
              return (synth(200, "Purged."));
          }

      } elseif (req.method == "BAN") {
          # Same ACL check as above:
          if (!client.ip ~ purge) {
              return (synth(405, "Not allowed."));
          }
          ban("req.http.host == " + req.http.host + "&& req.url == " + req.url);
          # Throw a synthetic page so the
          # request won't go to the backend.
          return (synth(200, "Ban added"));

      } elseif (req.method != "GET" &&
          req.method != "HEAD" &&
          req.method != "PUT" &&
          req.method != "POST" &&
          req.method != "PATCH" &&
          req.method != "TRACE" &&
          req.method != "OPTIONS" &&
          req.method != "DELETE") {
          /* Non-RFC2616 or CONNECT which is weird. */
          return (pipe);
      } elseif (req.method != "GET" &&
          req.method != "HEAD" &&
          req.method != "OPTIONS") {
          /* POST, PUT, PATCH will pass, always */
          return(pass);
      }

      return(hash);
    }

    sub vcl_pipe {
      /* This is not necessary if you do not do any request rewriting. */
      set req.http.connection = "close";
    }

    sub vcl_purge {
      return (synth(200, "PURGE: " + req.url + " - " + req.hash));
    }

    sub vcl_synth {
      if (resp.status == 301) {
        set resp.http.location = resp.reason;
        set resp.reason = "Moved";
        return (deliver);
      }
    }

    sub vcl_hit {
      if (obj.ttl >= 0s) {
        // A pure unadulterated hit, deliver it
        return (deliver);
      } elsif (obj.ttl + obj.grace > 0s) {
        // Object is in grace, deliver it
        // Automatically triggers a background fetch
        return (deliver);
      } else {
        return (restart);
      }
    }


    sub vcl_backend_response {
      # Annotate request with info about the backend used
      set beresp.http.x-varnish-plone-part = bereq.http.x-vcl-plone;
      # set beresp.http.x-varnish-plone-proto = bereq.http.x-vcl-proto;
      # set beresp.http.x-varnish-plone-host = bereq.http.x-vcl-host;
      # Don't allow static files to set cookies.
      # (?i) denotes case insensitive in PCRE (perl compatible regular expressions).
      # make sure you edit both and keep them equal.
      if (bereq.url ~ "(?i)\.(pdf|asc|dat|txt|doc|xls|ppt|tgz|png|gif|jpeg|jpg|ico|swf|css|js)(\?.*)?$") {
        unset beresp.http.set-cookie;
      }
      if (beresp.http.Set-Cookie) {
        set beresp.http.x-varnish-action = "FETCH (pass - response sets cookie)";
        set beresp.uncacheable = true;
        set beresp.ttl = 120s;
        return(deliver);
      }
      if (beresp.http.Cache-Control ~ "(private|no-cache|no-store)") {
        set beresp.http.x-varnish-action = "FETCH (pass - cache control disallows)";
        set beresp.uncacheable = true;
        set beresp.ttl = 120s;
        return(deliver);
      }

      # if (beresp.http.Authorization && !beresp.http.Cache-Control ~ "public") {
      # Do NOT cache if there is an "Authorization" header
      # beresp never has an Authorization header in beresp, right?
      if (beresp.http.Authorization) {
        set beresp.http.x-varnish-action = "FETCH (pass - authorized and no public cache control)";
        set beresp.uncacheable = true;
        set beresp.ttl = 120s;
        return(deliver);
      }

      # Use this rule IF no cache-control (SSR content)
      if ((bereq.http.x-varnish-reqtype ~ "express") && (!beresp.http.Cache-Control)) {
        set beresp.http.x-varnish-action = "INSERT (30s caching / 60s grace)";
        set beresp.uncacheable = false;
        set beresp.ttl = 30s;
        set beresp.grace = 60s;
        return(deliver);
      }

      if (!beresp.http.Cache-Control) {
        set beresp.http.x-varnish-action = "FETCH (override - backend not setting cache control)";
        set beresp.uncacheable = true;
        set beresp.ttl = 120s;
        return (deliver);
      }

      if (beresp.http.X-Anonymous && !beresp.http.Cache-Control) {
        set beresp.http.x-varnish-action = "FETCH (override - anonymous backend not setting cache control)";
        set beresp.ttl = 600s;
        return (deliver);
      }

      set beresp.http.x-varnish-action = "FETCH (insert)";
      return (deliver);
    }

    sub vcl_deliver {

      if (req.http.x-vcl-debug) {
        set resp.http.x-varnish-ttl = obj.ttl;
        set resp.http.x-varnish-grace = obj.grace;
        set resp.http.x-hits = obj.hits;
        set resp.http.x-varnish-reqtype = req.http.x-varnish-reqtype;
        if (req.http.x-auth) {
          set resp.http.x-auth = "Logged-in";
        } else {
          set resp.http.x-auth = "Anon";
        }
        if (obj.hits > 0) {
          set resp.http.x-cache = "HIT";
        } else {
          set resp.http.x-cache = "MISS";
        }
      } else {
        unset resp.http.x-varnish-action;
        unset resp.http.x-cache-operation;
        unset resp.http.x-cache-rule;
        unset resp.http.x-powered-by;
      }
    }
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/instance: kvoltoweb-httpcache-c8732c11
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: kube-httpcache
    app.kubernetes.io/version: v0.8.1
    helm.sh/chart: kube-httpcache-0.8.1
  name: kvoltoweb-httpcache-c8732c11-kube-httpcache
spec:
  ports:
    - name: http
      port: 80
      protocol: TCP
      targetPort: 8080
    - name: signaller
      port: 8090
      targetPort: 8090
    - name: metrics
      port: 9131
      targetPort: 9131
  selector:
    app.kubernetes.io/instance: kvoltoweb-httpcache-c8732c11
    app.kubernetes.io/name: kube-httpcache
  type: ClusterIP
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  labels:
    app.kubernetes.io/instance: kvoltoweb-httpcache-c8732c11
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: kube-httpcache
    app.kubernetes.io/version: v0.8.1
    helm.sh/chart: kube-httpcache-0.8.1
  name: kvoltoweb-httpcache-c8732c11-kube-httpcache
spec:
  replicas: 2
  selector:
    matchLabels:
      app.kubernetes.io/instance: kvoltoweb-httpcache-c8732c11
      app.kubernetes.io/name: kube-httpcache
  serviceName: kvoltoweb-httpcache-c8732c11-kube-httpcache
  template:
    metadata:
      labels:
        app.kubernetes.io/instance: kvoltoweb-httpcache-c8732c11
        app.kubernetes.io/name: kube-httpcache
    spec:
      containers:
        - args:
            - -admin-addr=0.0.0.0
            - -admin-port=6083
            - -signaller-enable
            - -signaller-port=8090
            - -frontend-port=8080
            - -frontend-watch=false
            - -frontend-namespace=$(NAMESPACE)
            - -frontend-service=kvoltoweb-httpcache-c8732c11-kube-httpcache
            - -backend-watch=false
            - -backend-namespace=$(NAMESPACE)
            - -backend-service=backend-service
            - -varnish-secret-file=/etc/varnish/k8s-secret/secret
            - -varnish-vcl-template=/etc/varnish/tmpl/default.vcl.tmpl
            - -varnish-storage=malloc,128M
            - -varnish-vcl-template-poll
          env:
            - name: NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
            - name: BACKEND_SERVICE_NAME
              value: kvoltoweb-plone-backend-service-c8892406
            - name: BACKEND_SERVICE_PORT
              value: "8080"
            - name: FRONTEND_SERVICE_NAME
              value: kvoltoweb-plone-frontend-service-c8020d45
            - name: FRONTEND_SERVICE_PORT
              value: "3000"
          image: quay.io/mittwald/kube-httpcache:stable
          imagePullPolicy: IfNotPresent
          name: kube-httpcache
          resources:
            limits:
              cpu: 500m
              memory: 500Mi
            requests:
              cpu: 100m
              memory: 100Mi
          securityContext: {}
          volumeMounts:
            - mountPath: /etc/varnish/tmpl
              name: template
            - mountPath: /etc/varnish/k8s-secret
              name: secret
            - mountPath: /var/lib/varnish
              name: var
        - args:
            - -no-exit
          command:
            - /exporter/prometheus_varnish_exporter
          env:
            - name: VSM_NOPID
              value: "1"
          image: quay.io/mittwald/kube-httpcache:stable
          imagePullPolicy: IfNotPresent
          name: exporter
          ports:
            - containerPort: 9131
              name: metrics
          resources:
            limits:
              cpu: 100m
              memory: 100Mi
            requests:
              cpu: 10m
              memory: 50Mi
          securityContext: {}
          volumeMounts:
            - mountPath: /var/lib/varnish
              name: var
      securityContext: {}
      serviceAccountName: kvoltoweb-httpcache-c8732c11-kube-httpcache
      volumes:
        - configMap:
            name: kvoltoweb-httpcache-c8732c11-kube-httpcache
          name: template
        - name: secret
          secret:
            secretName: kvoltoweb-httpcache-c8732c11-kube-httpcache
        - emptyDir: {}
          name: var
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  labels:
    app.kubernetes.io/instance: kvoltoweb-httpcache-c8732c11
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: kube-httpcache
    app.kubernetes.io/version: v0.8.1
    helm.sh/chart: kube-httpcache-0.8.1
  name: kvoltoweb-httpcache-c8732c11-kube-httpcache
spec:
  endpoints:
    - interval: 10s
      path: /metrics
      port: metrics
    - interval: 10s
      path: /metrics
      port: signaller
  selector:
    matchLabels:
      app.kubernetes.io/instance: kvoltoweb-httpcache-c8732c11
      app.kubernetes.io/name: kube-httpcache
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: sectigo-issuer
    konghq.com/https-redirect-status-code: "308"
    konghq.com/protocols: https
  name: kvoltoweb-ingress-main-cached-c824869d
spec:
  ingressClassName: kong
  rules:
    - host: cached.k8s-dev.geosphere.at
      http:
        paths:
          - backend:
              service:
                name: kvoltoweb-httpcache-c8732c11-kube-httpcache
                port:
                  number: 80
            path: /
            pathType: ImplementationSpecific
  tls:
    - hosts:
        - cached.k8s-dev.geosphere.at
      secretName: website-tls-main
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: sectigo-issuer
    konghq.com/https-redirect-status-code: "308"
    konghq.com/protocols: https
  name: kvoltoweb-ingress-uncached-frontend-c8e546a9
spec:
  ingressClassName: kong
  rules:
    - host: www-dev.geosphere.at
      http:
        paths:
          - backend:
              service:
                name: kvoltoweb-plone-frontend-service-c8020d45
                port:
                  number: 3000
            path: /
            pathType: ImplementationSpecific
  tls:
    - hosts:
        - www-dev.geosphere.at
      secretName: website-tls-uncached
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: sectigo-issuer
    konghq.com/https-redirect-status-code: "308"
    konghq.com/protocols: https
    konghq.com/rewrite: /VirtualHostBase/https/www-dev.geosphere.at/Plone/VirtualHostRoot/$1
  name: kvoltoweb-ingress-uncached-backend-c8ccdf2e
spec:
  ingressClassName: kong
  rules:
    - host: www-dev.geosphere.at
      http:
        paths:
          - backend:
              service:
                name: kvoltoweb-plone-backend-service-c8892406
                port:
                  number: 8080
            path: /~/((?:(?:\+\+api\+\+)(?:.*))|(?:(?:.*)/(?:(?:@@images|@@downloads)/.*)))
            pathType: ImplementationSpecific
  tls:
    - hosts:
        - www-dev.geosphere.at
      secretName: website-tls-uncached
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: sectigo-issuer
    konghq.com/https-redirect-status-code: "308"
    konghq.com/protocols: https
    konghq.com/rewrite: /VirtualHostBase/https/plone-backend.k8s-dev.geosphere.at/VirtualHostRoot/$1
  name: kvoltoweb-ingress-maintenance-backend-c8dda124
spec:
  ingressClassName: kong
  rules:
    - host: plone-backend.k8s-dev.geosphere.at
      http:
        paths:
          - backend:
              service:
                name: kvoltoweb-plone-backend-service-c8892406
                port:
                  number: 8080
            path: /~/(.*)
            pathType: ImplementationSpecific
  tls:
    - hosts:
        - plone-backend.k8s-dev.geosphere.at
      secretName: website-tls-maintenance
