From d384ad7f7bbd38bd27ba55a9c44e2a7aa315fc98 Mon Sep 17 00:00:00 2001 From: bom Date: Fri, 27 Sep 2024 15:04:05 +0200 Subject: [PATCH 01/17] Add infra for using c4k --- deps.edn | 4 +- src/dda/build/c4k.clj | 65 +++++++++++++++++++++++++++++++++ src/dda/build/c4k/domain.clj | 71 ++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 src/dda/build/c4k.clj create mode 100644 src/dda/build/c4k/domain.clj diff --git a/deps.edn b/deps.edn index ed56f13..b6810a5 100644 --- a/deps.edn +++ b/deps.edn @@ -7,7 +7,9 @@ :deps {org.clojure/clojure {:mvn/version "1.11.4"} org.clojure/spec.alpha {:mvn/version "0.5.238"} - orchestra/orchestra {:mvn/version "2021.01.01-1"}} + orchestra/orchestra {:mvn/version "2021.01.01-1"} + org.domaindrivenarchitecture/c4k-common-clj {:mvn/version "8.0.1-SNAPSHOT"} + cheshire/cheshire {:mvn/version "5.13.0"}} :aliases { diff --git a/src/dda/build/c4k.clj b/src/dda/build/c4k.clj new file mode 100644 index 0000000..576bc5d --- /dev/null +++ b/src/dda/build/c4k.clj @@ -0,0 +1,65 @@ +(ns dda.build.c4k + (:require [orchestra.core :refer [defn-spec]] + [clojure.spec.test.alpha :as st] + [cheshire.core :refer [parse-string generate-string]] + [dda.build.devops :as d] + [dda.build.c4k.domain :as domain] + [dda.build.infrastructure :as i])) + +(st/instrument `clean-build-dir!) + +(def default + (merge d/default {:autoapply false + :c4k-output-filename "c4k-app.yaml" + :c4k-config-filename "c4k-config.yaml" + :c4k-auth-filename "c4k-auth.yaml"})) + +(defn-spec clean-build-dir! nil? + [devops ::d/devops] + (let [config (merge default devops)] + (i/execute! (domain/clean-build-dir-command config) config))) + +(defn-spec run-c4k-jar! nil? + [devops ::d/devops] + (let [config (merge default devops)] + (doseq [c (domain/c4k-uberjar-command config)] + (i/execute! c config)))) + +(defn-spec run-c4k-executable! nil? + [devops ::d/devops] + (let [config (merge default devops)] + (doseq [c (domain/c4k-graalvm-command config)] + (i/execute! c config)))) + +; TODO: Generate functions assume that files have already been copied, +; which will happen if this is run after terragrunt +; but it is not guaranteed +(defn-spec generate-jar! nil? + [devops ::d/devops] + (let [config (merge default devops)] + (run-c4k-jar! config))) + +(defn-spec generate! nil? + [devops ::d/devops] + (let [config (merge default devops)] + (run-c4k-executable! config))) + +(defn-spec insert-tf-out! nil? + [devops ::d/devops + tf-out ::domain/tf-out] + (let [config (merge default devops) + default-c4k-config (parse-string (slurp (domain/config-path config)) + (fn [k] (keyword (.toLowerCase k)))) + tf-out-c4k-config (domain/create-c4k-config config tf-out)] + (->> default-c4k-config + (merge tf-out-c4k-config) + (generate-string) + (spit (domain/config-path config))))) + + +(st/instrument `clean-build-dir!) +(st/instrument `run-c4k-jar!) +(st/instrument `run-c4k-executable!) +(st/instrument `generate-jar!) +(st/instrument `generate!) +(st/instrument `insert-tf-out!) diff --git a/src/dda/build/c4k/domain.clj b/src/dda/build/c4k/domain.clj new file mode 100644 index 0000000..28a1cc0 --- /dev/null +++ b/src/dda/build/c4k/domain.clj @@ -0,0 +1,71 @@ +(ns dda.build.c4k.domain + (:require [clojure.spec.alpha :as s] + [orchestra.core :refer [defn-spec]] + [dda.build.devops.domain :as d] + [dda.c4k-common.predicate :as pred])) + +(s/def ::c4k-output-filenname string?) +(s/def ::autoapply boolean?) + +(s/def ::sensitive boolean?) + +(s/def ::type vector?) + +(s/def ::fqdn pred/fqdn-string?) +(s/def ::ipv4 pred/ipv4-string?) +(s/def ::ipv6 pred/ipv6-string?) +(s/def ::value + (s/keys :req-un [::fqdn ::ipv4 ::ipv6])) + +(s/def ::out + (s/keys :req-un [::sensitive ::type ::value])) + +(s/def ::tf-out + (s/keys :req-un [::out])) + +(s/def ::c4k-config-filename string?) +(s/def ::c4k-auth-filename string?) + +(s/def ::config + (s/keys :req-un [::d/name ::d/stage ::d/project-root-path ::d/build-dir-name ::d/debug + ::d/dry-run ::d/module ::c4k-output-filenname ::autoapply ::c4k-config-filename ::c4k-auth-filename] + :opt-un [])) + +(defn-spec config-path string? + [config ::config] + (let [{:keys [c4k-config-filename]} config] + (str (d/build-path config) "/" c4k-config-filename))) + +(defn-spec auth-path string? + [config ::config] + (let [{:keys [c4k-auth-filename]} config] + (str (d/build-path config) "/" c4k-auth-filename))) + +(defn-spec output-path string? + [config ::config] + (let [{:keys [c4k-output-filename]} config] + (str (d/build-path config) "/" c4k-output-filename))) + +(defn-spec clean-build-dir-command seq? + [config ::config] + ["rm" "-rf" (d/build-path (dissoc config :module))]) + +(defn-spec c4k-uberjar-command seq? + [config ::config] + (let [{:keys [module]} config + executable-name (str "c4k-" module "-standalone.jar")] + [["bash" "-c" (str executable-name " " (config-path config) " " (auth-path config) " > " (output-path config))]])) + +(defn-spec c4k-graalvm-command seq? + [config ::config] + (let [{:keys [module]} config + executable-name (str "c4k-" module)] + [["bash" "-c" (str executable-name " " (config-path config) " " (auth-path config) " > " (output-path config))]])) + +(defn-spec create-c4k-config + [config ::config + tf-out ::tf-out] + (let [{:keys [stage]} config + issuer (if (= stage "prod") "prod" "staging") + fqdn (:fqdn (:value (:out tf-out)))] + {:issuer issuer :fqdn fqdn})) -- 2.45.2 From 3c7b60de2ebb9e895b2fb0cdd3bee85570388c66 Mon Sep 17 00:00:00 2001 From: bom Date: Fri, 27 Sep 2024 15:20:00 +0200 Subject: [PATCH 02/17] Add docstrings --- src/dda/build/c4k.clj | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/dda/build/c4k.clj b/src/dda/build/c4k.clj index 576bc5d..ac671d7 100644 --- a/src/dda/build/c4k.clj +++ b/src/dda/build/c4k.clj @@ -35,16 +35,33 @@ ; which will happen if this is run after terragrunt ; but it is not guaranteed (defn-spec generate-jar! nil? + "Generates c4k app yaml using 'c4k-{module}-standalone.jar' + Stores the result in 'c4k-app.yaml' + + Defaults: c4k-config.yaml c4k-auth.yaml c4k-app.yaml + can be changed by adding another value for ':c4k-config-filename', ':c4k-auth-filename', ':c4k-output-filename' + " [devops ::d/devops] (let [config (merge default devops)] (run-c4k-jar! config))) (defn-spec generate! nil? + "Generates c4k app yaml using 'c4k-{module}' (graalvm executable) + Stores the result in 'c4k-app.yaml' + + Defaults: c4k-config.yaml c4k-auth.yaml c4k-app.yaml + can be changed by adding another value for ':c4k-config-filename', ':c4k-auth-filename', ':c4k-output-filename' + " [devops ::d/devops] (let [config (merge default devops)] (run-c4k-executable! config))) (defn-spec insert-tf-out! nil? + "Inserts relevant values from the tf output into the c4k config + + Default: c4k-config.yaml + can be changed by adding another value for ':c4k-config-filename' + " [devops ::d/devops tf-out ::domain/tf-out] (let [config (merge default devops) -- 2.45.2 From bd2683b7224aba4848c86d90d957fe149eb0f3f2 Mon Sep 17 00:00:00 2001 From: bom Date: Fri, 27 Sep 2024 17:33:04 +0200 Subject: [PATCH 03/17] Add provs infra --- src/dda/build/c4k/domain.clj | 2 +- src/dda/build/provs.clj | 40 +++++++++++++++++++++++++ src/dda/build/provs/domain.clj | 53 ++++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 src/dda/build/provs.clj create mode 100644 src/dda/build/provs/domain.clj diff --git a/src/dda/build/c4k/domain.clj b/src/dda/build/c4k/domain.clj index 28a1cc0..21d249f 100644 --- a/src/dda/build/c4k/domain.clj +++ b/src/dda/build/c4k/domain.clj @@ -62,7 +62,7 @@ executable-name (str "c4k-" module)] [["bash" "-c" (str executable-name " " (config-path config) " " (auth-path config) " > " (output-path config))]])) -(defn-spec create-c4k-config +(defn-spec create-c4k-config map? [config ::config tf-out ::tf-out] (let [{:keys [stage]} config diff --git a/src/dda/build/provs.clj b/src/dda/build/provs.clj new file mode 100644 index 0000000..c8624c0 --- /dev/null +++ b/src/dda/build/provs.clj @@ -0,0 +1,40 @@ +(ns dda.build.provs + (:require [orchestra.core :refer [defn-spec]] + [clojure.spec.test.alpha :as st] + [cheshire.core :refer [generate-string]] + [dda.build.devops :as d] + [dda.build.provs.domain :as domain] + [dda.build.c4k.domain :as c4k-d] + [dda.build.infrastructure :as i])) + +(def default + (merge d/default {:k3s-output-filename "out_k3sServerConfig.yaml" + :k3s-provision-user "root" + :c4k-output-filename "c4k-app.yaml" + :email "default@email.rep" + :echo false})) + +(defn-spec run-provs-server! nil? + [devops ::d/devops + tf-out ::c4k-d/tf-out] + (let [config (merge default devops)] + (doseq [c (domain/provs-server-command config tf-out)] + (i/execute! c config)))) + +(defn-spec write-k3s-config! nil? + "Create a server config for provs using tf-out and write it to a file + + Requires ':email' to be set, otherwise certs will not work + Default: out_k3sServerConfig.yaml + can be changed by adding another value for ':k3s-output-filename' + " + [devops ::d/devops + tf-out ::c4k-d/tf-out] + (let [config (merge default devops) + tf-out-k3s-config (domain/create-k3s-config config tf-out)] + (->> tf-out-k3s-config + (generate-string) + (spit (domain/output-path config))))) + +(st/instrument `run-provs-server!) +(st/instrument `write-k3s-config!) \ No newline at end of file diff --git a/src/dda/build/provs/domain.clj b/src/dda/build/provs/domain.clj new file mode 100644 index 0000000..6d799db --- /dev/null +++ b/src/dda/build/provs/domain.clj @@ -0,0 +1,53 @@ +(ns dda.build.provs.domain + (:require [clojure.spec.alpha :as s] + [orchestra.core :refer [defn-spec]] + [dda.build.devops.domain :as d] + [dda.c4k-common.predicate :as pred] + [dda.build.c4k.domain :as c4k-d])) + +; TODO: Use a better spec for emails +; should be added to c4k-common, it seems common enough +(s/def ::email pred/bash-env-string?) +(s/def ::fqdn pred/fqdn-string?) +(s/def ::ipv4 pred/ipv4-string?) +(s/def ::ipv6 pred/ipv6-string?) +(s/def ::echo boolean?) +(s/def ::k3s-output-filename string?) +(s/def ::k3s-provision-user pred/bash-env-string?) +(s/def ::config + (s/keys :req-un [::d/name ::d/stage ::d/project-root-path ::d/build-dir-name ::d/debug + ::d/dry-run ::d/module ::c4k-d/c4k-output-filenname + ::email ::echo ::k3s-output-filename ::k3s-provision-user])) +(s/def ::node + (s/keys :req-un [::ipv4 ::ipv6])) +(s/def ::letsencryptEndpoint pred/letsencrypt-issuer?) +(s/def ::certmanager + (s/keys :req-un [::email ::letsencryptEndpoint])) +(s/def ::server-config + (s/keys :req-un [::fqdn ::node ::certmanager ::echo])) + +(defn-spec output-path string? + [config ::config] + (let [{:keys [k3s-output-filename]} config] + (str (d/build-path config) "/" k3s-output-filename))) + +(defn-spec provs-server-command seq? + [config ::config + tf-out ::c4k-d/tf-out] + (let [{:keys [k3s-output-filename k3s-provision-user]} config + fqdn (get-in tf-out [:out :value :fqdn])] + [["provs-server.jar" "k3s" (str k3s-provision-user "@" fqdn) "-c" (output-path config) "-a" (c4k-d/output-path config)]])) + +(defn-spec create-k3s-config map? + [config ::config + tf-out ::c4k-d/tf-out] + (let [{:keys [stage email echo]} config + letsencrypt-endpoint (if (= stage "prod") "prod" "staging") + values (:value (:out tf-out)) + {:keys [fqdn ipv4 ipv6]} values] + {:fqdn fqdn + :node {:ipv4 ipv4 + :ipv6 ipv6} + :certmanager {:email email + :letsencryptEndpoint letsencrypt-endpoint} + :echo echo})) -- 2.45.2 From aa8e44a901fed470b6708248847eba690915699b Mon Sep 17 00:00:00 2001 From: bom Date: Fri, 4 Oct 2024 16:17:08 +0200 Subject: [PATCH 04/17] Use name instead of module for executable names --- src/dda/build/c4k/domain.clj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/dda/build/c4k/domain.clj b/src/dda/build/c4k/domain.clj index 21d249f..9fa5c97 100644 --- a/src/dda/build/c4k/domain.clj +++ b/src/dda/build/c4k/domain.clj @@ -52,15 +52,15 @@ (defn-spec c4k-uberjar-command seq? [config ::config] - (let [{:keys [module]} config - executable-name (str "c4k-" module "-standalone.jar")] - [["bash" "-c" (str executable-name " " (config-path config) " " (auth-path config) " > " (output-path config))]])) + (let [{:keys [name]} config + executable-name (str "c4k-" name "-standalone.jar")] + ["bash" "-c" (str executable-name " " (config-path config) " " (auth-path config) " > " (output-path config))])) (defn-spec c4k-graalvm-command seq? [config ::config] - (let [{:keys [module]} config - executable-name (str "c4k-" module)] - [["bash" "-c" (str executable-name " " (config-path config) " " (auth-path config) " > " (output-path config))]])) + (let [{:keys [name]} config + executable-name (str "c4k-" name)] + ["bash" "-c" (str executable-name " " (config-path config) " " (auth-path config) " > " (output-path config))])) (defn-spec create-c4k-config map? [config ::config -- 2.45.2 From d164b558344898c7bed504cb7c3387efd450df89 Mon Sep 17 00:00:00 2001 From: bom Date: Fri, 4 Oct 2024 16:17:19 +0200 Subject: [PATCH 05/17] Add c4k domain tests --- test/dda/build/c4k/domain_test.clj | 112 +++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 test/dda/build/c4k/domain_test.clj diff --git a/test/dda/build/c4k/domain_test.clj b/test/dda/build/c4k/domain_test.clj new file mode 100644 index 0000000..7bb939d --- /dev/null +++ b/test/dda/build/c4k/domain_test.clj @@ -0,0 +1,112 @@ +(ns dda.build.c4k.domain-test + (:require + [clojure.test :refer [deftest is]] + [clojure.spec.test.alpha :as st] + [dda.build.c4k.domain :as cut])) + +(st/instrument `cut/build-path) +(st/instrument `cut/create-build-dir-command) + +(deftest should-calculate-config-path + (is (= "../../target/dda-backup/config.yaml" + (cut/config-path {:name "dda-backup" + :project-root-path "../.." + :build-dir-name "target" + :version "4.11.8-dev" + :stage "dev" + :debug false + :dry-run false + :c4k-config-filename "config.yaml"}))) + (is (= "../../target/dda/backup/config.yaml" + (cut/config-path {:name "dda" + :module "backup" + :project-root-path "../.." + :build-dir-name "target" + :version "4.11.8-dev" + :stage "dev" + :debug false + :dry-run false + :c4k-config-filename "config.yaml"})))) + +(deftest should-calculate-auth-path + (is (= "../../target/dda-backup/auth.yaml" + (cut/auth-path {:name "dda-backup" + :project-root-path "../.." + :build-dir-name "target" + :version "4.11.8-dev" + :stage "dev" + :debug false + :dry-run false + :c4k-auth-filename "auth.yaml"}))) + (is (= "../../target/dda/backup/auth.yaml" + (cut/auth-path {:name "dda" + :module "backup" + :project-root-path "../.." + :build-dir-name "target" + :version "4.11.8-dev" + :stage "dev" + :debug false + :dry-run false + :c4k-auth-filename "auth.yaml"})))) + + +(deftest should-calculate-output-path + (is (= "../../target/dda-backup/out.yaml" + (cut/output-path {:name "dda-backup" + :project-root-path "../.." + :build-dir-name "target" + :version "4.11.8-dev" + :stage "dev" + :debug false + :dry-run false + :c4k-output-filename "out.yaml"}))) + (is (= "../../target/dda/backup/out.yaml" + (cut/output-path {:name "dda" + :module "backup" + :project-root-path "../.." + :build-dir-name "target" + :version "4.11.8-dev" + :stage "dev" + :debug false + :dry-run false + :c4k-output-filename "out.yaml"})))) + +(deftest should-calculate-clean-build-dir-command + (is (= ["rm" "-rf" "../../target/dda-backup"] + (cut/clean-build-dir-command {:name "dda-backup" + :project-root-path "../.." + :build-dir-name "target" + :version "4.11.8-dev" + :stage "dev" + :debug false + :dry-run false + :c4k-config-filename "config.yaml" + :c4k-auth-filename "auth.yaml" + :c4k-output-filename "out.yaml"})))) + +(deftest should-calculate-c4k-uberjar-command + (is (= ["bash" "-c" "c4k-dda-backup-standalone.jar ../../target/dda-backup/config.yaml ../../target/dda-backup/auth.yaml > ../../target/dda-backup/out.yaml"] + (cut/c4k-uberjar-command {:name "dda-backup" + :project-root-path "../.." + :build-dir-name "target" + :version "4.11.8-dev" + :stage "dev" + :debug false + :dry-run false + :c4k-config-filename "config.yaml" + :c4k-auth-filename "auth.yaml" + :c4k-output-filename "out.yaml"})))) + +(deftest should-calculate-c4k-graalvm-command + (is (= ["bash" "-c" "c4k-dda-backup ../../target/dda-backup/config.yaml ../../target/dda-backup/auth.yaml > ../../target/dda-backup/out.yaml"] + (cut/c4k-graalvm-command {:name "dda-backup" + :project-root-path "../.." + :build-dir-name "target" + :version "4.11.8-dev" + :stage "dev" + :debug false + :dry-run false + :c4k-config-filename "config.yaml" + :c4k-auth-filename "auth.yaml" + :c4k-output-filename "out.yaml"})))) + -- 2.45.2 From b6814110cbde65c48a923944b31363200aed0d76 Mon Sep 17 00:00:00 2001 From: bom Date: Fri, 4 Oct 2024 16:21:02 +0200 Subject: [PATCH 06/17] Instrument & fix spec --- src/dda/build/c4k/domain.clj | 4 ++-- test/dda/build/c4k/domain_test.clj | 29 +++++++++++++++++++++++------ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/dda/build/c4k/domain.clj b/src/dda/build/c4k/domain.clj index 9fa5c97..445050a 100644 --- a/src/dda/build/c4k/domain.clj +++ b/src/dda/build/c4k/domain.clj @@ -4,7 +4,7 @@ [dda.build.devops.domain :as d] [dda.c4k-common.predicate :as pred])) -(s/def ::c4k-output-filenname string?) +(s/def ::c4k-output-filename string?) (s/def ::autoapply boolean?) (s/def ::sensitive boolean?) @@ -28,7 +28,7 @@ (s/def ::config (s/keys :req-un [::d/name ::d/stage ::d/project-root-path ::d/build-dir-name ::d/debug - ::d/dry-run ::d/module ::c4k-output-filenname ::autoapply ::c4k-config-filename ::c4k-auth-filename] + ::d/dry-run ::d/module ::c4k-output-filename ::autoapply ::c4k-config-filename ::c4k-auth-filename] :opt-un [])) (defn-spec config-path string? diff --git a/test/dda/build/c4k/domain_test.clj b/test/dda/build/c4k/domain_test.clj index 7bb939d..646a001 100644 --- a/test/dda/build/c4k/domain_test.clj +++ b/test/dda/build/c4k/domain_test.clj @@ -4,8 +4,13 @@ [clojure.spec.test.alpha :as st] [dda.build.c4k.domain :as cut])) -(st/instrument `cut/build-path) -(st/instrument `cut/create-build-dir-command) +(st/instrument `cut/config-path) +(st/instrument `cut/auth-path) +(st/instrument `cut/output-path) +(st/instrument `cut/clean-build-dir-command) +(st/instrument `cut/c4k-uberjar-command) +(st/instrument `cut/c4k-graalvm-command) +(st/instrument `cut/create-c4k-config) (deftest should-calculate-config-path (is (= "../../target/dda-backup/config.yaml" @@ -16,7 +21,9 @@ :stage "dev" :debug false :dry-run false - :c4k-config-filename "config.yaml"}))) + :c4k-config-filename "config.yaml" + :c4k-auth-filename "auth.yaml" + :c4k-output-filename "out.yaml"}))) (is (= "../../target/dda/backup/config.yaml" (cut/config-path {:name "dda" :module "backup" @@ -26,7 +33,9 @@ :stage "dev" :debug false :dry-run false - :c4k-config-filename "config.yaml"})))) + :c4k-config-filename "config.yaml" + :c4k-auth-filename "auth.yaml" + :c4k-output-filename "out.yaml"})))) (deftest should-calculate-auth-path (is (= "../../target/dda-backup/auth.yaml" @@ -37,7 +46,9 @@ :stage "dev" :debug false :dry-run false - :c4k-auth-filename "auth.yaml"}))) + :c4k-config-filename "config.yaml" + :c4k-auth-filename "auth.yaml" + :c4k-output-filename "out.yaml"}))) (is (= "../../target/dda/backup/auth.yaml" (cut/auth-path {:name "dda" :module "backup" @@ -47,7 +58,9 @@ :stage "dev" :debug false :dry-run false - :c4k-auth-filename "auth.yaml"})))) + :c4k-config-filename "config.yaml" + :c4k-auth-filename "auth.yaml" + :c4k-output-filename "out.yaml"})))) (deftest should-calculate-output-path @@ -59,6 +72,8 @@ :stage "dev" :debug false :dry-run false + :c4k-config-filename "config.yaml" + :c4k-auth-filename "auth.yaml" :c4k-output-filename "out.yaml"}))) (is (= "../../target/dda/backup/out.yaml" (cut/output-path {:name "dda" @@ -69,6 +84,8 @@ :stage "dev" :debug false :dry-run false + :c4k-config-filename "config.yaml" + :c4k-auth-filename "auth.yaml" :c4k-output-filename "out.yaml"})))) (deftest should-calculate-clean-build-dir-command -- 2.45.2 From f27d140a633b8a777da03ad1d1f21c0e76155eb8 Mon Sep 17 00:00:00 2001 From: bom Date: Fri, 4 Oct 2024 16:35:33 +0200 Subject: [PATCH 07/17] Add provs domain tests --- src/dda/build/provs/domain.clj | 7 ++-- test/dda/build/provs/domain_test.clj | 55 ++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 test/dda/build/provs/domain_test.clj diff --git a/src/dda/build/provs/domain.clj b/src/dda/build/provs/domain.clj index 6d799db..b14a73c 100644 --- a/src/dda/build/provs/domain.clj +++ b/src/dda/build/provs/domain.clj @@ -16,8 +16,9 @@ (s/def ::k3s-provision-user pred/bash-env-string?) (s/def ::config (s/keys :req-un [::d/name ::d/stage ::d/project-root-path ::d/build-dir-name ::d/debug - ::d/dry-run ::d/module ::c4k-d/c4k-output-filenname - ::email ::echo ::k3s-output-filename ::k3s-provision-user])) + ::d/dry-run ::c4k-d/c4k-output-filename + ::email ::echo ::k3s-output-filename ::k3s-provision-user] + :opt-un [::d/module])) (s/def ::node (s/keys :req-un [::ipv4 ::ipv6])) (s/def ::letsencryptEndpoint pred/letsencrypt-issuer?) @@ -36,7 +37,7 @@ tf-out ::c4k-d/tf-out] (let [{:keys [k3s-output-filename k3s-provision-user]} config fqdn (get-in tf-out [:out :value :fqdn])] - [["provs-server.jar" "k3s" (str k3s-provision-user "@" fqdn) "-c" (output-path config) "-a" (c4k-d/output-path config)]])) + ["provs-server.jar" "k3s" (str k3s-provision-user "@" fqdn) "-c" (output-path config) "-a" (c4k-d/output-path config)])) (defn-spec create-k3s-config map? [config ::config diff --git a/test/dda/build/provs/domain_test.clj b/test/dda/build/provs/domain_test.clj new file mode 100644 index 0000000..67c5162 --- /dev/null +++ b/test/dda/build/provs/domain_test.clj @@ -0,0 +1,55 @@ +(ns dda.build.provs.domain-test + (:require + [clojure.test :refer [deftest is]] + [clojure.spec.test.alpha :as st] + [dda.build.provs.domain :as cut])) + +(st/instrument `cut/output-path) +(st/instrument `cut/provs-server-command) +(st/instrument `cut/create-k3s-config) + +(deftest should-calculate-output-path + (is (= "../../target/dda-backup/k3s-out.yaml" + (cut/output-path {:name "dda-backup" + :project-root-path "../.." + :build-dir-name "target" + :version "4.11.8-dev" + :stage "dev" + :debug false + :dry-run false + :c4k-output-filename "out.yaml" + :k3s-provision-user "root" + :k3s-output-filename "k3s-out.yaml" + :email "test@test.t" + :echo false}))) + (is (= "../../target/dda/backup/k3s-out.yaml" + (cut/output-path {:name "dda" + :module "backup" + :project-root-path "../.." + :build-dir-name "target" + :version "4.11.8-dev" + :stage "dev" + :debug false + :dry-run false + :c4k-output-filename "out.yaml" + :k3s-provision-user "root" + :k3s-output-filename "k3s-out.yaml" + :email "test@test.t" + :echo false})))) + +(deftest should-calculate-provs-server-command + (is (= ["provs-server.jar" "k3s" "root@test.test.de" "-c" "../../target/dda-backup/k3s-out.yaml" "-a" "../../target/dda-backup/out.yaml"] + (cut/provs-server-command {:name "dda-backup" + :project-root-path "../.." + :build-dir-name "target" + :version "4.11.8-dev" + :stage "dev" + :debug false + :dry-run false + :k3s-output-filename "k3s-out.yaml" + :k3s-provision-user "root" + :c4k-output-filename "out.yaml" + :email "test@test.t" + :echo false} + {:out {:sensitive false :type [] :value {:fqdn "test.test.de" :ipv4 "127.0.0.1" :ipv6 "::"}}})))) + -- 2.45.2 From 609358b057a734d7f638d335edc0b28536662eac Mon Sep 17 00:00:00 2001 From: bom Date: Fri, 4 Oct 2024 16:44:59 +0200 Subject: [PATCH 08/17] Move tf-out spec to terragrunt --- src/dda/build/c4k/domain.clj | 25 ++++--------------------- src/dda/build/provs/domain.clj | 7 ++++--- src/dda/build/terragrunt/domain.clj | 19 ++++++++++++++++++- test/dda/build/provs/domain_test.clj | 2 ++ 4 files changed, 28 insertions(+), 25 deletions(-) diff --git a/src/dda/build/c4k/domain.clj b/src/dda/build/c4k/domain.clj index 445050a..583d3c3 100644 --- a/src/dda/build/c4k/domain.clj +++ b/src/dda/build/c4k/domain.clj @@ -2,34 +2,17 @@ (:require [clojure.spec.alpha :as s] [orchestra.core :refer [defn-spec]] [dda.build.devops.domain :as d] - [dda.c4k-common.predicate :as pred])) + [dda.build.terragrunt.domain :as td])) (s/def ::c4k-output-filename string?) -(s/def ::autoapply boolean?) - -(s/def ::sensitive boolean?) - -(s/def ::type vector?) - -(s/def ::fqdn pred/fqdn-string?) -(s/def ::ipv4 pred/ipv4-string?) -(s/def ::ipv6 pred/ipv6-string?) -(s/def ::value - (s/keys :req-un [::fqdn ::ipv4 ::ipv6])) - -(s/def ::out - (s/keys :req-un [::sensitive ::type ::value])) - -(s/def ::tf-out - (s/keys :req-un [::out])) (s/def ::c4k-config-filename string?) (s/def ::c4k-auth-filename string?) (s/def ::config (s/keys :req-un [::d/name ::d/stage ::d/project-root-path ::d/build-dir-name ::d/debug - ::d/dry-run ::d/module ::c4k-output-filename ::autoapply ::c4k-config-filename ::c4k-auth-filename] - :opt-un [])) + ::d/dry-run ::c4k-output-filename ::c4k-config-filename ::c4k-auth-filename] + :opt-un [::d/module])) (defn-spec config-path string? [config ::config] @@ -64,7 +47,7 @@ (defn-spec create-c4k-config map? [config ::config - tf-out ::tf-out] + tf-out ::td/tf-out] (let [{:keys [stage]} config issuer (if (= stage "prod") "prod" "staging") fqdn (:fqdn (:value (:out tf-out)))] diff --git a/src/dda/build/provs/domain.clj b/src/dda/build/provs/domain.clj index b14a73c..4cd1e39 100644 --- a/src/dda/build/provs/domain.clj +++ b/src/dda/build/provs/domain.clj @@ -3,7 +3,8 @@ [orchestra.core :refer [defn-spec]] [dda.build.devops.domain :as d] [dda.c4k-common.predicate :as pred] - [dda.build.c4k.domain :as c4k-d])) + [dda.build.c4k.domain :as c4k-d] + [dda.build.terragrunt.domain :as td])) ; TODO: Use a better spec for emails ; should be added to c4k-common, it seems common enough @@ -34,14 +35,14 @@ (defn-spec provs-server-command seq? [config ::config - tf-out ::c4k-d/tf-out] + tf-out ::td/tf-out] (let [{:keys [k3s-output-filename k3s-provision-user]} config fqdn (get-in tf-out [:out :value :fqdn])] ["provs-server.jar" "k3s" (str k3s-provision-user "@" fqdn) "-c" (output-path config) "-a" (c4k-d/output-path config)])) (defn-spec create-k3s-config map? [config ::config - tf-out ::c4k-d/tf-out] + tf-out ::td/tf-out] (let [{:keys [stage email echo]} config letsencrypt-endpoint (if (= stage "prod") "prod" "staging") values (:value (:out tf-out)) diff --git a/src/dda/build/terragrunt/domain.clj b/src/dda/build/terragrunt/domain.clj index 48e8665..b2ec251 100644 --- a/src/dda/build/terragrunt/domain.clj +++ b/src/dda/build/terragrunt/domain.clj @@ -1,7 +1,24 @@ (ns dda.build.terragrunt.domain (:require [clojure.spec.alpha :as s] [orchestra.core :refer [defn-spec]] - [dda.build.devops.domain :as d])) + [dda.build.devops.domain :as d] + [dda.c4k-common.predicate :as pred])) + +(s/def ::sensitive boolean?) + +(s/def ::type vector?) + +(s/def ::fqdn pred/fqdn-string?) +(s/def ::ipv4 pred/ipv4-string?) +(s/def ::ipv6 pred/ipv6-string?) +(s/def ::value + (s/keys :req-un [::fqdn ::ipv4 ::ipv6])) + +(s/def ::out + (s/keys :req-un [::sensitive ::type ::value])) + +(s/def ::tf-out + (s/keys :req-un [::out])) (s/def ::tg-output-filenname string?) (s/def ::autoapply boolean?) diff --git a/test/dda/build/provs/domain_test.clj b/test/dda/build/provs/domain_test.clj index 67c5162..5b23684 100644 --- a/test/dda/build/provs/domain_test.clj +++ b/test/dda/build/provs/domain_test.clj @@ -48,6 +48,8 @@ :dry-run false :k3s-output-filename "k3s-out.yaml" :k3s-provision-user "root" + :c4k-config-filename "config.yaml" + :c4k-auth-filename "auth.yaml" :c4k-output-filename "out.yaml" :email "test@test.t" :echo false} -- 2.45.2 From e9011773e7f53d0b52c84047c717d057a8461f90 Mon Sep 17 00:00:00 2001 From: Michael Jerger Date: Fri, 4 Oct 2024 17:23:02 +0200 Subject: [PATCH 09/17] access to env --- src/dda/build/devops.clj | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/dda/build/devops.clj b/src/dda/build/devops.clj index 8287f23..994ff6e 100644 --- a/src/dda/build/devops.clj +++ b/src/dda/build/devops.clj @@ -22,6 +22,16 @@ :debug false :dry-run false}) +(defn-spec env-or-file string? + [name string?] + (let [from-env (System/getenv name) + name-from-file (System/getenv (str name "_FILE"))] + (cond + (some? from-env) from-env + (some? name-from-file) (slurp name-from-file) + :else (throw (RuntimeException. + (str "Environment: [" name "," name-from-file "] was missing.")))))) + (defn-spec clean-build-dir! nil? [devops ::devops] (let [final (merge default devops)] -- 2.45.2 From a4f1e69808f62c7c37642d19f3e31c95d3887e8e Mon Sep 17 00:00:00 2001 From: bom Date: Fri, 11 Oct 2024 12:43:58 +0200 Subject: [PATCH 10/17] Implement commands with outputs Expand infrastructure so we can read output from commands --- src/dda/build/infrastructure.clj | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/dda/build/infrastructure.clj b/src/dda/build/infrastructure.clj index 0adfd8d..20cec30 100644 --- a/src/dda/build/infrastructure.clj +++ b/src/dda/build/infrastructure.clj @@ -11,3 +11,15 @@ (println command)) (when-not dry-run (apply t/shell command)))) + +(defn-spec execute-output! string? + [command seq? + devops ::d/devops] + (let [{:keys [dry-run debug]} devops] + (when debug + (println command)) + (when-not dry-run + (->> command + (t/shell {:out :string}) + :out + clojure.string/trim)))) \ No newline at end of file -- 2.45.2 From 8f8f0d643a24ed7450addfe70a39361040f6ceb4 Mon Sep 17 00:00:00 2001 From: bom Date: Fri, 11 Oct 2024 13:14:22 +0200 Subject: [PATCH 11/17] Implement gopass infrastructure --- src/dda/build/gopass.clj | 51 +++++++++++++++++++++++++++ src/dda/build/gopass/domain.clj | 21 +++++++++++ test/dda/build/gopass/domain_test.clj | 13 +++++++ 3 files changed, 85 insertions(+) create mode 100644 src/dda/build/gopass.clj create mode 100644 src/dda/build/gopass/domain.clj create mode 100644 test/dda/build/gopass/domain_test.clj diff --git a/src/dda/build/gopass.clj b/src/dda/build/gopass.clj new file mode 100644 index 0000000..d5871cb --- /dev/null +++ b/src/dda/build/gopass.clj @@ -0,0 +1,51 @@ +(ns dda.build.gopass + (:require [orchestra.core :refer [defn-spec]] + [clojure.spec.test.alpha :as st] + [cheshire.core :refer [parse-string generate-string]] + [dda.build.devops :as d] + [dda.build.gopass.domain :as domain] + [dda.build.c4k.domain :as c4k-d] + [dda.build.infrastructure :as i])) + +(def default + (merge d/default {:c4k-auth-filename "c4k-auth.yaml"})) + +(defn-spec run-gopass-command! string? + [devops ::d/devops + entry ::domain/gopass-entry] + (let [config (merge default devops) + c (domain/gopass-show-command entry)] + (i/execute-output! c config))) + +(defn-spec resolve-gopass! ::resolved-config + "Resolves gopass values inside a map of key names and entries + + entries may either contain only a path + {:path \"test/path\"} + or a path and a field + {:path \"test/path\" :field \"field\"} + " + [devops ::d/devops + config ::domain/config] + (update-vals config #(run-gopass-command! devops %))) + +(defn-spec insert-gopass! nil? + "Inserts values from the resolved auth config into the c4k auth + + Default: c4k-auth.yaml + can be changed by adding another value for ':c4k-auth-filename' + " + [devops ::d/devops + resolved-config ::resolved-config] + (let [config (merge default devops) + default-c4k-auth (parse-string (slurp (c4k-d/auth-path config)) + (fn [k] (keyword (.toLowerCase k))))] + (->> default-c4k-auth + (merge resolved-config) + (generate-string) + (spit (domain/config-path config))))) + + +(st/instrument `run-gopass-command!) +(st/instrument `resolve-gopass!) +(st/instrument `insert-gopass!) diff --git a/src/dda/build/gopass/domain.clj b/src/dda/build/gopass/domain.clj new file mode 100644 index 0000000..0486a3b --- /dev/null +++ b/src/dda/build/gopass/domain.clj @@ -0,0 +1,21 @@ +(ns dda.build.gopass.domain + (:require [clojure.spec.alpha :as s] + [orchestra.core :refer [defn-spec]])) + +(s/def ::path string?) +(s/def ::field string?) +(s/def ::gopass-entry (s/keys :req-un [::path] + :opt-un [::field])) +(s/def ::config (s/map-of keyword? ::gopass-entry)) + +(s/def ::resolved-config (s/map-of keyword? string?)) + +(s/def ::gopass-command (s/coll-of string?)) +(s/def ::gopass-commands (s/coll-of ::gopass-command)) + +(defn-spec gopass-show-command ::gopass-command + [entry ::gopass-entry] + (let [{:keys [path field] :or {field nil}} entry] + (if (nil? field) + ["gopass" "show" "-y" "-o" path] + ["gopass" "show" "-y" "-o" path field]))) diff --git a/test/dda/build/gopass/domain_test.clj b/test/dda/build/gopass/domain_test.clj new file mode 100644 index 0000000..e16294a --- /dev/null +++ b/test/dda/build/gopass/domain_test.clj @@ -0,0 +1,13 @@ +(ns dda.build.gopass.domain-test + (:require + [clojure.test :refer [deftest is]] + [clojure.spec.test.alpha :as st] + [dda.build.gopass.domain :as cut])) + +(st/instrument `cut/gopass-show-command) + +(deftest should-show-gopass-command + (is (= ["gopass" "show" "-y" "-o" "test/pass"] + (cut/gopass-show-command {:path "test/pass"}))) + (is (= ["gopass" "show" "-y" "-o" "test/pass" "field"] + (cut/gopass-show-command {:path "test/pass" :field "field"})))) -- 2.45.2 From 87131fa50ff5d345989d7aca111e923b9d415cd9 Mon Sep 17 00:00:00 2001 From: bom Date: Fri, 11 Oct 2024 13:29:08 +0200 Subject: [PATCH 12/17] Use correct spec path in c4k --- src/dda/build/c4k.clj | 3 ++- src/dda/build/c4k/domain.clj | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dda/build/c4k.clj b/src/dda/build/c4k.clj index ac671d7..4506341 100644 --- a/src/dda/build/c4k.clj +++ b/src/dda/build/c4k.clj @@ -4,6 +4,7 @@ [cheshire.core :refer [parse-string generate-string]] [dda.build.devops :as d] [dda.build.c4k.domain :as domain] + [dda.build.terragrunt.domain :as tg-domain] [dda.build.infrastructure :as i])) (st/instrument `clean-build-dir!) @@ -63,7 +64,7 @@ can be changed by adding another value for ':c4k-config-filename' " [devops ::d/devops - tf-out ::domain/tf-out] + tf-out ::tg-domain/tf-out] (let [config (merge default devops) default-c4k-config (parse-string (slurp (domain/config-path config)) (fn [k] (keyword (.toLowerCase k)))) diff --git a/src/dda/build/c4k/domain.clj b/src/dda/build/c4k/domain.clj index 583d3c3..2e94e51 100644 --- a/src/dda/build/c4k/domain.clj +++ b/src/dda/build/c4k/domain.clj @@ -5,7 +5,6 @@ [dda.build.terragrunt.domain :as td])) (s/def ::c4k-output-filename string?) - (s/def ::c4k-config-filename string?) (s/def ::c4k-auth-filename string?) -- 2.45.2 From 0620c229c218ac17e03311481d7016be8ae05678 Mon Sep 17 00:00:00 2001 From: bom Date: Fri, 11 Oct 2024 13:29:53 +0200 Subject: [PATCH 13/17] Use correct spec path in gopass --- src/dda/build/gopass.clj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dda/build/gopass.clj b/src/dda/build/gopass.clj index d5871cb..6929604 100644 --- a/src/dda/build/gopass.clj +++ b/src/dda/build/gopass.clj @@ -17,7 +17,7 @@ c (domain/gopass-show-command entry)] (i/execute-output! c config))) -(defn-spec resolve-gopass! ::resolved-config +(defn-spec resolve-gopass! ::domain/resolved-config "Resolves gopass values inside a map of key names and entries entries may either contain only a path @@ -36,7 +36,7 @@ can be changed by adding another value for ':c4k-auth-filename' " [devops ::d/devops - resolved-config ::resolved-config] + resolved-config ::domain/resolved-config] (let [config (merge default devops) default-c4k-auth (parse-string (slurp (c4k-d/auth-path config)) (fn [k] (keyword (.toLowerCase k))))] -- 2.45.2 From 0b2ac0d289a0394cfe2d58ff7d6c6f32d144e08a Mon Sep 17 00:00:00 2001 From: bom Date: Fri, 11 Oct 2024 13:32:38 +0200 Subject: [PATCH 14/17] Fix call --- src/dda/build/gopass.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dda/build/gopass.clj b/src/dda/build/gopass.clj index 6929604..f4a6a8a 100644 --- a/src/dda/build/gopass.clj +++ b/src/dda/build/gopass.clj @@ -43,7 +43,7 @@ (->> default-c4k-auth (merge resolved-config) (generate-string) - (spit (domain/config-path config))))) + (spit (c4k-d/auth-path config))))) (st/instrument `run-gopass-command!) -- 2.45.2 From 06617d788164c66d058aa774c3e49c1b16db513f Mon Sep 17 00:00:00 2001 From: bom Date: Fri, 11 Oct 2024 13:38:22 +0200 Subject: [PATCH 15/17] Use correct spec path in provs --- src/dda/build/provs.clj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dda/build/provs.clj b/src/dda/build/provs.clj index c8624c0..840a000 100644 --- a/src/dda/build/provs.clj +++ b/src/dda/build/provs.clj @@ -4,7 +4,7 @@ [cheshire.core :refer [generate-string]] [dda.build.devops :as d] [dda.build.provs.domain :as domain] - [dda.build.c4k.domain :as c4k-d] + [dda.build.terragrunt.domain :as td] [dda.build.infrastructure :as i])) (def default @@ -16,7 +16,7 @@ (defn-spec run-provs-server! nil? [devops ::d/devops - tf-out ::c4k-d/tf-out] + tf-out ::td/tf-out] (let [config (merge default devops)] (doseq [c (domain/provs-server-command config tf-out)] (i/execute! c config)))) @@ -29,7 +29,7 @@ can be changed by adding another value for ':k3s-output-filename' " [devops ::d/devops - tf-out ::c4k-d/tf-out] + tf-out ::td/tf-out] (let [config (merge default devops) tf-out-k3s-config (domain/create-k3s-config config tf-out)] (->> tf-out-k3s-config -- 2.45.2 From b8eb32283f43f1a4c46caf8835e7dd7b41a1293c Mon Sep 17 00:00:00 2001 From: bom Date: Fri, 11 Oct 2024 15:01:20 +0200 Subject: [PATCH 16/17] Fix gopass & infra --- src/dda/build/gopass.clj | 2 +- src/dda/build/gopass/domain.clj | 2 +- src/dda/build/infrastructure.clj | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/dda/build/gopass.clj b/src/dda/build/gopass.clj index f4a6a8a..daf2030 100644 --- a/src/dda/build/gopass.clj +++ b/src/dda/build/gopass.clj @@ -27,7 +27,7 @@ " [devops ::d/devops config ::domain/config] - (update-vals config #(run-gopass-command! devops %))) + (apply merge (for [[k v] config] {(name k) (run-gopass-command! devops v)}))) (defn-spec insert-gopass! nil? "Inserts values from the resolved auth config into the c4k auth diff --git a/src/dda/build/gopass/domain.clj b/src/dda/build/gopass/domain.clj index 0486a3b..e78fbd8 100644 --- a/src/dda/build/gopass/domain.clj +++ b/src/dda/build/gopass/domain.clj @@ -8,7 +8,7 @@ :opt-un [::field])) (s/def ::config (s/map-of keyword? ::gopass-entry)) -(s/def ::resolved-config (s/map-of keyword? string?)) +(s/def ::resolved-config (s/map-of string? string?)) (s/def ::gopass-command (s/coll-of string?)) (s/def ::gopass-commands (s/coll-of ::gopass-command)) diff --git a/src/dda/build/infrastructure.clj b/src/dda/build/infrastructure.clj index 20cec30..e684fb2 100644 --- a/src/dda/build/infrastructure.clj +++ b/src/dda/build/infrastructure.clj @@ -19,7 +19,6 @@ (when debug (println command)) (when-not dry-run - (->> command - (t/shell {:out :string}) + (->> (t/shell command {:out :string}) :out clojure.string/trim)))) \ No newline at end of file -- 2.45.2 From 91ad092b1f9c7519d1099c3b706d01baf56ae5a4 Mon Sep 17 00:00:00 2001 From: bom Date: Fri, 11 Oct 2024 15:18:55 +0200 Subject: [PATCH 17/17] Fix command functions --- src/dda/build/c4k/domain.clj | 12 ++++++------ src/dda/build/provs/domain.clj | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/dda/build/c4k/domain.clj b/src/dda/build/c4k/domain.clj index 2e94e51..190a1d3 100644 --- a/src/dda/build/c4k/domain.clj +++ b/src/dda/build/c4k/domain.clj @@ -34,15 +34,15 @@ (defn-spec c4k-uberjar-command seq? [config ::config] - (let [{:keys [name]} config - executable-name (str "c4k-" name "-standalone.jar")] - ["bash" "-c" (str executable-name " " (config-path config) " " (auth-path config) " > " (output-path config))])) + (let [{:keys [module]} config + executable-name (str "c4k-" module "-standalone.jar")] + [["bash" "-c" (str executable-name " " (config-path config) " " (auth-path config) " > " (output-path config))]])) (defn-spec c4k-graalvm-command seq? [config ::config] - (let [{:keys [name]} config - executable-name (str "c4k-" name)] - ["bash" "-c" (str executable-name " " (config-path config) " " (auth-path config) " > " (output-path config))])) + (let [{:keys [module]} config + executable-name (str "c4k-" module)] + [["bash" "-c" (str executable-name " " (config-path config) " " (auth-path config) " > " (output-path config))]])) (defn-spec create-c4k-config map? [config ::config diff --git a/src/dda/build/provs/domain.clj b/src/dda/build/provs/domain.clj index 4cd1e39..77cdd37 100644 --- a/src/dda/build/provs/domain.clj +++ b/src/dda/build/provs/domain.clj @@ -38,7 +38,7 @@ tf-out ::td/tf-out] (let [{:keys [k3s-output-filename k3s-provision-user]} config fqdn (get-in tf-out [:out :value :fqdn])] - ["provs-server.jar" "k3s" (str k3s-provision-user "@" fqdn) "-c" (output-path config) "-a" (c4k-d/output-path config)])) + [["provs-server.jar" "k3s" (str k3s-provision-user "@" fqdn) "-c" (output-path config) "-a" (c4k-d/output-path config)]])) (defn-spec create-k3s-config map? [config ::config -- 2.45.2