Merge branch 'refactor-uptodate' into 'master'

Refactoring

See merge request domaindrivenarchitecture/c4k-nextcloud!6
merge-requests/6/merge
Clemens Geibel 1 year ago
commit c13cecab46

@ -49,7 +49,7 @@ test-schema:
stage: build_and_test stage: build_and_test
script: script:
- lein uberjar - lein uberjar
- java -jar target/uberjar/c4k-nextcloud-standalone.jar valid-config.edn valid-auth.edn | kubeconform --kubernetes-version 1.19.0 --strict --skip "Certificate,CronJob" - - java -jar target/uberjar/c4k-nextcloud-standalone.jar src/test/resources/nextcloud-test/valid-config.yaml src/test/resources/nextcloud-test/valid-auth.yaml | kubeconform --kubernetes-version 1.19.0 --strict --skip "Certificate,CronJob" -
artifacts: artifacts:
paths: paths:
- target/uberjar - target/uberjar

@ -0,0 +1,17 @@
# Upgrade major or minor versions of nextcloud
## Nextcloud versions of c4k-nextcloud docker images
- 4.0.3: nextcloud 22
- 5.0.0: nextcloud 23
- 6.0.0: nextcloud 24
- 7.0.0: nextcloud 25
## Uprgrading process
1. Change the version of the docker image in the deployment to the next major version
- `kubectl edit deploy cloud-deployment`
- change `image: domaindrivenarchitecture/c4k-cloud:4.0.3`
2. Wait for the pod to finish restarting
3. Verify the website is working and https://URL/settings/admin/overview shows the correct version
4. Repeat until desired version is reached

@ -45,15 +45,17 @@ output "ipv4" {
## k8s minicluster ## k8s minicluster
For k8s installation we use our [dda-k8s-crate](https://github.com/DomainDrivenArchitecture/dda-k8s-crate) with the following configuation: For k8s installation we use our [provs](https://repo.prod.meissa.de/meissa/provs) with the following configuation:
``` ```
{:user :k8s postgres-db-user: "nextcloud"
:k8s {:external-ip "ip-from-above"} postgres-db-password: "nextcloud-db-password"
:cert-manager :letsencrypt-prod-issuer nextcloud-admin-user: "cloudadmin"
:persistent-dirs ["cloud", "postgres"] nextcloud-admin-password: "cloudpassword"
} aws-access-key-id: "aws-id"
aws-secret-access-key: "aws-secret"
restic-password: "restic-password"
``` ```
## kubectl apply c4k-nextcloud ## kubectl apply c4k-nextcloud

@ -1,4 +1,4 @@
FROM nextcloud:22 FROM nextcloud:25
# Prepare Entrypoint Script # Prepare Entrypoint Script
ADD resources /tmp ADD resources /tmp

@ -2,7 +2,7 @@
"name": "c4k-nextcloud", "name": "c4k-nextcloud",
"description": "Generate c4k yaml for a nextcloud deployment.", "description": "Generate c4k yaml for a nextcloud deployment.",
"author": "meissa GmbH", "author": "meissa GmbH",
"version": "4.0.3-SNAPSHOT", "version": "7.0.1-SNAPSHOT",
"homepage": "https://gitlab.com/domaindrivenarchitecture/c4k-nextcloud#readme", "homepage": "https://gitlab.com/domaindrivenarchitecture/c4k-nextcloud#readme",
"repository": "https://www.npmjs.com/package/c4k-nextcloud", "repository": "https://www.npmjs.com/package/c4k-nextcloud",
"license": "APACHE2", "license": "APACHE2",

@ -1,11 +1,11 @@
(defproject org.domaindrivenarchitecture/c4k-nextcloud "4.0.4-SNAPSHOT" (defproject org.domaindrivenarchitecture/c4k-nextcloud "7.0.1-SNAPSHOT"
:description "nextcloud c4k-installation package" :description "nextcloud c4k-installation package"
:url "https://domaindrivenarchitecture.org" :url "https://domaindrivenarchitecture.org"
:license {:name "Apache License, Version 2.0" :license {:name "Apache License, Version 2.0"
:url "https://www.apache.org/licenses/LICENSE-2.0.html"} :url "https://www.apache.org/licenses/LICENSE-2.0.html"}
:dependencies [[org.clojure/clojure "1.11.1"] :dependencies [[org.clojure/clojure "1.11.1"]
[org.clojure/tools.reader "1.3.6"] [org.clojure/tools.reader "1.3.6"]
[org.domaindrivenarchitecture/c4k-common-clj "2.0.3"]] [org.domaindrivenarchitecture/c4k-common-clj "6.0.1"]]
:target-path "target/%s/" :target-path "target/%s/"
:source-paths ["src/main/cljc" :source-paths ["src/main/cljc"
"src/main/clj"] "src/main/clj"]
@ -39,8 +39,7 @@
"-H:ResourceConfigurationFiles=graalvm-resource-config.json" "-H:ResourceConfigurationFiles=graalvm-resource-config.json"
"-H:Log=registerResource" "-H:Log=registerResource"
"-H:Name=target/graalvm/${:name}"] "-H:Name=target/graalvm/${:name}"]
"inst" ["shell" "sudo" "inst" ["shell"
"install" "sh"
"-m=755" "-c"
"target/uberjar/c4k-nextcloud-standalone.jar" "lein uberjar && sudo install -m=755 target/uberjar/c4k-nextcloud-standalone.jar /usr/local/bin/c4k-nextcloud-standalone.jar"]})
"/usr/local/bin/c4k-nextcloud-standalone.jar"]})

