diff --git a/src/main/cljc/dda/c4k_jitsi/core.cljc b/src/main/cljc/dda/c4k_jitsi/core.cljc index 8f44e88..4eb4548 100644 --- a/src/main/cljc/dda/c4k_jitsi/core.cljc +++ b/src/main/cljc/dda/c4k_jitsi/core.cljc @@ -34,6 +34,8 @@ (cm/concat-vec (ns/generate resolved-config) (jitsi/prosody-config resolved-config) + (jitsi/jitsi-config resolved-config) + (jitsi/jibri-config resolved-config) ;; [(jitsi/generate-jvb-service config) ;; (jitsi/generate-web-service config) ;; (jitsi/generate-etherpad-service config) diff --git a/src/main/cljc/dda/c4k_jitsi/jitsi.cljc b/src/main/cljc/dda/c4k_jitsi/jitsi.cljc index 449a498..5bb4f8d 100644 --- a/src/main/cljc/dda/c4k_jitsi/jitsi.cljc +++ b/src/main/cljc/dda/c4k_jitsi/jitsi.cljc @@ -173,3 +173,18 @@ (-> (load-and-adjust-namespace "jitsi/prosody-auth-jvb-secret.yaml" namespace) (cm/replace-key-value :JVB_AUTH_PASSWORD (b64/encode jvb-auth-password)))])) + +(defn-spec jitsi-config cp/map-or-seq? + [config config?] + (let [{:keys [fqdn namespace]} config] + [(load-and-adjust-namespace "jitsi/jitsi-config-serviceaccount.yaml" namespace)])) + +(defn-spec jibri-config cp/map-or-seq? + [config config?] + (let [{:keys [fqdn namespace]} config] + [(load-and-adjust-namespace "jitsi/jitsi-config-serviceaccount.yaml" namespace) + (load-and-adjust-namespace "jitsi/jibri-config-default-cm.yaml" namespace) + (load-and-adjust-namespace "jitsi/jibri-config-envs.yaml" namespace) + (load-and-adjust-namespace "jitsi/jibri-config-init-cm.yaml" namespace) + (load-and-adjust-namespace "jitsi/jibri-config-service.yaml" namespace) + (load-and-adjust-namespace "jitsi/jibri-config-deployment.yaml" namespace)])) diff --git a/src/main/resources/jitsi/deployment.yaml b/src/main/resources/jitsi/deployment.yaml index 318eb50..60ce776 100644 --- a/src/main/resources/jitsi/deployment.yaml +++ b/src/main/resources/jitsi/deployment.yaml @@ -37,37 +37,6 @@ spec: key: JICOFO_AUTH_PASSWORD - name: TZ value: Europe/Berlin - - name: prosody - image: jitsi/prosody:stable-9646 - imagePullPolicy: IfNotPresent - env: - - name: PUBLIC_URL - value: REPLACE_JITSI_FQDN - - name: XMPP_SERVER - value: localhost - - name: JICOFO_COMPONENT_SECRET - valueFrom: - secretKeyRef: - name: jitsi-config - key: JICOFO_COMPONENT_SECRET - - name: JVB_AUTH_USER - value: jvb - - name: JVB_AUTH_PASSWORD - valueFrom: - secretKeyRef: - name: jitsi-config - key: JVB_AUTH_PASSWORD - - name: JICOFO_AUTH_USER - value: focus - - name: JICOFO_AUTH_PASSWORD - valueFrom: - secretKeyRef: - name: jitsi-config - key: JICOFO_AUTH_PASSWORD - - name: TZ - value: Europe/Berlin - - name: JVB_TCP_HARVESTER_DISABLED - value: "true" - name: web image: domaindrivenarchitecture/c4k-jitsi-web imagePullPolicy: IfNotPresent diff --git a/src/main/resources/jitsi/jibri-config-default-cm.yaml b/src/main/resources/jitsi/jibri-config-default-cm.yaml new file mode 100644 index 0000000..3022246 --- /dev/null +++ b/src/main/resources/jitsi/jibri-config-default-cm.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: jitsi-meet-jibri-defaults + namespace: NAMESPACE + labels: + app.kubernetes.io/name: jitsi-meet + app.kubernetes.io/component: jibri +data: + jibri.conf: | + # Using jibri /default/jibri.conf from container image + + logging.properties: | + # Using jibri /default/logging.properties from container image + + autoscaler-sidecar.config: | + # Using jibri /default/autoscaler-sidecar.config from container image + + xorg-video-dummy.conf: | + # Using jibri /default/xorg-video-dummy.conf from container image \ No newline at end of file diff --git a/src/main/resources/jitsi/jibri-config-deployment.yaml b/src/main/resources/jitsi/jibri-config-deployment.yaml new file mode 100644 index 0000000..5e12829 --- /dev/null +++ b/src/main/resources/jitsi/jibri-config-deployment.yaml @@ -0,0 +1,95 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: jitsi-meet-jibri + namespace: NAMESPACE + labels: + app.kubernetes.io/name: jitsi-meet + app.kubernetes.io/component: jibri +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: jitsi-meet + app.kubernetes.io/component: jibri + template: + metadata: + labels: + app.kubernetes.io/name: jitsi-meet + app.kubernetes.io/component: jibri + spec: + serviceAccountName: jitsi-meet + containers: + - name: jitsi-meet + securityContext: + capabilities: + add: ["SYS_ADMIN"] + image: "jitsi/jibri:stable-9646" + imagePullPolicy: IfNotPresent + ports: + - name: http-internal + containerPort: 3333 + - name: http-api + containerPort: 2222 + livenessProbe: + exec: + command: + - /bin/bash + - -c + - curl -sq localhost:2222/jibri/api/v1.0/health | jq '"\(.status.health.healthStatus) + \(.status.busyStatus)"' | grep -qP 'HEALTHY (IDLE|BUSY)' + failureThreshold: 2 + initialDelaySeconds: 5 + periodSeconds: 5 + readinessProbe: + exec: + command: + - /bin/bash + - -c + - curl -sq localhost:2222/jibri/api/v1.0/health | jq '"\(.status.health.healthStatus) + \(.status.busyStatus)"' | grep -qP 'HEALTHY (IDLE|BUSY)' + failureThreshold: 2 + initialDelaySeconds: 5 + periodSeconds: 5 + + envFrom: + - secretRef: + name: prosody-jibri + - configMapRef: + name: prosody-common + - configMapRef: + name: jitsi-meet-jibri + + resources: + {} + + volumeMounts: + - name: config + mountPath: /config + - name: jibri-data + mountPath: /data + + volumes: + - name: config + emptyDir: {} + - name: custom-cont-inits + configMap: + defaultMode: 493 + name: jitsi-meet-jibri-cont-inits + items: + - key: 10-config + path: 10-config + - name: custom-defaults + configMap: + name: jitsi-meet-jibri-defaults + items: + - key: jibri.conf + path: jibri.conf + - key: logging.properties + path: logging.properties + - key: autoscaler-sidecar.config + path: autoscaler-sidecar.config + - key: xorg-video-dummy.conf + path: xorg-video-dummy.conf + - name: jibri-data + emptyDir: {} \ No newline at end of file diff --git a/src/main/resources/jitsi/jibri-config-envs.yaml b/src/main/resources/jitsi/jibri-config-envs.yaml new file mode 100644 index 0000000..fa43c0d --- /dev/null +++ b/src/main/resources/jitsi/jibri-config-envs.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: jitsi-meet-jibri + namespace: NAMESPACE + labels: + app.kubernetes.io/name: jitsi-meet + app.kubernetes.io/component: jibri +data: + XMPP_SERVER: 'prosody.NAMESPACE.svc.cluster.local' + JIBRI_BREWERY_MUC: 'jibribrewery' + JIBRI_RECORDING_DIR: '/data/recordings' + JIBRI_FINALIZE_RECORDING_SCRIPT_PATH: "/config/finalize.sh" + JIBRI_STRIP_DOMAIN_JID: muc + DISPLAY: ":0" + JIBRI_SINGLE_USE_MODE: "true" \ No newline at end of file diff --git a/src/main/resources/jitsi/jibri-config-init-cm.yaml b/src/main/resources/jitsi/jibri-config-init-cm.yaml new file mode 100644 index 0000000..bc9510b --- /dev/null +++ b/src/main/resources/jitsi/jibri-config-init-cm.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: jitsi-meet-jibri-cont-inits + namespace: NAMESPACE + labels: + app.kubernetes.io/name: jitsi-meet + app.kubernetes.io/component: jibri +data: + 10-config: | + # Using jibri /etc/cont-init.d/10-config from container image \ No newline at end of file diff --git a/src/main/resources/jitsi/jibri-config-service.yaml b/src/main/resources/jitsi/jibri-config-service.yaml new file mode 100644 index 0000000..31072cf --- /dev/null +++ b/src/main/resources/jitsi/jibri-config-service.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: Service +metadata: + name: jitsi-meet-jibri + namespace: NAMESPACE + labels: + app.kubernetes.io/name: jitsi-meet + app.kubernetes.io/component: jibri +spec: + type: ClusterIP + ports: + - name: http-internal + port: 3333 + targetPort: 3333 + protocol: TCP + - name: http-api + port: 2222 + targetPort: 2222 + protocol: TCP + selector: + app.kubernetes.io/name: jitsi-meet + app.kubernetes.io/component: jibri \ No newline at end of file diff --git a/src/main/resources/jitsi/jitsi-config-serviceaccount.yaml b/src/main/resources/jitsi/jitsi-config-serviceaccount.yaml new file mode 100644 index 0000000..d6ab876 --- /dev/null +++ b/src/main/resources/jitsi/jitsi-config-serviceaccount.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: jitsi-meet + namespace: NAMESPACE + labels: + app.kubernetes.io/name: jitsi-meet \ No newline at end of file diff --git a/src/main/resources/jitsi/prosody-config-common-cm.yaml b/src/main/resources/jitsi/prosody-config-common-cm.yaml index 43040fa..8f0e06e 100644 --- a/src/main/resources/jitsi/prosody-config-common-cm.yaml +++ b/src/main/resources/jitsi/prosody-config-common-cm.yaml @@ -20,4 +20,6 @@ data: ENABLE_COLIBRI_WEBSOCKET: 'true' ENABLE_COLIBRI_WEBSOCKET_UNSAFE_REGEX: '1' ENABLE_XMPP_WEBSOCKET: 'true' - TZ: 'Europe/Amsterdam' \ No newline at end of file + ENABLE_RECORDING: "true" + ENABLE_FILE_RECORDING_SERVICE_SHARING: "true" + TZ: 'Europe/Berlin' \ No newline at end of file diff --git a/src/test/cljc/dda/c4k_jitsi/jitsi_test.cljc b/src/test/cljc/dda/c4k_jitsi/jitsi_test.cljc index 2933d5e..89ca2c8 100644 --- a/src/test/cljc/dda/c4k_jitsi/jitsi_test.cljc +++ b/src/test/cljc/dda/c4k_jitsi/jitsi_test.cljc @@ -5,220 +5,10 @@ [clojure.spec.test.alpha :as st] [dda.c4k-jitsi.jitsi :as cut])) -(st/instrument `cut/generate-deployment) -(st/instrument `cut/generate-secret-jitsi) -(st/instrument `cut/generate-ingress-web) -(st/instrument `cut/generate-jvb-service) - -(deftest should-generate-deployment - (is (= {:apiVersion "apps/v1", - :kind "Deployment", - :metadata - {:labels {:app "jitsi"}, - :name "jitsi" - :namespace "jitsi"}, - :spec - {:strategy {:type "Recreate"}, - :selector {:matchLabels {:app "jitsi"}}, - :template - {:metadata {:labels {:app "jitsi"}}, - :spec - {:containers - [{:name "jicofo", - :image "jitsi/jicofo:stable-9646", - :imagePullPolicy "IfNotPresent", - :env - [{:name "XMPP_SERVER", :value "localhost"} - {:name "JICOFO_COMPONENT_SECRET", - :valueFrom {:secretKeyRef {:name "jitsi-config", :key "JICOFO_COMPONENT_SECRET"}}} - {:name "JICOFO_AUTH_USER", :value "focus"} - {:name "JICOFO_AUTH_PASSWORD", :valueFrom {:secretKeyRef {:name "jitsi-config", :key "JICOFO_AUTH_PASSWORD"}}} - {:name "TZ", :value "Europe/Berlin"}]} - {:name "prosody", - :image "jitsi/prosody:stable-9646", - :imagePullPolicy "IfNotPresent", - :env - [{:name "PUBLIC_URL", :value "xy.xy.xy"} - {:name "XMPP_SERVER", :value "localhost"} - {:name "JICOFO_COMPONENT_SECRET", - :valueFrom {:secretKeyRef {:name "jitsi-config", :key "JICOFO_COMPONENT_SECRET"}}} - {:name "JVB_AUTH_USER", :value "jvb"} - {:name "JVB_AUTH_PASSWORD", :valueFrom {:secretKeyRef {:name "jitsi-config", :key "JVB_AUTH_PASSWORD"}}} - {:name "JICOFO_AUTH_USER", :value "focus"} - {:name "JICOFO_AUTH_PASSWORD", :valueFrom {:secretKeyRef {:name "jitsi-config", :key "JICOFO_AUTH_PASSWORD"}}} - {:name "TZ", :value "Europe/Berlin"} - {:name "JVB_TCP_HARVESTER_DISABLED", :value "true"}]} - {:name "web", - :image "domaindrivenarchitecture/c4k-jitsi-web", - :imagePullPolicy "IfNotPresent", - :env - [{:name "PUBLIC_URL", :value "xy.xy.xy"} - {:name "XMPP_SERVER", :value "localhost"} - {:name "XMPP_BOSH_URL_BASE", :value "http://127.0.0.1:5280"} - {:name "JICOFO_AUTH_USER", :value "focus"} - {:name "TZ", :value "Europe/Berlin"} - {:name "JVB_TCP_HARVESTER_DISABLED", :value "true"} - {:name "DEFAULT_LANGUAGE", :value "de"} - {:name "RESOLUTION", :value "480"} - {:name "RESOLUTION_MIN", :value "240"} - {:name "RESOLUTION_WIDTH", :value "853"} - {:name "RESOLUTION_WIDTH_MIN", :value "427"} - {:name "DISABLE_AUDIO_LEVELS", :value "true"} - {:name "ETHERPAD_PUBLIC_URL", :value "https://etherpad.xy.xy.xy/p/"} - {:name "WHITEBOARD_ENABLED", :value "true"} - {:name "WHITEBOARD_COLLAB_SERVER_PUBLIC_URL", :value "https://excalidraw-backend.xy.xy.xy"} - {:name "COLIBRI_WEBSOCKET_REGEX", :value "127.0.0.1"}]} - {:name "jvb", - :image "jitsi/jvb:stable-9646", - :imagePullPolicy "IfNotPresent", - :env - [{:name "PUBLIC_URL", :value "xy.xy.xy"} - {:name "XMPP_SERVER", :value "localhost"} - {:name "DOCKER_HOST_ADDRESS", :value "xy.xy.xy"} - {:name "JICOFO_AUTH_USER", :value "focus"} - {:name "JVB_TCP_HARVESTER_DISABLED", :value "true"} - {:name "JVB_AUTH_USER", :value "jvb"} - {:name "JVB_PORT", :value "30300"} - {:name "JVB_AUTH_PASSWORD", :valueFrom {:secretKeyRef {:name "jitsi-config", :key "JVB_AUTH_PASSWORD"}}} - {:name "JICOFO_AUTH_PASSWORD", :valueFrom {:secretKeyRef {:name "jitsi-config", :key "JICOFO_AUTH_PASSWORD"}}} - {:name "TZ", :value "Europe/Berlin"}]} - {:name "etherpad", - :image "etherpad/etherpad:2", - :env - [{:name "XMPP_SERVER", :value "localhost"} - {:name "JICOFO_COMPONENT_SECRET", - :valueFrom {:secretKeyRef {:name "jitsi-config", :key "JICOFO_COMPONENT_SECRET"}}} - {:name "JICOFO_AUTH_USER", :value "focus"} - {:name "JICOFO_AUTH_PASSWORD", :valueFrom {:secretKeyRef {:name "jitsi-config", :key "JICOFO_AUTH_PASSWORD"}}} - {:name "TZ", :value "Europe/Berlin"}]}]}}}} - (cut/generate-deployment {:fqdn "xy.xy.xy" - :namespace "jitsi"})))) - -(deftest should-generate-secret - (is (= {:apiVersion "v1", - :kind "Secret", - :metadata - {:name "jitsi-config" - :namespace "jitsi"}, - :type "Opaque", - :data - {:JVB_AUTH_PASSWORD "anZiLWF1dGg=", - :JICOFO_AUTH_PASSWORD "amljb2ZvLWF1dGg=", - :JICOFO_COMPONENT_SECRET "amljb2ZvLWNvbXA="}} - (cut/generate-secret-jitsi - {:fqdn "xy.xy.xy" - :namespace "jitsi"} - {:jvb-auth-password "jvb-auth" - :jicofo-auth-password "jicofo-auth" - :jicofo-component-secret "jicofo-comp"})))) - - (deftest should-generate-ingress-web - (is (= [{:apiVersion "cert-manager.io/v1", - :kind "Certificate", - :metadata - {:name "web", - :labels {:app.kubernetes.part-of "web"}, - :namespace "jitsi"}, - :spec - {:secretName "web", - :commonName "xy.xy.xy", - :duration "2160h", - :renewBefore "720h", - :dnsNames ["xy.xy.xy"], - :issuerRef {:name "staging", :kind "ClusterIssuer"}}} - {:apiVersion "networking.k8s.io/v1", - :kind "Ingress", - :metadata - {:namespace "jitsi", - :annotations - {:traefik.ingress.kubernetes.io/router.entrypoints "web, websecure", - :traefik.ingress.kubernetes.io/router.middlewares - "default-redirect-https@kubernetescrd", - :metallb.universe.tf/address-pool "public"}, - :name "web", - :labels {:app.kubernetes.part-of "web"}}, - :spec - {:tls [{:hosts ["xy.xy.xy"], :secretName "web"}], - :rules - [{:host "xy.xy.xy", - :http - {:paths - [{:pathType "Prefix", - :path "/", - :backend {:service {:name "web", :port {:number 80}}}}]}}]}}] - (cut/generate-ingress-web - {:fqdn "xy.xy.xy" - :namespace "jitsi"})))) - -(deftest should-generate-ingress-modelector - (is (= [{:apiVersion "cert-manager.io/v1", - :kind "Certificate", - :metadata - {:name "modelector", - :labels {:app.kubernetes.part-of "modelector"}, - :namespace "jitsi"}, - :spec - {:secretName "modelector", - :commonName "modelector.xy.xy", - :duration "2160h", - :renewBefore "720h", - :dnsNames ["modelector.xy.xy"], - :issuerRef {:name "staging", :kind "ClusterIssuer"}}} - {:apiVersion "networking.k8s.io/v1", - :kind "Ingress", - :metadata - {:namespace "jitsi", - :annotations - {:traefik.ingress.kubernetes.io/router.entrypoints "web, websecure", - :traefik.ingress.kubernetes.io/router.middlewares - "default-redirect-https@kubernetescrd", - :metallb.universe.tf/address-pool "public"}, - :name "modelector", - :labels {:app.kubernetes.part-of "modelector"}}, - :spec - {:tls [{:hosts ["modelector.xy.xy"], :secretName "modelector"}], - :rules - [{:host "modelector.xy.xy", - :http - {:paths - [{:pathType "Prefix", - :path "/", - :backend {:service {:name "modelector", :port {:number 80}}}}]}}]}}] - (cut/generate-ingress-modelector - {:fqdn "xy.xy" - :namespace "jitsi"})))) - -(deftest should-generate-jvb-service - (is (= {:apiVersion "v1", - :kind "Service", - :metadata - {:labels {:service "jvb"}, - :annotations - #:metallb.universe.tf{:allow-shared-ip "shared-ip-service-group", - :address-pool "public"}, - :name "jvb-udp" - :namespace "jitsi"}, - :spec - {:type "LoadBalancer", - :ports - [{:port 30300, :protocol "UDP", :targetPort 30300, :nodePort 30300}], - :selector {:app "jitsi"}}} - (cut/generate-jvb-service - {:fqdn "xy.xy.xy" - :namespace "jitsi"})))) - -(deftest should-generate-web-service - (is (= {:apiVersion "v1", - :kind "Service", - :metadata {:labels {:service "web"}, :name "web", :namespace "jitsi"}, - :spec - {:ports - [{:name "http", :port 80, :targetPort 80} - {:name "https", :port 443, :targetPort 443}], - :selector {:app "jitsi"}}} - (cut/generate-web-service - {:fqdn "xy.xy.xy" - :namespace "jitsi"})))) +(st/instrument `cut/prosody-config) +(st/instrument `cut/prosody-auth) +(st/instrument `cut/jitsi-config) +(st/instrument `cut/jibri-config) (deftest should-generate-etherpad-service (is (= {:apiVersion "v1", @@ -330,7 +120,9 @@ :ENABLE_COLIBRI_WEBSOCKET "true", :ENABLE_COLIBRI_WEBSOCKET_UNSAFE_REGEX "1", :ENABLE_XMPP_WEBSOCKET "true", - :TZ "Europe/Amsterdam"}} + :ENABLE_RECORDING "true", + :ENABLE_FILE_RECORDING_SERVICE_SHARING "true", + :TZ "Europe/Berlin"}} (second (cut/prosody-config {:fqdn "xy.xy.xy" :namespace "jitsi"})))) @@ -344,4 +136,16 @@ :namespace "jitsi"} {:jvb-auth-password "jvb-auth" :jicofo-auth-password "jicofo-auth" - :jicofo-component-secret "jicofo-comp"}))))) \ No newline at end of file + :jicofo-component-secret "jicofo-comp"}))))) + +(deftest should-generate-jitsi + (is (= 1 + (count (cut/jitsi-config + {:fqdn "xy.xy.xy" + :namespace "jitsi"}))))) + +(deftest should-generate-jibri + (is (= 6 + (count (cut/jibri-config + {:fqdn "xy.xy.xy" + :namespace "jitsi"})))))