---
apiVersion: codemowers.cloud/v1beta1
kind: MinioBucketClaim
metadata:
  name: camtiler
spec:
  capacity: 1Ti
  class: external
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: cams.k-space.ee
spec:
  group: k-space.ee
  names:
    plural: cams
    singular: cam
    kind: Camera
    shortNames:
      - cam
  scope: Namespaced
  versions:
    - name: v1alpha1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                roi:
                  type: object
                  description: Region of interest for this camera
                  properties:
                    threshold:
                      type: integer
                      description: Percentage of pixels changed within ROI to
                        consider whole frame to have motion detected.
                        Defaults to 5.
                    enabled:
                      type: boolean
                      description: Whether motion detection is enabled for this
                        camera. Defaults to false.
                    left:
                      type: integer
                      description: Left boundary of ROI as
                        percentage of the width of a frame.
                        By default 0.
                    right:
                      type: integer
                      description: Right boundary of ROI as
                        percentage of the width of a frame.
                        By default 100.
                    top:
                      type: integer
                      description: Top boundary of ROI as
                        percentage of the height of a frame
                        By deafault 0.
                    bottom:
                      type: integer
                      description: Bottom boundary of ROI as
                        percentage of the height of a frame.
                        By default 100.
                secretRef:
                  type: string
                  description: Secret that contains authentication credentials
                target:
                  type: string
                  description: URL of the video feed stream
                replicas:
                  type: integer
                  minimum: 1
                  maximum: 2
                  description: For highly available deployment set this to 2 or
                    higher. Make sure you also run Mongo and Minio in HA
                    configurations
              required: ["target"]
          required: ["spec"]
---
apiVersion: codemowers.io/v1alpha1
kind: ClusterOperator
metadata:
  name: camera
spec:
  resource:
    group: k-space.ee
    version: v1alpha1
    plural: cams
  secret:
    enabled: false
  services:
    - apiVersion: v1
      kind: Service
      metadata:
        name: foobar
        labels:
          app.kubernetes.io/name: foobar
          component: camera-motion-detect
      spec:
        type: ClusterIP
        selector:
          app.kubernetes.io/name: foobar
          component: camera-motion-detect
        ports:
          - protocol: TCP
            port: 80
            targetPort: 5000
  deployments:
    - apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: camera-foobar
      spec:
        revisionHistoryLimit: 0
        replicas: 1

        strategy:
          type: RollingUpdate
          rollingUpdate:
            # Swap following two with replicas: 2
            maxSurge: 1
            maxUnavailable: 0
        selector:
          matchLabels:
            app.kubernetes.io/name: foobar
        template:
          metadata:
            labels:
              app.kubernetes.io/name: foobar
              component: camera-motion-detect
          spec:
            containers:
              - name: camera-motion-detect
                image: harbor.k-space.ee/k-space/camera-motion-detect:latest
                starupProbe:
                  httpGet:
                    path: /healthz
                    port: 5000
                  initialDelaySeconds: 2
                  periodSeconds: 180
                  timeoutSeconds: 60
                readinessProbe:
                  httpGet:
                    path: /readyz
                    port: 5000
                  initialDelaySeconds: 60
                  periodSeconds: 60
                  timeoutSeconds: 5
                ports:
                  - containerPort: 5000
                    name: "http"
                resources:
                  requests:
                    memory: "64Mi"
                    cpu: "200m"
                  limits:
                    memory: "256Mi"
                    cpu: "4000m"
                securityContext:
                  readOnlyRootFilesystem: true
                  runAsNonRoot: true
                  runAsUser: 1000
                command:
                  - /app/camdetect.py
                  - http://user@foobar.cam.k-space.ee:8080/?action=stream
                env:
                  - name: SOURCE_NAME
                    value: foobar
                  - name: S3_BUCKET_NAME
                    valueFrom:
                      secretKeyRef:
                        name: miniobucket-camtiler-owner-secrets
                        key: BUCKET_NAME
                  - name: S3_ENDPOINT_URL
                    valueFrom:
                      secretKeyRef:
                        name: miniobucket-camtiler-owner-secrets
                        key: AWS_S3_ENDPOINT_URL
                  - name: AWS_SECRET_ACCESS_KEY
                    valueFrom:
                      secretKeyRef:
                        name: miniobucket-camtiler-owner-secrets
                        key: AWS_SECRET_ACCESS_KEY
                  - name: AWS_ACCESS_KEY_ID
                    valueFrom:
                      secretKeyRef:
                        name: miniobucket-camtiler-owner-secrets
                        key: AWS_ACCESS_KEY_ID
                  - name: BASIC_AUTH_PASSWORD
                    valueFrom:
                      secretKeyRef:
                        name: camera-secrets
                        key: password
                  - name: MONGO_URI
                    valueFrom:
                      secretKeyRef:
                        name: mongodb-application-readwrite
                        key: connectionString.standard

            # Make sure 2+ pods of same camera are scheduled on different hosts
            affinity:
              podAntiAffinity:
                requiredDuringSchedulingIgnoredDuringExecution:
                  - labelSelector:
                      matchExpressions:
                        - key: app.kubernetes.io/name
                          operator: In
                          values:
                            - foobar
                    topologyKey: topology.kubernetes.io/zone

            # Make sure camera deployments are spread over workers
            topologySpreadConstraints:
              - maxSkew: 1
                topologyKey: topology.kubernetes.io/zone
                whenUnsatisfiable: DoNotSchedule
                labelSelector:
                  matchLabels:
                    app.kubernetes.io/name: foobar
                    component: camera-motion-detect