@ -4,7 +4,7 @@
"src/test/cljc" "src/test/cljc"
"src/test/cljs" "src/test/cljs"
"src/test/resources"] "src/test/resources"]
:dependencies [[org.domaindrivenarchitecture/c4k-common-cljs "2.0.3"] :dependencies [[org.domaindrivenarchitecture/c4k-common-cljs "6.0.1"]
[hickory "0.7.1"]] [hickory "0.7.1"]]
:builds {:frontend {:target :browser :builds {:frontend {:target :browser
:modules {:main {:init-fn dda.c4k-nextcloud.browser/init}} :modules {:main {:init-fn dda.c4k-nextcloud.browser/init}}

@ -1,55 +1,15 @@
(ns dda.c4k-nextcloud.uberjar (ns dda.c4k-nextcloud.uberjar
(:gen-class) (:gen-class)
(:require (:require
[clojure.spec.alpha :as s] [dda.c4k-common.uberjar :as uberjar]
[clojure.string :as cs] [dda.c4k-nextcloud.nextcloud :as nextcloud]
[clojure.tools.reader.edn :as edn] [dda.c4k-nextcloud.core :as core]))
[expound.alpha :as expound]
[dda.c4k-common.yaml :as yaml]
[dda.c4k-nextcloud.core :as core]
[dda.c4k-nextcloud.nextcloud :as nextcloud]))
(def usage
"usage:
c4k-nextcloud {your configuraton file} {your authorization file}")
(s/def ::options (s/* #{"-h"}))
(s/def ::filename (s/and string?
#(not (cs/starts-with? % "-"))))
(s/def ::cmd-args (s/cat :options ::options
:args (s/?
(s/cat :config ::filename
:auth ::filename))))
(defn invalid-args-msg
[spec args]
(s/explain spec args)
(println (str "Bad commandline arguments\n" usage)))
(defn -main [& cmd-args] (defn -main [& cmd-args]
(let [parsed-args-cmd (s/conform ::cmd-args cmd-args)] (uberjar/main-common
(if (= ::s/invalid parsed-args-cmd) "c4k-nextcloud"
(invalid-args-msg ::cmd-args cmd-args) nextcloud/config?
(let [{:keys [options args]} parsed-args-cmd nextcloud/auth?
{:keys [config auth]} args] core/config-defaults
(cond core/k8s-objects
(some #(= "-h" %) options) cmd-args))
(println usage)
:default
(let [config-str (slurp config)
auth-str (slurp auth)
config-parse-fn (if (yaml/is-yaml? config) yaml/from-string edn/read-string)
auth-parse-fn (if (yaml/is-yaml? auth) yaml/from-string edn/read-string)
parsed-config (config-parse-fn config-str)
parsed-auth (auth-parse-fn auth-str)
config-valid? (s/valid? ::core/config parsed-config)
auth-valid? (s/valid? ::core/auth parsed-auth)]
(if (and config-valid? auth-valid?)
(println (core/generate parsed-config parsed-auth))
(do
(when (not config-valid?)
(println
(expound/expound-str ::core/config parsed-config {:print-specs? false})))
(when (not auth-valid?)
(println
(expound/expound-str ::core/auth parsed-auth {:print-specs? false})))))))))))

@ -23,14 +23,14 @@
(defn generate-config [my-conf] (defn generate-config [my-conf]
(let [{:keys [restic-repository]} my-conf] (let [{:keys [restic-repository]} my-conf]
(-> (->
(yaml/from-string (yaml/load-resource "backup/config.yaml")) (yaml/load-as-edn "backup/config.yaml")
(cm/replace-key-value :restic-repository restic-repository)))) (cm/replace-key-value :restic-repository restic-repository))))
(defn generate-cron [] (defn generate-cron []
(yaml/from-string (yaml/load-resource "backup/cron.yaml"))) (yaml/from-string (yaml/load-resource "backup/cron.yaml")))
(defn generate-backup-restore-deployment [my-conf] (defn generate-backup-restore-deployment [my-conf]
(let [backup-restore-yaml (yaml/from-string (yaml/load-resource "backup/backup-restore-deployment.yaml"))] (let [backup-restore-yaml (yaml/load-as-edn "backup/backup-restore-deployment.yaml")]
(if (and (contains? my-conf :local-integration-test) (= true (:local-integration-test my-conf))) (if (and (contains? my-conf :local-integration-test) (= true (:local-integration-test my-conf)))
(cm/replace-named-value backup-restore-yaml "CERTIFICATE_FILE" "/var/run/secrets/localstack-secrets/ca.crt") (cm/replace-named-value backup-restore-yaml "CERTIFICATE_FILE" "/var/run/secrets/localstack-secrets/ca.crt")
backup-restore-yaml))) backup-restore-yaml)))
@ -38,7 +38,7 @@
(defn generate-secret [my-auth] (defn generate-secret [my-auth]
(let [{:keys [aws-access-key-id aws-secret-access-key restic-password]} my-auth] (let [{:keys [aws-access-key-id aws-secret-access-key restic-password]} my-auth]
(-> (->
(yaml/from-string (yaml/load-resource "backup/secret.yaml")) (yaml/load-as-edn "backup/secret.yaml")
(cm/replace-key-value :aws-access-key-id (b64/encode aws-access-key-id)) (cm/replace-key-value :aws-access-key-id (b64/encode aws-access-key-id))
(cm/replace-key-value :aws-secret-access-key (b64/encode aws-secret-access-key)) (cm/replace-key-value :aws-secret-access-key (b64/encode aws-secret-access-key))
(cm/replace-key-value :restic-password (b64/encode restic-password))))) (cm/replace-key-value :restic-password (b64/encode restic-password)))))

@ -1,60 +1,44 @@
(ns dda.c4k-nextcloud.core (ns dda.c4k-nextcloud.core
(:require (:require
[clojure.string :as cs]
[clojure.spec.alpha :as s] [clojure.spec.alpha :as s]
#?(:clj [orchestra.core :refer [defn-spec]] #?(:clj [orchestra.core :refer [defn-spec]]
:cljs [orchestra.core :refer-macros [defn-spec]]) :cljs [orchestra.core :refer-macros [defn-spec]])
[dda.c4k-common.common :as cm]
[dda.c4k-common.predicate :as cp]
[dda.c4k-common.yaml :as yaml] [dda.c4k-common.yaml :as yaml]
[dda.c4k-common.postgres :as postgres] [dda.c4k-common.postgres :as postgres]
[dda.c4k-nextcloud.nextcloud :as nextcloud] [dda.c4k-nextcloud.nextcloud :as nextcloud]
[dda.c4k-nextcloud.backup :as backup])) [dda.c4k-nextcloud.backup :as backup]
[dda.c4k-common.monitoring :as mon]))
(def default-storage-class :local-path) (def default-storage-class :local-path)
(def config-defaults {:issuer "staging"}) (def config-defaults {:issuer "staging"})
(def config? (s/keys :req-un [::nextcloud/fqdn] (defn-spec k8s-objects cp/map-or-seq?
:opt-un [::nextcloud/issuer [config nextcloud/config?
::nextcloud/restic-repository auth nextcloud/auth?]
::nextcloud/pv-storage-size-gb
::nextcloud/pvc-storage-class-name]))
(def auth? (s/keys :req-un [::postgres/postgres-db-user ::postgres/postgres-db-password
::nextcloud/nextcloud-admin-user ::nextcloud/nextcloud-admin-password
::aws-access-key-id ::aws-secret-access-key
::restic-password]))
(s/def ::config config?)
(s/def ::auth auth?)
(defn-spec k8s-objects any?
[config (s/merge config? auth?)]
(let [nextcloud-default-storage-config {:pvc-storage-class-name default-storage-class (let [nextcloud-default-storage-config {:pvc-storage-class-name default-storage-class
:pv-storage-size-gb 200}] :pv-storage-size-gb 200}]
(into (map yaml/to-string
[] (filter
(concat [(yaml/to-string (postgres/generate-config {:postgres-size :8gb})) #(not (nil? %))
(yaml/to-string (postgres/generate-secret config)) (cm/concat-vec
(yaml/to-string (postgres/generate-pvc {:pv-storage-size-gb 50 [(postgres/generate-config {:postgres-size :8gb :db-name "nextcloud"})
:pvc-storage-class-name default-storage-class})) (postgres/generate-secret auth)
(yaml/to-string (postgres/generate-deployment)) (postgres/generate-pvc {:pv-storage-size-gb 50
(yaml/to-string (postgres/generate-service)) :pvc-storage-class-name default-storage-class})
(yaml/to-string (nextcloud/generate-secret config)) (postgres/generate-deployment)
(yaml/to-string (nextcloud/generate-pvc (merge nextcloud-default-storage-config config))) (postgres/generate-service)
(yaml/to-string (nextcloud/generate-deployment config)) (nextcloud/generate-secret auth)
(yaml/to-string (nextcloud/generate-service)) (nextcloud/generate-pvc (merge nextcloud-default-storage-config config))
(yaml/to-string (nextcloud/generate-certificate config)) (nextcloud/generate-deployment config)
(yaml/to-string (nextcloud/generate-ingress config))] (nextcloud/generate-service)]
(when (contains? config :restic-repository) (nextcloud/generate-ingress-and-cert config)
[(yaml/to-string (backup/generate-config config)) (when (:contains? config :restic-repository)
(yaml/to-string (backup/generate-secret config)) [(backup/generate-config config)
(yaml/to-string (backup/generate-cron)) (backup/generate-secret auth)
(yaml/to-string (backup/generate-backup-restore-deployment config))]))))) (backup/generate-cron)
(backup/generate-backup-restore-deployment config)])
(defn-spec generate any? (when (:contains? config :mon-cfg)
[my-config config? (mon/generate (:mon-cfg config) (:mon-auth auth))))))))
my-auth auth?]
(let [resulting-config (merge config-defaults my-config my-auth)]
(cs/join
"\n---\n"
(k8s-objects resulting-config))))

@ -5,9 +5,12 @@
#?(:clj [orchestra.core :refer [defn-spec]] #?(:clj [orchestra.core :refer [defn-spec]]
:cljs [orchestra.core :refer-macros [defn-spec]]) :cljs [orchestra.core :refer-macros [defn-spec]])
[dda.c4k-common.yaml :as yaml] [dda.c4k-common.yaml :as yaml]
[dda.c4k-common.ingress :as ing]
[dda.c4k-common.base64 :as b64] [dda.c4k-common.base64 :as b64]
[dda.c4k-common.predicate :as cp] [dda.c4k-common.predicate :as cp]
[dda.c4k-common.common :as cm])) [dda.c4k-common.postgres :as postgres]
[dda.c4k-common.common :as cm]
[dda.c4k-common.monitoring :as mon]))
(s/def ::fqdn cp/fqdn-string?) (s/def ::fqdn cp/fqdn-string?)
(s/def ::issuer cp/letsencrypt-issuer?) (s/def ::issuer cp/letsencrypt-issuer?)
@ -17,58 +20,58 @@
(s/def ::pvc-storage-class-name cp/pvc-storage-class-name?) (s/def ::pvc-storage-class-name cp/pvc-storage-class-name?)
(s/def ::pv-storage-size-gb pos?) (s/def ::pv-storage-size-gb pos?)
(def strong-config? (s/keys :req-un [::fqdn ::issuer ::pv-storage-size-gb (def config? (s/keys :req-un [::fqdn]
::pvc-storage-class-name] :opt-un [::issuer
:opt-un [::restic-repository])) ::restic-repository
::pv-storage-size-gb
::pvc-storage-class-name
::mon/mon-cfg]))
(def auth? (s/keys :req-un [::postgres/postgres-db-user ::postgres/postgres-db-password
::nextcloud-admin-user ::nextcloud-admin-password
::aws-access-key-id ::aws-secret-access-key
::restic-password]
:opt-un [::mon/mon-auth]))
#?(:cljs #?(:cljs
(defmethod yaml/load-resource :nextcloud [resource-name] (defmethod yaml/load-resource :nextcloud [resource-name]
(case resource-name (case resource-name
"nextcloud/certificate.yaml" (rc/inline "nextcloud/certificate.yaml")
"nextcloud/deployment.yaml" (rc/inline "nextcloud/deployment.yaml") "nextcloud/deployment.yaml" (rc/inline "nextcloud/deployment.yaml")
"nextcloud/ingress.yaml" (rc/inline "nextcloud/ingress.yaml")
"nextcloud/pvc.yaml" (rc/inline "nextcloud/pvc.yaml") "nextcloud/pvc.yaml" (rc/inline "nextcloud/pvc.yaml")
"nextcloud/service.yaml" (rc/inline "nextcloud/service.yaml") "nextcloud/service.yaml" (rc/inline "nextcloud/service.yaml")
"nextcloud/secret.yaml" (rc/inline "nextcloud/secret.yaml") "nextcloud/secret.yaml" (rc/inline "nextcloud/secret.yaml")
(throw (js/Error. "Undefined Resource!"))))) (throw (js/Error. "Undefined Resource!")))))
(defn generate-certificate [config] (defn-spec generate-deployment cp/map-or-seq?
(let [{:keys [fqdn issuer]} config [config config?]
letsencrypt-issuer issuer]
(->
(yaml/from-string (yaml/load-resource "nextcloud/certificate.yaml"))
(assoc-in [:spec :commonName] fqdn)
(assoc-in [:spec :dnsNames] [fqdn])
(assoc-in [:spec :issuerRef :name] letsencrypt-issuer))))
(defn generate-deployment [config]
(let [{:keys [fqdn]} config] (let [{:keys [fqdn]} config]
(-> (yaml/from-string (yaml/load-resource "nextcloud/deployment.yaml")) (-> (yaml/load-as-edn "nextcloud/deployment.yaml")
(cm/replace-all-matching-values-by-new-value "fqdn" fqdn)))) (cm/replace-all-matching-values-by-new-value "fqdn" fqdn))))
(defn generate-ingress [config] (defn-spec generate-ingress-and-cert cp/map-or-seq?
(let [{:keys [fqdn issuer] [config config?]
:or {issuer "staging"}} config (ing/generate-ingress-and-cert
letsencrypt-issuer issuer] (merge
(-> {:service-name "cloud-service"
(yaml/from-string (yaml/load-resource "nextcloud/ingress.yaml")) :service-port 80
(assoc-in [:metadata :annotations :cert-manager.io/cluster-issuer] letsencrypt-issuer) :fqdns [(:fqdn config)]}
(cm/replace-all-matching-values-by-new-value "fqdn" fqdn)))) config)))
(defn-spec generate-pvc cp/map-or-seq? (defn-spec generate-pvc cp/map-or-seq?
[config (s/keys :req-un [::pv-storage-size-gb ::pvc-storage-class-name])] [config (s/keys :req-un [::pv-storage-size-gb ::pvc-storage-class-name])]
(let [{:keys [pv-storage-size-gb pvc-storage-class-name]} config] (let [{:keys [pv-storage-size-gb pvc-storage-class-name]} config]
(-> (->
(yaml/from-string (yaml/load-resource "nextcloud/pvc.yaml")) (yaml/load-as-edn "nextcloud/pvc.yaml")
(assoc-in [:spec :resources :requests :storage] (str pv-storage-size-gb "Gi")) (assoc-in [:spec :resources :requests :storage] (str pv-storage-size-gb "Gi"))
(assoc-in [:spec :storageClassName] (name pvc-storage-class-name))))) (assoc-in [:spec :storageClassName] (name pvc-storage-class-name)))))
(defn generate-service [] (defn generate-service []
(yaml/from-string (yaml/load-resource "nextcloud/service.yaml"))) (yaml/load-as-edn "nextcloud/service.yaml"))
(defn generate-secret [config] (defn-spec generate-secret cp/map-or-seq?
(let [{:keys [nextcloud-admin-user nextcloud-admin-password]} config] [auth auth?]
(let [{:keys [nextcloud-admin-user nextcloud-admin-password]} auth]
(-> (->
(yaml/from-string (yaml/load-resource "nextcloud/secret.yaml")) (yaml/load-as-edn "nextcloud/secret.yaml")
(cm/replace-key-value :nextcloud-admin-user (b64/encode nextcloud-admin-user)) (cm/replace-key-value :nextcloud-admin-user (b64/encode nextcloud-admin-user))
(cm/replace-key-value :nextcloud-admin-password (b64/encode nextcloud-admin-password))))) (cm/replace-key-value :nextcloud-admin-password (b64/encode nextcloud-admin-password)))))

@ -1,31 +1,42 @@
(ns dda.c4k-nextcloud.browser (ns dda.c4k-nextcloud.browser
(:require (:require
[clojure.tools.reader.edn :as edn] [clojure.tools.reader.edn :as edn]
[dda.c4k-common.common :as cm]
[dda.c4k-common.monitoring :as mon]
[dda.c4k-nextcloud.core :as core] [dda.c4k-nextcloud.core :as core]
[dda.c4k-nextcloud.nextcloud :as nextcloud] [dda.c4k-nextcloud.nextcloud :as nextcloud]
[dda.c4k-common.browser :as br] [dda.c4k-common.browser :as br]
[dda.c4k-common.postgres :as pgc])) [dda.c4k-common.postgres :as pgc]))
(defn generate-content (defn generate-content []
[] (cm/concat-vec
(into [] (concat [(assoc (br/generate-needs-validation) :content [(assoc
(into [] (concat (br/generate-input-field "fqdn" "Your fqdn:" "nextcloud-neu.prod.meissa-gmbh.de") (br/generate-needs-validation) :content
(br/generate-input-field "nextcloud-data-volume-path" "(Optional) Your nextcloud-data-volume-path:" "/var/nextcloud") (cm/concat-vec
(br/generate-input-field "postgres-data-volume-path" "(Optional) Your postgres-data-volume-path:" "/var/postgres") (br/generate-group "domain"
(br/generate-input-field "restic-repository" "(Optional) Your restic-repository:" "restic-repository") (cm/concat-vec (br/generate-input-field "fqdn" "Your fqdn:" "nextcloud-neu.prod.meissa-gmbh.de")
(br/generate-input-field "issuer" "(Optional) Your issuer prod/staging:" "") (br/generate-input-field "issuer" "(Optional) Your issuer prod/staging:" "")
[(br/generate-br)] (br/generate-input-field "pv-storage-size-gb" "(Optional) Your nextcloud storage size in GB" "8")
(br/generate-text-area "auth" "Your auth.edn:" "{:postgres-db-user \"nextcloud\" (br/generate-input-field "pvc-storage-class-name" "(Optional) Your storage class type (manual / local-path):" "local-path")
(br/generate-input-field "postgres-data-volume-path" "(Optional) Your postgres-data-volume-path:" "/var/postgres")
(br/generate-input-field "restic-repository" "(Optional) Your restic-repository:" "restic-repository")
(br/generate-input-field "mon-cluster-name" "(Optional) monitoring cluster name:" "keycloak")
(br/generate-input-field "mon-cluster-stage" "(Optional) monitoring cluster stage:" "test")
(br/generate-input-field "mon-cloud-url" "(Optional) grafana cloud url:" "https://prometheus-prod-01-eu-west-0.grafana.net/api/prom/push")))
(br/generate-group "credentials"
(br/generate-text-area "auth" "Your auth.edn:" "{:postgres-db-user \"nextcloud\"
:postgres-db-password \"nextcloud-db-password\" :postgres-db-password \"nextcloud-db-password\"
:nextcloud-admin-password \"nextcloud-admin-password\" :nextcloud-admin-password \"nextcloud-admin-password\"
:nextcloud-admin-user \"nextcloud-admin-user\" :nextcloud-admin-user \"nextcloud-admin-user\"
:aws-access-key-id \"aws-id\" :aws-access-key-id \"aws-id\"
:aws-secret-access-key \"aws-secret\" :aws-secret-access-key \"aws-secret\"
:restic-password \"restic-password\"}" :restic-password \"restic-password\"}
"5") :mon-auth {:grafana-cloud-user \"your-user-id\"
[(br/generate-br)] :grafana-cloud-password \"your-cloud-password\"}"
(br/generate-button "generate-button" "Generate c4k yaml"))))] "5"))
(br/generate-output "c4k-nextcloud-output" "Your c4k deployment.yaml:" "25")))) [(br/generate-br)]
(br/generate-button "generate-button" "Generate c4k yaml")))]
(br/generate-output "c4k-nextcloud-output" "Your c4k deployment.yaml:" "25")))
(defn generate-content-div (defn generate-content-div
[] []
@ -35,29 +46,40 @@
(generate-content)}) (generate-content)})
(defn config-from-document [] (defn config-from-document []
(let [nextcloud-data-volume-path (br/get-content-from-element "nextcloud-data-volume-path" :optional true) (let [pv-storage-size-gb (br/get-content-from-element "pv-storage-size-gb" :optional true)
pvc-storage-class-name (br/get-content-from-element "pvc-storage-class-name" :optional true)
postgres-data-volume-path (br/get-content-from-element "postgres-data-volume-path" :optional true) postgres-data-volume-path (br/get-content-from-element "postgres-data-volume-path" :optional true)
restic-repository (br/get-content-from-element "restic-repository" :optional true) restic-repository (br/get-content-from-element "restic-repository" :optional true)
issuer (br/get-content-from-element "issuer" :optional true :deserializer keyword)] issuer (br/get-content-from-element "issuer" :optional true)
mon-cluster-name (br/get-content-from-element "mon-cluster-name" :optional true)
mon-cluster-stage (br/get-content-from-element "mon-cluster-stage" :optional true)
mon-cloud-url (br/get-content-from-element "mon-cloud-url" :optional true)]
(merge (merge
{:fqdn (br/get-content-from-element "fqdn")} {:fqdn (br/get-content-from-element "fqdn")}
(when (some? nextcloud-data-volume-path) (when (and (some? pv-storage-size-gb) (some? pvc-storage-class-name))
{:nextcloud-data-volume-path nextcloud-data-volume-path}) {:pv-storage-size-gb pv-storage-size-gb :pvc-storage-class-name pvc-storage-class-name})
(when (some? postgres-data-volume-path) (when (some? postgres-data-volume-path)
{:postgres-data-volume-path postgres-data-volume-path}) {:postgres-data-volume-path postgres-data-volume-path})
(when (some? restic-repository) (when (some? restic-repository)
{:restic-repository restic-repository}) {:restic-repository restic-repository})
(when (some? issuer) (when (some? issuer)
{:issuer issuer}) {:issuer issuer})
))) (when (some? mon-cluster-name)
{:mon-cfg {:cluster-name mon-cluster-name
:cluster-stage (keyword mon-cluster-stage)
:grafana-cloud-url mon-cloud-url}}))))
(defn validate-all! [] (defn validate-all! []
(br/validate! "fqdn" ::nextcloud/fqdn) (br/validate! "fqdn" ::nextcloud/fqdn)
(br/validate! "nextcloud-data-volume-path" ::nextcloud/nextcloud-data-volume-path :optional true) (br/validate! "pv-storage-size-gb" ::nextcloud/pv-storage-size-gb :optional true)
(br/validate! "pvc-storage-class-name" ::nextcloud/pvc-storage-class-name :optional true)
(br/validate! "postgres-data-volume-path" ::pgc/postgres-data-volume-path :optional true) (br/validate! "postgres-data-volume-path" ::pgc/postgres-data-volume-path :optional true)
(br/validate! "restic-repository" ::nextcloud/restic-repository :optional true) (br/validate! "restic-repository" ::nextcloud/restic-repository :optional true)
(br/validate! "issuer" ::nextcloud/issuer :optional true :deserializer keyword) (br/validate! "issuer" ::nextcloud/issuer :optional true)
(br/validate! "auth" core/auth? :deserializer edn/read-string) (br/validate! "mon-cluster-name" ::mon/cluster-name :optional true)
(br/validate! "mon-cluster-stage" ::mon/cluster-stage :optional true)
(br/validate! "mon-cloud-url" ::mon/grafana-cloud-url :optional true)
(br/validate! "auth" nextcloud/auth? :deserializer edn/read-string)
(br/set-validated!)) (br/set-validated!))
(defn add-validate-listener [name] (defn add-validate-listener [name]
@ -70,13 +92,19 @@
(.getElementById "generate-button") (.getElementById "generate-button")
(.addEventListener "click" (.addEventListener "click"
#(do (validate-all!) #(do (validate-all!)
(-> (core/generate (-> (cm/generate-common
(config-from-document) (config-from-document)
(br/get-content-from-element "auth" :deserializer edn/read-string)) (br/get-content-from-element "auth" :deserializer edn/read-string)
{}
core/k8s-objects)
(br/set-output!))))) (br/set-output!)))))
(add-validate-listener "fqdn") (add-validate-listener "fqdn")
(add-validate-listener "nextcloud-data-volume-path") (add-validate-listener "pv-storage-size-gb")
(add-validate-listener "pvc-storage-class-name")
(add-validate-listener "postgres-data-volume-path") (add-validate-listener "postgres-data-volume-path")
(add-validate-listener "restic-repository") (add-validate-listener "restic-repository")
(add-validate-listener "issuer") (add-validate-listener "issuer")
(add-validate-listener "mon-cluster-name")
(add-validate-listener "mon-cluster-stage")
(add-validate-listener "mon-cloud-url")
(add-validate-listener "auth")) (add-validate-listener "auth"))

@ -1,15 +0,0 @@
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: cloud-cert
namespace: default
spec:
secretName: cloud-cert
duration: 2160h # 90d
renewBefore: 360h # 15d
commonName: fqdn
dnsNames:
- fqdn
issuerRef:
name: staging
kind: ClusterIssuer

@ -18,7 +18,7 @@ spec:
redeploy: v3 redeploy: v3
spec: spec:
containers: containers:
- image: domaindrivenarchitecture/c4k-cloud - image: domaindrivenarchitecture/c4k-cloud:7.0.0
name: cloud-app name: cloud-app
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
ports: ports:

@ -1,29 +0,0 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-cloud
annotations:
cert-manager.io/cluster-issuer: letsencrypt-staging-issuer
ingress.kubernetes.io/ssl-redirect: "true"
ingress.kubernetes.io/rewrite-target: /
ingress.kubernetes.io/proxy-body-size: "256m"
ingress.kubernetes.io/proxy-connect-timeout: "300"
ingress.kubernetes.io/proxy-send-timeout: "300"
ingress.kubernetes.io/proxy-read-timeout: "300"
namespace: default
spec:
tls:
- hosts:
- fqdn
secretName: cloud-cert
rules:
- host: fqdn
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: cloud-service
port:
number: 80

@ -1,55 +0,0 @@
(ns dda.c4k-nextcloud.core-test
(:require
#?(:clj [clojure.test :refer [deftest is are testing run-tests]]
:cljs [cljs.test :refer-macros [deftest is are testing run-tests]])
[clojure.string :as st]
[dda.c4k-nextcloud.core :as cut]
))
(deftest should-k8s-objects
(is (= 15
(count (cut/k8s-objects {:fqdn "nextcloud-neu.prod.meissa-gmbh.de"
:postgres-db-user "nextcloud"
:postgres-db-password "nextcloud-db-password"
:nextcloud-admin-user "cloudadmin"
:nextcloud-admin-password "cloudpassword"
:issuer "prod"
:aws-access-key-id "aws-id"
:aws-secret-access-key "aws-secret"
:restic-password "restic-pw"
:restic-repository "restic-repository"}))))
(is (= 11
(count (cut/k8s-objects {:fqdn "nextcloud-neu.prod.meissa-gmbh.de"
:postgres-db-user "nextcloud"
:postgres-db-password "nextcloud-db-password"
:nextcloud-admin-user "cloudadmin"
:nextcloud-admin-password "cloudpassword"
:issuer "prod"
:aws-access-key-id "aws-id"
:aws-secret-access-key "aws-secret"
:restic-password "restic-pw"}))))
(is (st/includes?
(get-in (cut/k8s-objects {:fqdn "nextcloud-neu.prod.meissa-gmbh.de"
:postgres-db-user "nextcloud"
:postgres-db-password "nextcloud-db-password"
:nextcloud-admin-user "cloudadmin"
:nextcloud-admin-password "cloudpassword"
:issuer "prod"
:aws-access-key-id "aws-id"
:aws-secret-access-key "aws-secret"
:restic-password "restic-pw"})
[0])
"max_connections = 700"))
(is (st/includes?
(get-in (cut/k8s-objects {:fqdn "nextcloud-neu.prod.meissa-gmbh.de"
:postgres-db-user "nextcloud"
:postgres-db-password "nextcloud-db-password"
:nextcloud-admin-user "cloudadmin"
:nextcloud-admin-password "cloudpassword"
:issuer "prod"
:aws-access-key-id "aws-id"
:aws-secret-access-key "aws-secret"
:restic-password "restic-pw"})
[6])
"storageClassName: local-path"))
)

@ -2,8 +2,28 @@
(:require (:require
#?(:clj [clojure.test :refer [deftest is are testing run-tests]] #?(:clj [clojure.test :refer [deftest is are testing run-tests]]
:cljs [cljs.test :refer-macros [deftest is are testing run-tests]]) :cljs [cljs.test :refer-macros [deftest is are testing run-tests]])
#?(:cljs [shadow.resource :as rc])
[clojure.spec.alpha :as s]
[clojure.spec.test.alpha :as st]
[dda.c4k-common.yaml :as yaml]
[dda.c4k-nextcloud.nextcloud :as cut])) [dda.c4k-nextcloud.nextcloud :as cut]))
(st/instrument)
#?(:cljs
(defmethod yaml/load-resource :nextcloud-test [resource-name]
(case resource-name
"nextcloud-test/valid-auth.yaml" (rc/inline "nextcloud-test/valid-auth.yaml")
"nextcloud-test/valid-config.yaml" (rc/inline "nextcloud-test/valid-config.yaml")
"nextcloud-test/invalid-auth.yaml" (rc/inline "nextcloud-test/invalid-auth.yaml")
"nextcloud-test/invalid-config.yaml" (rc/inline "nextcloud-test/invalid-config.yaml"))))
(deftest validate-valid-resources
(is (s/valid? cut/config? (yaml/load-as-edn "nextcloud-test/valid-config.yaml")))
(is (s/valid? cut/auth? (yaml/load-as-edn "nextcloud-test/valid-auth.yaml")))
(is (not (s/valid? cut/config? (yaml/load-as-edn "nextcloud-test/invalid-config.yaml"))))
(is (not (s/valid? cut/auth? (yaml/load-as-edn "nextcloud-test/invalid-auth.yaml")))))
(deftest should-generate-secret (deftest should-generate-secret
(is (= {:apiVersion "v1" (is (= {:apiVersion "v1"
:kind "Secret" :kind "Secret"
@ -12,49 +32,50 @@
:data :data
{:nextcloud-admin-user "Y2xvdWRhZG1pbg==" {:nextcloud-admin-user "Y2xvdWRhZG1pbg=="
:nextcloud-admin-password "Y2xvdWRwYXNzd29yZA=="}} :nextcloud-admin-password "Y2xvdWRwYXNzd29yZA=="}}
(cut/generate-secret {:nextcloud-admin-user "cloudadmin" (cut/generate-secret {:postgres-db-user "postgres-user"
:postgres-db-password "postgres-password"
:aws-access-key-id "aws-key"
:aws-secret-access-key "aws-secret-key"
:restic-password "restic-password"
:nextcloud-admin-user "cloudadmin"
:nextcloud-admin-password "cloudpassword"})))) :nextcloud-admin-password "cloudpassword"}))))
(deftest should-generate-certificate (deftest should-generate-ingress-and-cert
(is (= {:apiVersion "cert-manager.io/v1" (is (= [{:apiVersion "cert-manager.io/v1",
:kind "Certificate" :kind "Certificate",
:metadata {:name "cloud-cert", :namespace "default"} :metadata
:spec {:name "cloud-service",
{:secretName "cloud-cert" :labels {:app.kubernetes.part-of "cloud-service"},
:duration "2160h" :namespace "default"},
:renewBefore "360h", :spec
:commonName "xx", {:secretName "cloud-service",
:dnsNames ["xx"] :commonName "somefqdn.de",
:issuerRef :duration "2160h",
{:name "prod", :kind "ClusterIssuer"}}} :renewBefore "360h",
(cut/generate-certificate {:fqdn "xx" :issuer "prod"})))) :dnsNames ["somefqdn.de"],
:issuerRef {:name "staging", :kind "ClusterIssuer"}}}
(deftest should-generate-ingress {:apiVersion "networking.k8s.io/v1",
(is (= {:apiVersion "networking.k8s.io/v1" :kind "Ingress",
:kind "Ingress" :metadata
:metadata {:name "cloud-service",
{:name "ingress-cloud" :namespace "default",
:annotations :labels {:app.kubernetes.part-of "cloud-service"},
{:cert-manager.io/cluster-issuer "staging" :annotations
:ingress.kubernetes.io/proxy-body-size "256m" {:traefik.ingress.kubernetes.io/router.entrypoints "web, websecure",
:ingress.kubernetes.io/ssl-redirect "true" :traefik.ingress.kubernetes.io/router.middlewares
:ingress.kubernetes.io/rewrite-target "/" "default-redirect-https@kubernetescrd",
:ingress.kubernetes.io/proxy-connect-timeout "300" :metallb.universe.tf/address-pool "public"}},
:ingress.kubernetes.io/proxy-send-timeout "300" :spec
:ingress.kubernetes.io/proxy-read-timeout "300"} {:tls [{:hosts ["somefqdn.de"], :secretName "cloud-service"}],
:namespace "default"} :rules
:spec [{:host "somefqdn.de",
{:tls [{:hosts ["xx"], :secretName "cloud-cert"}] :http
:rules {:paths
[{:host "xx" [{:pathType "Prefix",
:http :path "/",
{:paths :backend
[{:path "/" {:service {:name "cloud-service", :port {:number 80}}}}]}}]}}]
:pathType "Prefix" (cut/generate-ingress-and-cert {:fqdn "somefqdn.de"}))))
:backend
{:service
{:name "cloud-service", :port {:number 80}}}}]}}]}}
(cut/generate-ingress {:fqdn "xx"}))))
(deftest should-generate-pvc (deftest should-generate-pvc
(is (= {:apiVersion "v1" (is (= {:apiVersion "v1"
@ -77,7 +98,7 @@
{:metadata {:labels {:app "cloud-app", :app.kubernetes.io/name "cloud-pod", :app.kubernetes.io/application "cloud", :redeploy "v3"}} {:metadata {:labels {:app "cloud-app", :app.kubernetes.io/name "cloud-pod", :app.kubernetes.io/application "cloud", :redeploy "v3"}}
:spec :spec
{:containers {:containers
[{:image "domaindrivenarchitecture/c4k-cloud" [{:image "domaindrivenarchitecture/c4k-cloud:7.0.0"
:name "cloud-app" :name "cloud-app"
:imagePullPolicy "IfNotPresent" :imagePullPolicy "IfNotPresent"
:ports [{:containerPort 80}] :ports [{:containerPort 80}]
@ -93,11 +114,11 @@
[{:name "NEXTCLOUD_ADMIN_USER", :valueFrom {:secretKeyRef {:name "cloud-secret", :key "nextcloud-admin-user"}}} [{:name "NEXTCLOUD_ADMIN_USER", :valueFrom {:secretKeyRef {:name "cloud-secret", :key "nextcloud-admin-user"}}}
{:name "NEXTCLOUD_ADMIN_PASSWORD" {:name "NEXTCLOUD_ADMIN_PASSWORD"
:valueFrom {:secretKeyRef {:name "cloud-secret", :key "nextcloud-admin-password"}}} :valueFrom {:secretKeyRef {:name "cloud-secret", :key "nextcloud-admin-password"}}}
{:name "NEXTCLOUD_TRUSTED_DOMAINS", :value "xx"} {:name "NEXTCLOUD_TRUSTED_DOMAINS", :value "somefqdn.de"}
{:name "POSTGRES_USER", :valueFrom {:secretKeyRef {:name "postgres-secret", :key "postgres-user"}}} {:name "POSTGRES_USER", :valueFrom {:secretKeyRef {:name "postgres-secret", :key "postgres-user"}}}
{:name "POSTGRES_PASSWORD", :valueFrom {:secretKeyRef {:name "postgres-secret", :key "postgres-password"}}} {:name "POSTGRES_PASSWORD", :valueFrom {:secretKeyRef {:name "postgres-secret", :key "postgres-password"}}}
{:name "POSTGRES_DB", :valueFrom {:configMapKeyRef {:name "postgres-config", :key "postgres-db"}}} {:name "POSTGRES_DB", :valueFrom {:configMapKeyRef {:name "postgres-config", :key "postgres-db"}}}
{:name "POSTGRES_HOST", :value "postgresql-service:5432"}] {:name "POSTGRES_HOST", :value "postgresql-service:5432"}]
:volumeMounts [{:name "cloud-data-volume", :mountPath "/var/www/html"}]}] :volumeMounts [{:name "cloud-data-volume", :mountPath "/var/www/html"}]}]
:volumes [{:name "cloud-data-volume", :persistentVolumeClaim {:claimName "cloud-pvc"}}]}}}} :volumes [{:name "cloud-data-volume", :persistentVolumeClaim {:claimName "cloud-pvc"}}]}}}}
(cut/generate-deployment {:fqdn "xx"})))) (cut/generate-deployment {:fqdn "somefqdn.de"}))))

@ -2,6 +2,6 @@ postgres-db-user: "nextcloud"
postgres-db-password: "nextcloud-db-password" postgres-db-password: "nextcloud-db-password"
nextcloud-admin-user: "cloudadmin" nextcloud-admin-user: "cloudadmin"
nextcloud-admin-password: "cloudpassword" nextcloud-admin-password: "cloudpassword"
aws-access-key-id: "aws-id" aws-accss-key-id: "aws-id"
aws-secret-access-key: "aws-secret" aws-secret-access-key: "aws-secret"
restic-password: "restic-password" restic-password: "restic-password"

@ -1,5 +1,5 @@
fqdn: "cloud.test.meissa-gmbh.de" fqdns: "cloud.test.meissa-gmbh.de"
issuer: "staging" issuer: "none"
nextcloud-data-volume-path: "/var/cloud" nextcloud-data-volume-path: "/var/cloud"
postgres-data-volume-path: "/var/postgres" postgres-data-volume-path: "/var/postgres"
restic-repository: "s3:s3.amazonaws.com/your-bucket/your-folder" restic-repository: "s3:s3.amazonaws.com/your-bucket/your-folder"

@ -4,4 +4,6 @@
:nextcloud-admin-password "cloudpassword" :nextcloud-admin-password "cloudpassword"
:aws-access-key-id "aws-id" :aws-access-key-id "aws-id"
:aws-secret-access-key "aws-secret" :aws-secret-access-key "aws-secret"
:restic-password "restic-password"} :restic-password "restic-password"
:mon-auth {:grafana-cloud-user "user"
:grafana-cloud-password "password"}}

@ -0,0 +1,10 @@
postgres-db-user: "nextcloud"
postgres-db-password: "nextcloud-db-password"
nextcloud-admin-user: "cloudadmin"
nextcloud-admin-password: "cloudpassword"
aws-access-key-id: "aws-id"
aws-secret-access-key: "aws-secret"
restic-password: "restic-password"
mon-auth:
grafana-cloud-user: "user"
grafana-cloud-password: "password"

@ -2,4 +2,7 @@
:issuer "staging" :issuer "staging"
:nextcloud-data-volume-path "/var/cloud" :nextcloud-data-volume-path "/var/cloud"
:postgres-data-volume-path "/var/postgres" :postgres-data-volume-path "/var/postgres"
:restic-repository "s3:s3.amazonaws.com/your-bucket/your-folder"} :restic-repository "s3:s3.amazonaws.com/your-bucket/your-folder"
:mon-cfg {:grafana-cloud-url "url-for-your-prom-remote-write-endpoint"
:k3s-cluster-name "jitsi"
:k3s-cluster-stage "test"}}

@ -0,0 +1,9 @@
fqdn: "cloud.test.meissa-gmbh.de"
issuer: "staging"
nextcloud-data-volume-path: "/var/cloud"
postgres-data-volume-path: "/var/postgres"
restic-repository: "s3:s3.amazonaws.com/your-bucket/your-folder"
mon-cfg:
grafana-cloud-url: "url-for-your-prom-remote-write-endpoint"
cluster-name: "keycloak"
cluster-stage: "test"
Loading…
Cancel
Save