diff --git a/doc/tryItOut.png b/doc/tryItOut.png index a4c2b58..6f0bda8 100644 Binary files a/doc/tryItOut.png and b/doc/tryItOut.png differ diff --git a/infrastructure/c4k-website-build/image/resources/entrypoint.sh b/infrastructure/c4k-website-build/image/resources/entrypoint.sh index 6116524..39833e9 100755 --- a/infrastructure/c4k-website-build/image/resources/entrypoint.sh +++ b/infrastructure/c4k-website-build/image/resources/entrypoint.sh @@ -5,10 +5,6 @@ mkdir $SOURCEDIR source /usr/local/bin/functions.sh -function move-website-files-to-target() { - (cd $BUILDDIR; dir=$(ls); cd $dir; rsync -ru --exclude-from "/etc/exclude.pattern" --delete resources/public/* $WEBSITEROOT;) -} - echo "Downloading website" get-and-unzip-website-data echo "Building website" diff --git a/infrastructure/c4k-website-build/image/resources/functions.sh b/infrastructure/c4k-website-build/image/resources/functions.sh index ca52db7..60b673b 100644 --- a/infrastructure/c4k-website-build/image/resources/functions.sh +++ b/infrastructure/c4k-website-build/image/resources/functions.sh @@ -7,6 +7,10 @@ function get-and-unzip-website-data() { } function build-and-extract-website() { - (cd $BUILDDIR; dir=$(ls); cd $dir; timeout -s SIGKILL 35s lein ring server-headless;) + (cd $BUILDDIR; dir=$(ls); cd $dir; lein run;) # websiteartifactname=$(ls target/ | grep -Eo "*.+\.war"); unzip target/$websiteartifactname } + +function move-website-files-to-target() { + (cd $BUILDDIR; dir=$(ls); cd $dir; rsync -ru --exclude-from "/etc/exclude.pattern" --delete resources/public/* $WEBSITEROOT;) +} diff --git a/src/main/cljc/dda/c4k_website/core.cljc b/src/main/cljc/dda/c4k_website/core.cljc index b71b103..0aee851 100644 --- a/src/main/cljc/dda/c4k_website/core.cljc +++ b/src/main/cljc/dda/c4k_website/core.cljc @@ -7,21 +7,55 @@ (def config-defaults {:issuer "staging"}) -(def config? (s/keys :req-un [::website/fqdn] +(def config? (s/keys :req-un [::website/fqdn + ::website/single + ::website/multi + ::website/fqdn1 + ::website/fqdn2] :opt-un [::website/issuer])) (def auth? (s/keys :req-un [::website/authtoken ::website/gitrepourl])) +(defn set-single-repo-url + [config] + (assoc config :gitrepourl (:singlegitrepourl config))) + +(defn set-multi-fqdn ; Sets the first value of :multi to be the name giving fqdn + [config] + (assoc config :fqdn (keyword ((keyword (first (:multi config))) config))) config) + +(defn set-single-fqdn ; Sets the value of :single to be the name giving fqdn + [config] + (assoc config :fqdn ((keyword (:single config)) config))) (defn k8s-objects [config] (cm/concat-vec (map yaml/to-string (filter #(not (nil? %)) - [(website/generate-nginx-deployment config) - (website/generate-nginx-configmap config) - (website/generate-nginx-service config) - (website/generate-website-content-volume config) - (website/generate-ingress config) - (website/generate-certificate config) - (website/generate-website-build-cron config) - (website/generate-website-build-secret config)])))) + [; multi-case + (website/generate-nginx-deployment (set-multi-fqdn config)) + (website/generate-multi-nginx-configmap config) + (website/generate-nginx-service (set-multi-fqdn config)) + (website/generate-website-content-volume (set-multi-fqdn config)) + (website/generate-multi-ingress config) + (website/generate-multi-certificate config) + (website/generate-website-build-cron (set-multi-fqdn config)) + (website/generate-website-build-secret (set-multi-fqdn config)) + ; single case + (website/generate-nginx-deployment (set-single-fqdn config)) + (website/generate-single-nginx-configmap config) + (website/generate-nginx-service (set-single-fqdn config)) + (website/generate-website-content-volume (set-single-fqdn config)) + (website/generate-single-ingress config) + (website/generate-single-certificate config) + (website/generate-website-build-cron (set-single-repo-url (set-single-fqdn config))) + (website/generate-website-build-secret (set-single-fqdn config))])))) + +; read config, +; +; when multi not empty +; call multi-functions and set value of key :fqdn to first value of key of list of :multi +; then call general functions with modified input +; if single empty, return nil for any single function +; else call single-functions and set value of key :fqdn to value of key of key :single +; then call general functions with modified input \ No newline at end of file diff --git a/src/main/cljc/dda/c4k_website/website.cljc b/src/main/cljc/dda/c4k_website/website.cljc index 9e86e7b..47eb265 100644 --- a/src/main/cljc/dda/c4k_website/website.cljc +++ b/src/main/cljc/dda/c4k_website/website.cljc @@ -1,6 +1,6 @@ (ns dda.c4k-website.website (:require - [clojure.spec.alpha :as s] + [clojure.spec.alpha :as s] [clojure.string :as st] #?(:cljs [shadow.resource :as rc]) #?(:clj [orchestra.core :refer [defn-spec]] @@ -10,19 +10,32 @@ [dda.c4k-common.yaml :as yaml] [dda.c4k-common.common :as cm] [dda.c4k-common.base64 :as b64] - [dda.c4k-common.predicate :as pred])) + [dda.c4k-common.predicate :as pred] + [clojure.string :as str])) + +(defn keyword-string? + [input] + (str/starts-with? input "fqdn")) + +(defn keyword-string-list? + [input] + (every? true? (map keyword-string? input))) (s/def ::fqdn pred/fqdn-string?) +(s/def ::fqdn1 pred/fqdn-string?) +(s/def ::fqdn2 pred/fqdn-string?) +(s/def ::single keyword-string?) +(s/def ::multi keyword-string-list?) (s/def ::issuer pred/letsencrypt-issuer?) (s/def ::authtoken pred/bash-env-string?) (s/def ::gitrepourl pred/bash-env-string?) -(def config? (s/keys :req-un [::fqdn] +(def config? (s/keys :req-un [::fqdn ::single ::multi ::fqdn1 ::fqdn2] :opt-un [::issuer])) -(def auth? (s/keys :req-un [::authtoken ::gitrepourl])) +(def auth? (s/keys :req-un [::authtoken ::gitrepourl ::singlegitrepourl])) -(def volume-size 3) +(def volume-size 3) (defn unique-name-from-fqdn [fqdn] @@ -41,11 +54,14 @@ #?(:cljs (defmethod yaml/load-resource :website [resource-name] (case resource-name - "website/certificate.yaml" (rc/inline "website/certificate.yaml") - "website/ingress.yaml" (rc/inline "website/ingress.yaml") - "website/nginx-configmap.yaml" (rc/inline "website/nginx-configmap.yaml") + "website/single-certificate.yaml" (rc/inline "website/single-certificate.yaml") + "website/multi-certificate.yaml" (rc/inline "website/multi-certificate.yaml") + "website/single-ingress.yaml" (rc/inline "website/single-ingress.yaml") + "website/multi-ingress.yaml" (rc/inline "website/multi-ingress.yaml") + "website/single-nginx-configmap.yaml" (rc/inline "website/single-nginx-configmap.yaml") + "website/multi-nginx-configmap.yaml" (rc/inline "website/multi-nginx-configmap.yaml") "website/nginx-deployment.yaml" (rc/inline "website/nginx-deployment.yaml") - "website/nginx-service.yaml" (rc/inline "website/nginx-service.yaml") + "website/nginx-service.yaml" (rc/inline "website/nginx-service.yaml") "website/website-content-volume.yaml" (rc/inline "website/website-content-volume.yaml") "website/website-build-cron.yaml" (rc/inline "website/website-build-cron.yaml") "website/website-build-deployment.yaml" (rc/inline "website/website-build-deployment.yaml") @@ -56,33 +72,72 @@ (defmethod yaml/load-as-edn :website [resource-name] (yaml/from-string (yaml/load-resource resource-name)))) -(defn-spec generate-certificate pred/map-or-seq? +(defn-spec generate-single-certificate pred/map-or-seq? [config config?] - (let [{:keys [fqdn issuer] + (let [{:keys [issuer single] :or {issuer "staging"}} config + fqdn ((keyword single) config) letsencrypt-issuer (name issuer)] (-> - (yaml/load-as-edn "website/certificate.yaml") + (yaml/load-as-edn "website/single-certificate.yaml") (assoc-in [:spec :issuerRef :name] letsencrypt-issuer) (replace-all-matching-subvalues-in-string-start "NAME" (unique-name-from-fqdn fqdn)) (cm/replace-all-matching-values-by-new-value "FQDN" fqdn)))) -(defn-spec generate-ingress pred/map-or-seq? +(defn-spec generate-single-ingress pred/map-or-seq? [config config?] - (let [{:keys [fqdn]} config] + (let [{:keys [single]} config + fqdn ((keyword single) config)] (-> - (yaml/load-as-edn "website/ingress.yaml") + (yaml/load-as-edn "website/single-ingress.yaml") (replace-all-matching-subvalues-in-string-start "NAME" (unique-name-from-fqdn fqdn)) (cm/replace-all-matching-values-by-new-value "FQDN" fqdn)))) -(defn-spec generate-nginx-configmap pred/map-or-seq? +(defn-spec generate-single-nginx-configmap pred/map-or-seq? [config config?] - (let [{:keys [fqdn]} config - configmap (yaml/load-as-edn "website/nginx-configmap.yaml")] + (let [{:keys [single]} config + fqdn ((keyword single) config) + configmap (yaml/load-as-edn "website/single-nginx-configmap.yaml")] (-> configmap (assoc-in [:data :website.conf] (st/replace (-> configmap :data :website.conf) #"FQDN" (str fqdn ";"))) - (replace-all-matching-subvalues-in-string-start "NAME" (unique-name-from-fqdn fqdn))))) + (replace-all-matching-subvalues-in-string-start "NAME" (unique-name-from-fqdn fqdn))))) + +(defn-spec generate-multi-certificate pred/map-or-seq? + [config config?] + (let [{:keys [issuer multi] + :or {issuer "staging"}} config + fqdn ((keyword (first multi)) config) + fqdn1 ((keyword (second multi)) config) + letsencrypt-issuer (name issuer)] + (-> + (yaml/load-as-edn "website/multi-certificate.yaml") + (assoc-in [:spec :issuerRef :name] letsencrypt-issuer) + (replace-all-matching-subvalues-in-string-start "NAME" (unique-name-from-fqdn fqdn)) + (cm/replace-all-matching-values-by-new-value "FQDN" fqdn) + (cm/replace-all-matching-values-by-new-value "FQDN1" fqdn1)))) + +(defn-spec generate-multi-ingress pred/map-or-seq? + [config config?] + (let [{:keys [multi]} config + fqdn ((keyword (first multi)) config) + fqdn1 ((keyword (second multi)) config)] + (-> + (yaml/load-as-edn "website/multi-ingress.yaml") + (replace-all-matching-subvalues-in-string-start "NAME" (unique-name-from-fqdn fqdn)) + (cm/replace-all-matching-values-by-new-value "FQDN" fqdn) + (cm/replace-all-matching-values-by-new-value "FQDN1" fqdn1)))) + +(defn-spec generate-multi-nginx-configmap pred/map-or-seq? + [config config?] + (let [{:keys [multi]} config + fqdn ((keyword (first multi)) config) + fqdn1 ((keyword (second multi)) config) + configmap (yaml/load-as-edn "website/multi-nginx-configmap.yaml")] + (-> + configmap + (assoc-in [:data :website.conf] (st/replace (-> configmap :data :website.conf) #"FQDN\ FQDN1" (str fqdn " " fqdn1 ";"))) + (replace-all-matching-subvalues-in-string-start "NAME" (unique-name-from-fqdn fqdn))))) (defn-spec generate-nginx-deployment pred/map-or-seq? [config config?] @@ -124,8 +179,8 @@ (defn-spec generate-website-build-secret pred/map-or-seq? [auth auth?] - (let [{:keys [fqdn - authtoken + (let [{:keys [fqdn + authtoken gitrepourl]} auth] (-> (yaml/load-as-edn "website/website-build-secret.yaml") diff --git a/src/main/cljs/dda/c4k_website/browser.cljs b/src/main/cljs/dda/c4k_website/browser.cljs index d69d012..ef168dc 100644 --- a/src/main/cljs/dda/c4k_website/browser.cljs +++ b/src/main/cljs/dda/c4k_website/browser.cljs @@ -29,14 +29,19 @@ (generate-group "domain" (cm/concat-vec - (br/generate-input-field "fqdn" "Your fqdn:" "deineWebsite.de") + (br/generate-input-field "fqdn" "Your first fqdn:" "deineWebsite.de") + (br/generate-input-field "fqdn1" "Your second fqdn:" "deineWebsite.com") + (br/generate-input-field "fqdn2" "Your third fqdn:" "meineWebsite.org") + (br/generate-input-field "multi" "Holds fqdns pointing to same ingress" "[\"fqdn\", \"fqdn1\"]") + (br/generate-input-field "single" "Holds fqdn pointing to another ingress" "fqdn") (br/generate-input-field "issuer" "(Optional) Your issuer prod/staging:" ""))) (generate-group "credentials" (br/generate-text-area "auth" "Your auth.edn:" - "{:gitrepourl \"https://your.gitea.host/api/v1/repos///archive/.zip\" - :authtoken \"yourgiteaauthtoken\" + "{:authtoken \"yourgiteaauthtoken\" + :gitrepourl \"https://your.gitea.host/api/v1/repos///archive/.zip\" + :singlegitrepourl \"https://your.gitea.host/api/v1/repos///archive/.zip\" }" "3")) [(br/generate-br)] @@ -59,6 +64,10 @@ (defn validate-all! [] (br/validate! "fqdn" ::website/fqdn) + (br/validate! "fqdn1" ::website/fqdn1) + (br/validate! "fqdn2" ::website/fqdn2) + (br/validate! "single" ::website/single) + (br/validate! "multi" ::website/multi) (br/validate! "issuer" ::website/issuer :optional true) (br/validate! "auth" core/auth? :deserializer edn/read-string) (br/set-form-validated!)) @@ -81,5 +90,9 @@ core/k8s-objects) (br/set-output!))))) (add-validate-listener "fqdn") + (add-validate-listener "fqdn1") + (add-validate-listener "fqdn2") + (add-validate-listener "single") + (add-validate-listener "multi") (add-validate-listener "issuer") (add-validate-listener "auth")) diff --git a/src/main/resources/website/multi-certificate.yaml b/src/main/resources/website/multi-certificate.yaml new file mode 100644 index 0000000..27768b3 --- /dev/null +++ b/src/main/resources/website/multi-certificate.yaml @@ -0,0 +1,17 @@ +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: NAME-cert + namespace: default +spec: + secretName: NAME-cert + commonName: FQDN + duration: 2160h # 90d + renewBefore: 360h # 15d + dnsNames: + - FQDN + - FQDN1 + issuerRef: + name: staging + kind: ClusterIssuer + \ No newline at end of file diff --git a/src/main/resources/website/multi-ingress.yaml b/src/main/resources/website/multi-ingress.yaml new file mode 100644 index 0000000..a37e8db --- /dev/null +++ b/src/main/resources/website/multi-ingress.yaml @@ -0,0 +1,36 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: NAME-ingress + namespace: default + annotations: + ingress.kubernetes.io/ssl-redirect: "true" + traefik.ingress.kubernetes.io/router.middlewares: default-redirect-https@kubernetescrd +spec: + tls: + - hosts: + - FQDN + - FQDN1 + secretName: NAME-cert + rules: + - host: FQDN + http: + paths: + - pathType: Prefix + path: "/" + backend: + service: + name: NAME-service + port: + number: 80 + - host: FQDN1 + http: + paths: + - pathType: Prefix + path: "/" + backend: + service: + name: NAME-service + port: + number: 80 + \ No newline at end of file diff --git a/src/main/resources/website/multi-nginx-configmap.yaml b/src/main/resources/website/multi-nginx-configmap.yaml new file mode 100644 index 0000000..a8e0348 --- /dev/null +++ b/src/main/resources/website/multi-nginx-configmap.yaml @@ -0,0 +1,99 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: NAME-configmap + namespace: default +data: + nginx.conf: | + user nginx; + worker_processes 3; + error_log /var/log/nginx/error.log; + pid /var/log/nginx/nginx.pid; + worker_rlimit_nofile 8192; + events { + worker_connections 4096; + } + http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + log_format main '$remote_addr - $remote_user [$time_local] $status' + '"$request" $body_bytes_sent "$http_referer"' + '"$http_user_agent" "$http_x_forwarded_for"'; + access_log /var/log/nginx/access.log main; + sendfile on; + tcp_nopush on; + keepalive_timeout 65; + server_names_hash_bucket_size 128; + include /etc/nginx/conf.d/website.conf; + } + mime.types: | + types { + text/html html htm shtml; + text/css css; + text/xml xml rss; + image/gif gif; + image/jpeg jpeg jpg; + application/x-javascript js; + text/plain txt; + text/x-component htc; + text/mathml mml; + image/png png; + image/x-icon ico; + image/x-jng jng; + image/vnd.wap.wbmp wbmp; + application/java-archive jar war ear; + application/mac-binhex40 hqx; + application/pdf pdf; + application/x-cocoa cco; + application/x-java-archive-diff jardiff; + application/x-java-jnlp-file jnlp; + application/x-makeself run; + application/x-perl pl pm; + application/x-pilot prc pdb; + application/x-rar-compressed rar; + application/x-redhat-package-manager rpm; + application/x-sea sea; + application/x-shockwave-flash swf; + application/x-stuffit sit; + application/x-tcl tcl tk; + application/x-x509-ca-cert der pem crt; + application/x-xpinstall xpi; + application/zip zip; + application/octet-stream deb; + application/octet-stream bin exe dll; + application/octet-stream dmg; + application/octet-stream eot; + application/octet-stream iso img; + application/octet-stream msi msp msm; + audio/mpeg mp3; + audio/x-realaudio ra; + video/mpeg mpeg mpg; + video/quicktime mov; + video/x-flv flv; + video/x-msvideo avi; + video/x-ms-wmv wmv; + video/x-ms-asf asx asf; + video/x-mng mng; + } + website.conf: | + server { + listen 80 default_server; + listen [::]:80 default_server; + listen 443 ssl; + ssl_certificate /etc/certs/tls.crt; + ssl_certificate_key /etc/certs/tls.key; + server_name FQDN FQDN1 + add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload'; + add_header Content-Security-Policy "default-src 'self'; font-src *;img-src * data:; script-src *; style-src *"; + add_header X-XSS-Protection "1; mode=block"; + add_header X-Frame-Options "SAMEORIGIN"; + add_header X-Content-Type-Options nosniff; + add_header Referrer-Policy "strict-origin"; + # add_header Permissions-Policy "permissions here"; + root /var/www/html/website/; + index index.html; + location / { + try_files $uri $uri/ /index.html =404; + } + } + \ No newline at end of file diff --git a/src/main/resources/website/nginx-deployment.yaml b/src/main/resources/website/nginx-deployment.yaml index eba5998..ce44bda 100644 --- a/src/main/resources/website/nginx-deployment.yaml +++ b/src/main/resources/website/nginx-deployment.yaml @@ -15,7 +15,7 @@ spec: containers: - name: NAME-nginx image: nginx:latest - imagePullPolicy: "Always" + imagePullPolicy: IfNotPresent ports: - containerPort: 80 volumeMounts: diff --git a/src/main/resources/website/certificate.yaml b/src/main/resources/website/single-certificate.yaml similarity index 100% rename from src/main/resources/website/certificate.yaml rename to src/main/resources/website/single-certificate.yaml diff --git a/src/main/resources/website/ingress.yaml b/src/main/resources/website/single-ingress.yaml similarity index 100% rename from src/main/resources/website/ingress.yaml rename to src/main/resources/website/single-ingress.yaml diff --git a/src/main/resources/website/nginx-configmap.yaml b/src/main/resources/website/single-nginx-configmap.yaml similarity index 100% rename from src/main/resources/website/nginx-configmap.yaml rename to src/main/resources/website/single-nginx-configmap.yaml diff --git a/src/test/cljc/dda/c4k_website/website_test.cljc b/src/test/cljc/dda/c4k_website/website_test.cljc index da52cf0..a4507c6 100644 --- a/src/test/cljc/dda/c4k_website/website_test.cljc +++ b/src/test/cljc/dda/c4k_website/website_test.cljc @@ -5,20 +5,32 @@ [clojure.spec.test.alpha :as st] [dda.c4k-common.test-helper :as th] [dda.c4k-common.base64 :as b64] - [dda.c4k-website.website :as cut])) + [dda.c4k-website.website :as cut] + [dda.c4k-website.core :as cutc])) -(st/instrument `cut/generate-certificate) -(st/instrument `cut/generate-ingress) -(st/instrument `cut/generate-nginx-configmap) +(st/instrument `cut/generate-single-certificate) +(st/instrument `cut/generate-single-ingress) +(st/instrument `cut/generate-single-nginx-configmap) +(st/instrument `cut/generate-multi-certificate) +(st/instrument `cut/generate-multi-ingress) +(st/instrument `cut/generate-multi-nginx-configmap) (st/instrument `cut/generate-website-content-volume) -(deftest should-generate-certificate +(deftest should-generate-single-certificate (is (= {:name-c2 "prod", :name-c1 "staging"} - (th/map-diff (cut/generate-certificate {:fqdn "test.de"}) - (cut/generate-certificate {:issuer "prod" - :fqdn "test.de"}))))) + (th/map-diff (cut/generate-single-certificate {:fqdn "test.de" + :fqdn1 "test.org" + :single "fqdn1" + :fqdn2 "bla.com" + :multi ["fqdn1", "fqdn"]}) + (cut/generate-single-certificate {:fqdn "test.com" + :fqdn1 "test.org" + :issuer "prod" + :single "fqdn1" + :fqdn2 "bla.com" + :multi ["fqdn1", "fqdn"]}))))) -(deftest should-generate-ingress +(deftest should-generate-single-ingress (is (= {:apiVersion "networking.k8s.io/v1", :kind "Ingress", :metadata @@ -32,15 +44,79 @@ :rules [{:host "test.de", :http {:paths [{:pathType "Prefix", :path "/", :backend {:service {:name "test-de-service", :port {:number 80}}}}]}}]}} - (cut/generate-ingress {:fqdn "test.de"})))) + (cut/generate-single-ingress {:fqdn "test.de" + :fqdn1 "test.org" + :fqdn2 "bla.com" + :multi ["fqdn1", "fqdn"] + :single "fqdn"})))) -(deftest should-generate-nginx-configmap +(deftest should-generate-single-nginx-configmap (is (= {:website.conf-c1 "server {\n listen 80 default_server;\n listen [::]:80 default_server;\n listen 443 ssl;\n ssl_certificate /etc/certs/tls.crt;\n ssl_certificate_key /etc/certs/tls.key;\n server_name test.de; \n add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload';\n add_header Content-Security-Policy \"default-src 'self'; font-src *;img-src * data:; script-src *; style-src *\";\n add_header X-XSS-Protection \"1; mode=block\";\n add_header X-Frame-Options \"SAMEORIGIN\";\n add_header X-Content-Type-Options nosniff;\n add_header Referrer-Policy \"strict-origin\";\n # add_header Permissions-Policy \"permissions here\";\n root /var/www/html/website/;\n index index.html;\n location / {\n try_files $uri $uri/ /index.html =404;\n }\n}\n", :website.conf-c2 "server {\n listen 80 default_server;\n listen [::]:80 default_server;\n listen 443 ssl;\n ssl_certificate /etc/certs/tls.crt;\n ssl_certificate_key /etc/certs/tls.key;\n server_name test.com; \n add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload';\n add_header Content-Security-Policy \"default-src 'self'; font-src *;img-src * data:; script-src *; style-src *\";\n add_header X-XSS-Protection \"1; mode=block\";\n add_header X-Frame-Options \"SAMEORIGIN\";\n add_header X-Content-Type-Options nosniff;\n add_header Referrer-Policy \"strict-origin\";\n # add_header Permissions-Policy \"permissions here\";\n root /var/www/html/website/;\n index index.html;\n location / {\n try_files $uri $uri/ /index.html =404;\n }\n}\n", :name-c1 "test-de-configmap", :name-c2 "test-com-configmap"} - (th/map-diff (cut/generate-nginx-configmap {:fqdn "test.de"}) - (cut/generate-nginx-configmap {:fqdn "test.com"}))))) + (th/map-diff (cut/generate-single-nginx-configmap {:fqdn "test.de" + :fqdn1 "test.org" + :single "fqdn" + :fqdn2 "bla.com" + :multi ["fqdn1", "fqdn"]}) + (cut/generate-single-nginx-configmap {:fqdn "test.org" + :fqdn1 "test.com" + :single "fqdn1" + :fqdn2 "bla.com" + :multi ["fqdn1", "fqdn"]}))))) + +(deftest should-generate-multi-certificate + (is (= {:name-c2 "prod", :name-c1 "staging"} + (th/map-diff (cut/generate-multi-certificate {:fqdn "test.de" + :fqdn1 "test.com" + :fqdn2 "test.io" + :single "fqdn1" + :multi ["fqdn", "fqdn2"]}) + (cut/generate-multi-certificate {:fqdn "test.io" + :fqdn1 "test.com" + :fqdn2 "test.de" + :single "fqdn1" + :multi ["fqdn2", "fqdn"] + :issuer "prod"}))))) + +(deftest should-generate-multi-ingress + (is (= {:apiVersion "networking.k8s.io/v1", + :kind "Ingress", + :metadata + {:name "test-de-ingress", + :namespace "default", + :annotations + {:ingress.kubernetes.io/ssl-redirect "true", + :traefik.ingress.kubernetes.io/router.middlewares "default-redirect-https@kubernetescrd"}}, + :spec + {:tls [{:hosts ["test.de", "test.io"], :secretName "test-de-cert"}], + :rules + [{:host "test.de", + :http {:paths [{:pathType "Prefix", :path "/", :backend {:service {:name "test-de-service", :port {:number 80}}}}]}} + {:host "test.io", + :http {:paths [{:pathType "Prefix", :path "/", :backend {:service {:name "test-de-service", :port {:number 80}}}}]}}]}} + (cut/generate-multi-ingress {:fqdn "test.de" + :fqdn1 "test.com" + :fqdn2 "test.io" + :single "fqdn1" + :multi ["fqdn", "fqdn2"]})))) + +(deftest should-generate-nginx-multi-configmap + (is (= {:website.conf-c1 "server {\n listen 80 default_server;\n listen [::]:80 default_server;\n listen 443 ssl;\n ssl_certificate /etc/certs/tls.crt;\n ssl_certificate_key /etc/certs/tls.key;\n server_name test.de test.io; \n add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload';\n add_header Content-Security-Policy \"default-src 'self'; font-src *;img-src * data:; script-src *; style-src *\";\n add_header X-XSS-Protection \"1; mode=block\";\n add_header X-Frame-Options \"SAMEORIGIN\";\n add_header X-Content-Type-Options nosniff;\n add_header Referrer-Policy \"strict-origin\";\n # add_header Permissions-Policy \"permissions here\";\n root /var/www/html/website/;\n index index.html;\n location / {\n try_files $uri $uri/ /index.html =404;\n }\n}\n", + :website.conf-c2 "server {\n listen 80 default_server;\n listen [::]:80 default_server;\n listen 443 ssl;\n ssl_certificate /etc/certs/tls.crt;\n ssl_certificate_key /etc/certs/tls.key;\n server_name test.com test.io; \n add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload';\n add_header Content-Security-Policy \"default-src 'self'; font-src *;img-src * data:; script-src *; style-src *\";\n add_header X-XSS-Protection \"1; mode=block\";\n add_header X-Frame-Options \"SAMEORIGIN\";\n add_header X-Content-Type-Options nosniff;\n add_header Referrer-Policy \"strict-origin\";\n # add_header Permissions-Policy \"permissions here\";\n root /var/www/html/website/;\n index index.html;\n location / {\n try_files $uri $uri/ /index.html =404;\n }\n}\n", + :name-c1 "test-de-configmap", + :name-c2 "test-com-configmap"} + (th/map-diff (cut/generate-multi-nginx-configmap {:fqdn "test.de" + :fqdn1 "test.com" + :fqdn2 "test.io" + :single "fqdn1" + :multi ["fqdn", "fqdn2"]}) + (cut/generate-multi-nginx-configmap {:fqdn "test.de" + :fqdn1 "test.com" + :fqdn2 "test.io" + :single "fqdn2" + :multi ["fqdn1", "fqdn2"]}))))) (deftest should-generate-nginx-deployment (is (= {:apiVersion "apps/v1", @@ -55,7 +131,7 @@ {:containers [{:name "test-de-nginx", :image "nginx:latest", - :imagePullPolicy "Always", + :imagePullPolicy "IfNotPresent", :ports [{:containerPort 80}], :volumeMounts [{:mountPath "/etc/nginx", :readOnly true, :name "nginx-config-volume"} @@ -75,18 +151,69 @@ {:name "website-cert", :secret {:secretName "test-de-cert", :items [{:key "tls.crt", :path "tls.crt"} {:key "tls.key", :path "tls.key"}]}}]}}}} - (cut/generate-nginx-deployment {:fqdn "test.de"})))) + (cut/generate-nginx-deployment {:fqdn "test.de" + :fqdn1 "test.com" + :fqdn2 "test.io" + :single "fqdn2" + :multi ["fqdn1", "fqdn2"]})))) -(deftest should-generate-nginx-service ;todo +(deftest should-generate-nginx-deployment-set-single + (is (= {:apiVersion "apps/v1", + :kind "Deployment", + :metadata {:name "test-de-deployment"}, + :spec + {:replicas 1, + :selector {:matchLabels {:app "test-de-nginx"}}, + :template + {:metadata {:labels {:app "test-de-nginx"}}, + :spec + {:containers + [{:name "test-de-nginx", + :image "nginx:latest", + :imagePullPolicy "IfNotPresent", + :ports [{:containerPort 80}], + :volumeMounts + [{:mountPath "/etc/nginx", :readOnly true, :name "nginx-config-volume"} + {:mountPath "/var/log/nginx", :name "log"} + {:mountPath "/var/www/html/website", :name "website-content-volume", :readOnly true} + {:mountPath "/etc/certs", :name "website-cert", :readOnly true}]}], + :volumes + [{:name "nginx-config-volume", + :configMap + {:name "test-de-configmap", + :items + [{:key "nginx.conf", :path "nginx.conf"} + {:key "website.conf", :path "conf.d/website.conf"} + {:key "mime.types", :path "mime.types"}]}} + {:name "log", :emptyDir {}} + {:name "website-content-volume", :persistentVolumeClaim {:claimName "test-de-content-volume"}} + {:name "website-cert", + :secret + {:secretName "test-de-cert", :items [{:key "tls.crt", :path "tls.crt"} {:key "tls.key", :path "tls.key"}]}}]}}}} + (cut/generate-nginx-deployment (cutc/set-single-fqdn + {:fqdn "test.io" + :fqdn1 "test.com" + :fqdn2 "test.de" + :single "fqdn2" + :multi ["fqdn1", "fqdn2"]}))))) + +(deftest should-generate-nginx-service (is (= {:name-c1 "test-de-service", :name-c2 "test-com-service", :app-c1 "test-de-nginx", - :app-c2 "test-com-nginx" - } - (th/map-diff (cut/generate-nginx-service {:fqdn "test.de"}) - (cut/generate-nginx-service {:fqdn "test.com"}))))) + :app-c2 "test-com-nginx"} + (th/map-diff (cut/generate-nginx-service (cutc/set-multi-fqdn {:fqdn "test.de" + :fqdn1 "bla.de" + :fqdn2 "bla.com" + :single "fqdn1" + :multi ["fqdn", "fqdn"]})) + (cut/generate-nginx-service (cutc/set-multi-fqdn {:fqdn "test.com" + :fqdn1 "bla.de" + :fqdn2 "bla.com" + :single "fqdn1" + :multi ["fqdn", "fqdn"]})))))) -(deftest should-generate-website-build-cron ;todo +(deftest should-generate-website-build-cron (is (= {:apiVersion "batch/v1beta1", :kind "CronJob", :metadata {:name "test-de-build-cron", :labels {:app.kubernetes.part-of "website"}}, @@ -108,7 +235,11 @@ :volumeMounts [{:name "content-volume", :mountPath "/var/www/html/website"}]}], :volumes [{:name "content-volume", :persistentVolumeClaim {:claimName "test-de-content-volume"}}], :restartPolicy "OnFailure"}}}}}} - (cut/generate-website-build-cron {:fqdn "test.de"})))) + (cut/generate-website-build-cron {:fqdn "test.de" + :fqdn1 "bla.de" + :fqdn2 "bla.com" + :single "fqdn1" + :multi ["fqdn1", "fqdn"]})))) (deftest should-generate-website-build-deployment (is (= {:apiVersion "apps/v1", @@ -131,7 +262,11 @@ :envFrom [{:secretRef {:name "test-de-secret"}}], :volumeMounts [{:name "content-volume", :mountPath "/var/www/html/website"}]}], :volumes [{:name "content-volume", :persistentVolumeClaim {:claimName "test-de-content-volume"}}]}}}} - (cut/generate-website-build-deployment {:fqdn "test.de"})))) + (cut/generate-website-build-deployment {:fqdn "test.de" + :fqdn1 "bla.de" + :fqdn2 "bla.com" + :single "fqdn1" + :multi ["fqdn1", "fqdn"]})))) (deftest should-generate-website-build-secret (is (= {:name-c1 "test-de-secret", @@ -140,17 +275,60 @@ :AUTHTOKEN-c2 (b64/encode "token2"), :GITREPOURL-c1 (b64/encode "test.de/user/repo.git"), :GITREPOURL-c2 (b64/encode "test.com/user/repo.git")} - (th/map-diff (cut/generate-website-build-secret {:fqdn "test.de" - :authtoken "token1" - :gitrepourl "test.de/user/repo.git"}) + (th/map-diff (cut/generate-website-build-secret {:fqdn "test.de" + :fqdn1 "bla.de" + :fqdn2 "bla.com" + :single "fqdn1" + :multi ["fqdn1", "fqdn"] + :authtoken "token1" + :gitrepourl "test.de/user/repo.git" + :singlegitrepourl "test.com/user/otherrepo.git"}) (cut/generate-website-build-secret {:fqdn "test.com" + :fqdn1 "bla.de" + :fqdn2 "bla.com" + :single "fqdn1" + :multi ["fqdn1", "fqdn"] :authtoken "token2" - :gitrepourl "test.com/user/repo.git"}))))) + :gitrepourl "test.com/user/repo.git" + :singlegitrepourl "test.com/user/otherrepo.git"}))))) +(deftest should-generate-website-build-secret-set-single + (is (= {:name-c1 "test-de-secret", + :name-c2 "test-com-secret", + :AUTHTOKEN-c1 (b64/encode "token1"), + :AUTHTOKEN-c2 (b64/encode "token2"), + :GITREPOURL-c1 (b64/encode "test.de/user/main.git"), + :GITREPOURL-c2 (b64/encode "test.com/user/master.git")} + (th/map-diff (cut/generate-website-build-secret (cutc/set-single-repo-url + {:fqdn "test.de" + :fqdn1 "bla.de" + :fqdn2 "bla.com" + :single "fqdn" + :multi ["fqdn", "fqdn"] + :authtoken "token1" + :gitrepourl "test.de/user/repo.git" + :singlegitrepourl "test.de/user/main.git"})) + (cut/generate-website-build-secret (cutc/set-single-repo-url + {:fqdn "test.com" + :fqdn1 "bla.de" + :fqdn2 "bla.com" + :single "fqdn" + :multi ["fqdn1", "fqdn"] + :authtoken "token2" + :gitrepourl "test.com/user/repo.git" + :singlegitrepourl "test.com/user/master.git"})))))) (deftest should-generate-website-content-volume (is (= {:name-c1 "test-de-content-volume", :name-c2 "test-com-content-volume", :app-c1 "test-de-nginx", :app-c2 "test-com-nginx"} - (th/map-diff (cut/generate-website-content-volume {:fqdn "test.de"}) - (cut/generate-website-content-volume {:fqdn "test.com"}))))) + (th/map-diff (cut/generate-website-content-volume {:fqdn "test.de" + :fqdn1 "bla.de" + :fqdn2 "bla.com" + :single "fqdn1" + :multi ["fqdn1", "fqdn"]}) + (cut/generate-website-content-volume {:fqdn "test.com" + :fqdn1 "bla.de" + :fqdn2 "bla.com" + :single "fqdn1" + :multi ["fqdn1", "fqdn"]}))))) diff --git a/valid-auth.edn b/valid-auth.edn index 0feaed6..efd6262 100644 --- a/valid-auth.edn +++ b/valid-auth.edn @@ -1,2 +1,3 @@ {:authtoken "asdfasdfe" - :gitrepourl "https://some.de/path/to/repo.zip"} + :gitrepourl "https://some.de/path/to/repo.zip" + :singlegitrepourl "https://someother.de/path/to/repo.zip"} diff --git a/valid-config.edn b/valid-config.edn index 18105d1..ddd65b7 100644 --- a/valid-config.edn +++ b/valid-config.edn @@ -1,5 +1,6 @@ -{:fqdn "repo.test.meissa.de" - :issuer "staging" - :volume-total-storage-size 20 - :number-of-websites 5 - } +{:fqdn "meissa.de" + :fqdn1 "meissa-gmbh.de" + :fqdn2 "domaindrivenarchitecture.org" + :multi ["fqdn", "fqdn1"] + :single "fqdn2" + :issuer "staging"} \ No newline at end of file