---
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: cameras
spec:
  groups:
    - name: cameras
      rules:
        - alert: CameraLost
          expr: rate(camtiler_frames_total{stage="downloaded"}[1m]) < 1
          for: 2m
          labels:
            severity: warning
          annotations:
            summary: Camera feed stopped
        - alert: CameraServerRoomMotion
          expr: rate(camtiler_events_total{app_kubernetes_io_name="server-room"}[30m]) > 0
          for: 1m
          labels:
            severity: warning
          annotations:
            summary: Motion was detected in server room
        - alert: CameraSlowUploads
          expr: camtiler_queue_frames{stage="upload"} > 10
          for: 5m
          labels:
            severity: warning
          annotations:
            summary: Motion detect snapshots are piling up and
              not getting uploaded to S3
        - alert: CameraSlowProcessing
          expr: camtiler_queue_frames{stage="download"} > 10
          for: 5m
          labels:
            severity: warning
          annotations:
            summary: Motion detection processing pipeline is not keeping up
              with incoming frames
        - alert: CameraResourcesThrottled
          expr: sum by (pod) (rate(container_cpu_cfs_throttled_periods_total{namespace="camtiler"}[1m])) > 0
          for: 5m
          labels:
            severity: warning
          annotations:
            summary: CPU limits are bottleneck
---
apiVersion: k-space.ee/v1alpha1
kind: Camera
metadata:
  name: workshop
spec:
  target: http://user@workshop.cam.k-space.ee:8080/?action=stream
  secretRef: camera-secrets
  replicas: 1
---
apiVersion: k-space.ee/v1alpha1
kind: Camera
metadata:
  name: server-room
spec:
  target: http://user@server-room.cam.k-space.ee:8080/?action=stream
  secretRef: camera-secrets
  replicas: 2
---
apiVersion: k-space.ee/v1alpha1
kind: Camera
metadata:
  name: printer
spec:
  target: http://user@printer.cam.k-space.ee:8080/?action=stream
  secretRef: camera-secrets
  replicas: 1
---
apiVersion: k-space.ee/v1alpha1
kind: Camera
metadata:
  name: chaos
spec:
  target: http://user@chaos.cam.k-space.ee:8080/?action=stream
  secretRef: camera-secrets
  replicas: 1
---
apiVersion: k-space.ee/v1alpha1
kind: Camera
metadata:
  name: cyber
spec:
  target: http://user@cyber.cam.k-space.ee:8080/?action=stream
  secretRef: camera-secrets
  replicas: 1
---
apiVersion: k-space.ee/v1alpha1
kind: Camera
metadata:
  name: kitchen
spec:
  target: http://user@kitchen.cam.k-space.ee:8080/?action=stream
  secretRef: camera-secrets
  replicas: 1
---
apiVersion: k-space.ee/v1alpha1
kind: Camera
metadata:
  name: back-door
spec:
  target: http://user@100.102.3.3:8080/?action=stream
  secretRef: camera-secrets
  replicas: 1
---
apiVersion: k-space.ee/v1alpha1
kind: Camera
metadata:
  name: ground-door
spec:
  target: http://user@100.102.3.1:8080/?action=stream
  secretRef: camera-secrets
  replicas: 1
---
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
  name: camera-motion-detect
spec:
  selector:
    matchLabels:
      component: camera-motion-detect
  podMetricsEndpoints:
    - port: http
  podTargetLabels:
    - app.kubernetes.io/name
    - component