Update to allow 1:N resource generators if the default fn specifies such
This commit is contained in:
@@ -1,12 +1,14 @@
|
|||||||
(ns utils.stack-processor
|
(ns utils.stack-processor
|
||||||
(:require
|
(:require
|
||||||
["@pulumi/kubernetes" :as k8s]
|
["@pulumi/kubernetes" :as k8s]
|
||||||
|
["@local/crds/gateway" :as gateway-api]
|
||||||
|
["@local/crds/cert_manager" :as cert-manager]
|
||||||
["@pulumi/pulumi" :as pulumi]
|
["@pulumi/pulumi" :as pulumi]
|
||||||
["@pulumi/vault" :as vault]
|
["@pulumi/vault" :as vault]
|
||||||
["@pulumiverse/harbor" :as harbor]
|
["@pulumiverse/harbor" :as harbor]
|
||||||
[utils.defaults :as default]
|
[utils.defaults :as default]
|
||||||
[utils.vault :as vault-utils]
|
[utils.vault :as vault-utils]
|
||||||
[utils.general :refer [deep-merge new-resource component-factory resource-factory deploy-stack-factory iterate-stack]]
|
[utils.general :refer [deep-merge new-resource create-expander resource-factory deploy-stack-factory iterate-stack]]
|
||||||
["@pulumi/docker" :as docker]
|
["@pulumi/docker" :as docker]
|
||||||
["@pulumi/docker-build" :as docker-build]
|
["@pulumi/docker-build" :as docker-build]
|
||||||
[clojure.walk :as walk]
|
[clojure.walk :as walk]
|
||||||
@@ -15,8 +17,9 @@
|
|||||||
[configs :refer [cfg]]
|
[configs :refer [cfg]]
|
||||||
[utils.k8s :as k8s-utils]
|
[utils.k8s :as k8s-utils]
|
||||||
[utils.harbor :as harbor-utils]
|
[utils.harbor :as harbor-utils]
|
||||||
[utils.docker :as docker-utils])
|
[utils.docker :as docker-utils]
|
||||||
(:require-macros [utils.general :refer [build-registry]]))
|
[utils.safe-fns :refer [safe-fns]])
|
||||||
|
(:require-macros [utils.general :refer [p-> build-registry]]))
|
||||||
|
|
||||||
|
|
||||||
#_(def component-specs-defs
|
#_(def component-specs-defs
|
||||||
@@ -26,15 +29,32 @@
|
|||||||
|
|
||||||
#_(def component-specs (build-registry component-specs-defs))
|
#_(def component-specs (build-registry component-specs-defs))
|
||||||
|
|
||||||
(defn make-paths [& path-groups]
|
|
||||||
(mapcat (fn [{:keys [paths backend]}]
|
|
||||||
(mapv (fn [p]
|
|
||||||
{:path p
|
|
||||||
:pathType "Prefix"
|
|
||||||
:backend {:service backend}})
|
|
||||||
paths))
|
|
||||||
path-groups))
|
|
||||||
|
|
||||||
|
;; We should move this to a list of safe-fns that extend the below inherently. That way we don't bloat this file.
|
||||||
|
(defn make-listeners [domains-or-json]
|
||||||
|
(let [domains (if (string? domains-or-json)
|
||||||
|
(js->clj (js/JSON.parse domains-or-json))
|
||||||
|
domains-or-json)]
|
||||||
|
(vec
|
||||||
|
(mapcat
|
||||||
|
(fn [domain]
|
||||||
|
(let [clean-name (clojure.string/replace domain #"\." "-")
|
||||||
|
secret-name (str clean-name "-tls")]
|
||||||
|
|
||||||
|
[{:name (str "https-root-" clean-name)
|
||||||
|
:port 443
|
||||||
|
:protocol "HTTPS"
|
||||||
|
:hostname domain
|
||||||
|
:tls {:mode "Terminate"
|
||||||
|
:certificateRefs [{:name secret-name}]}}
|
||||||
|
|
||||||
|
{:name (str "https-wild-" clean-name)
|
||||||
|
:port 443
|
||||||
|
:protocol "HTTPS"
|
||||||
|
:hostname (str "*." domain)
|
||||||
|
:tls {:mode "Terminate"
|
||||||
|
:certificateRefs [{:name secret-name}]}}]))
|
||||||
|
domains))))
|
||||||
|
|
||||||
(defn safe-parse-int [s]
|
(defn safe-parse-int [s]
|
||||||
(let [n (js/parseInt s 10)]
|
(let [n (js/parseInt s 10)]
|
||||||
@@ -49,12 +69,6 @@
|
|||||||
(safe-parse-int v)
|
(safe-parse-int v)
|
||||||
v))
|
v))
|
||||||
|
|
||||||
;; Whitelist functions for resolving templates. Intended to be extended.
|
|
||||||
(def ^:private safe-fns
|
|
||||||
{'str str
|
|
||||||
'b64e (fn [s] (-> (.from js/Buffer s) (.toString "base64")))
|
|
||||||
'println #(js/console.log %)
|
|
||||||
'make-paths make-paths})
|
|
||||||
|
|
||||||
(defn- is-output? [x] (some? (.-__pulumiOutput x)))
|
(defn- is-output? [x] (some? (.-__pulumiOutput x)))
|
||||||
|
|
||||||
@@ -128,7 +142,7 @@
|
|||||||
:k8s:secret {:constructor (.. k8s -core -v1 -Secret)
|
:k8s:secret {:constructor (.. k8s -core -v1 -Secret)
|
||||||
:provider-key :k8s
|
:provider-key :k8s
|
||||||
:defaults-fn (fn [env] ((get-in default/defaults [:k8s :secret]) (:options env)))}
|
:defaults-fn (fn [env] ((get-in default/defaults [:k8s :secret]) (:options env)))}
|
||||||
|
|
||||||
:k8s:config-map {:constructor (.. k8s -core -v1 -ConfigMap)
|
:k8s:config-map {:constructor (.. k8s -core -v1 -ConfigMap)
|
||||||
:provider-key :k8s
|
:provider-key :k8s
|
||||||
:defaults-fn (fn [env] ((get-in default/defaults [:k8s :config-map]) (:options env)))}
|
:defaults-fn (fn [env] ((get-in default/defaults [:k8s :config-map]) (:options env)))}
|
||||||
@@ -147,13 +161,46 @@
|
|||||||
|
|
||||||
:k8s:chart {:constructor (.. k8s -helm -v3 -Chart)
|
:k8s:chart {:constructor (.. k8s -helm -v3 -Chart)
|
||||||
:provider-key :k8s
|
:provider-key :k8s
|
||||||
:defaults-fn (fn [env]
|
:defaults-fn (fn [env]
|
||||||
(deep-merge ((get-in default/defaults [:k8s :chart]) (:options env))
|
(deep-merge ((get-in default/defaults [:k8s :chart]) (:options env))
|
||||||
(update-in (get-in (:options env) [:k8s:chart-opts]) [:values]
|
(update-in (get-in (:options env) [:k8s:chart-opts]) [:values]
|
||||||
#(deep-merge % (or (:yaml-values (:options env)) {})))))}
|
#(deep-merge % (or (:yaml-values (:options env)) {})))))}
|
||||||
:k8s:storage-class {:constructor (.. k8s -storage -v1 -StorageClass)
|
:k8s:storage-class {:constructor (.. k8s -storage -v1 -StorageClass)
|
||||||
|
:provider-key :k8s
|
||||||
|
:defaults-fn (fn [env] ((get-in default/defaults [:k8s :storage-class]) (:options env)))}
|
||||||
|
|
||||||
|
:k8s:gateway {:constructor (.. gateway-api -v1 -Gateway)
|
||||||
|
:provider-key :k8s
|
||||||
|
:defaults-fn (fn [env] ((get-in default/defaults [:k8s :gateway]) (:options env)))}
|
||||||
|
|
||||||
|
:k8s:httproute {:constructor (.. gateway-api -v1 -HTTPRoute)
|
||||||
:provider-key :k8s
|
:provider-key :k8s
|
||||||
:defaults-fn (fn [env] ((get-in default/defaults [:k8s :storage-class]) (:options env)))}
|
:defaults-fn (fn [env] ((get-in default/defaults [:k8s :httproute]) (:options env)))}
|
||||||
|
|
||||||
|
:k8s:cluster-issuer {:constructor (.. cert-manager -v1 -ClusterIssuer)
|
||||||
|
:provider-key :k8s
|
||||||
|
:defaults-fn (fn [env] ((get-in default/defaults [:k8s :cluster-issuer]) (:options env)))}
|
||||||
|
|
||||||
|
:k8s:certificates
|
||||||
|
{:constructor (.. cert-manager -v1 -Certificate)
|
||||||
|
:provider-key :k8s
|
||||||
|
:defaults-fn (fn [env]
|
||||||
|
(let [{:keys [app-namespace is-prod?]} (:options env)]
|
||||||
|
(p-> env :options :vault:prepare "stringData" .-domains
|
||||||
|
#(vec
|
||||||
|
(for [domain (js/JSON.parse %)]
|
||||||
|
(let [clean-name (clojure.string/replace domain #"\." "-")]
|
||||||
|
{:_suffix clean-name
|
||||||
|
:metadata {:namespace app-namespace}
|
||||||
|
:spec {:dnsNames [domain (str "*." domain)]
|
||||||
|
:secretName (str clean-name "-tls")
|
||||||
|
:issuerRef {:name (if is-prod? "letsencrypt-prod" "letsencrypt-staging")
|
||||||
|
:kind "ClusterIssuer"}}}))))))}
|
||||||
|
|
||||||
|
:k8s:certificate
|
||||||
|
{:constructor (.. cert-manager -v1 -Certificate)
|
||||||
|
:provider-key :k8s
|
||||||
|
:defaults-fn (fn [env] ((get-in default/defaults [:k8s :certificate]) (:options env)))}
|
||||||
|
|
||||||
;; Docker Resources
|
;; Docker Resources
|
||||||
:docker:image {:constructor (.. docker-build -Image)
|
:docker:image {:constructor (.. docker-build -Image)
|
||||||
@@ -164,7 +211,7 @@
|
|||||||
:harbor:project {:constructor (.. harbor -Project)
|
:harbor:project {:constructor (.. harbor -Project)
|
||||||
:provider-key :harbor
|
:provider-key :harbor
|
||||||
:defaults-fn (fn [env] ((get-in default/defaults [:harbor :project]) (:options env)))}
|
:defaults-fn (fn [env] ((get-in default/defaults [:harbor :project]) (:options env)))}
|
||||||
|
|
||||||
:harbor:robot-account {:constructor (.. harbor -RobotAccount)
|
:harbor:robot-account {:constructor (.. harbor -RobotAccount)
|
||||||
:provider-key :harbor
|
:provider-key :harbor
|
||||||
:defaults-fn (fn [env] ((get-in default/defaults [:harbor :robot-account]) (:options env)))}})
|
:defaults-fn (fn [env] ((get-in default/defaults [:harbor :robot-account]) (:options env)))}})
|
||||||
@@ -176,31 +223,55 @@
|
|||||||
(fn [dispatch-key _config] dispatch-key))
|
(fn [dispatch-key _config] dispatch-key))
|
||||||
|
|
||||||
(defmethod deploy-resource :default
|
(defmethod deploy-resource :default
|
||||||
[dispatch-key
|
[dispatch-key full-config]
|
||||||
full-config]
|
|
||||||
|
|
||||||
(if-let [spec (get component-specs dispatch-key)]
|
(if-let [spec (get component-specs dispatch-key)]
|
||||||
(let [app-name (:app-name full-config)
|
(let [app-name (:app-name full-config)
|
||||||
dependsOn (:dependsOn full-config)
|
dependsOn (:dependsOn full-config)
|
||||||
provider-key (:provider-key spec)
|
provider-key (:provider-key spec)
|
||||||
provider (get full-config provider-key)
|
provider (get full-config provider-key)
|
||||||
|
resource-class (:constructor spec)
|
||||||
opts-key (keyword (str (name dispatch-key) "-opts"))
|
opts-key (keyword (str (name dispatch-key) "-opts"))
|
||||||
component-opts (get full-config opts-key)
|
component-opts (get full-config opts-key)
|
||||||
env {:options full-config :secrets (:secrets full-config)}
|
env {:options full-config :secrets (:secrets full-config) :component-opts component-opts}
|
||||||
defaults (when-let [defaults-fn (:defaults-fn spec)]
|
raw-defaults (when-let [df (:defaults-fn spec)] (df env))]
|
||||||
(defaults-fn env))
|
|
||||||
resource-class (:constructor spec)]
|
(if resource-class
|
||||||
|
(let [base-creator (fn [final-args suffix]
|
||||||
(if resource-class
|
(let [final-name (if suffix
|
||||||
(let [creator-fn (fn [final-args]
|
(str app-name "-" suffix)
|
||||||
(new-resource resource-class
|
app-name)]
|
||||||
app-name
|
(new-resource resource-class
|
||||||
final-args
|
final-name
|
||||||
provider
|
final-args
|
||||||
dependsOn))
|
provider
|
||||||
resource (generic-transform creator-fn component-opts defaults (:secrets env) full-config)]
|
dependsOn)))]
|
||||||
|
|
||||||
|
{:resource
|
||||||
|
(p-> raw-defaults
|
||||||
|
#(let [defaults-list (if (vector? %)
|
||||||
|
%
|
||||||
|
[%])
|
||||||
|
is-multi? (vector? %) resources
|
||||||
|
(doall
|
||||||
|
(map-indexed
|
||||||
|
(fn [idx item]
|
||||||
|
(let [suffix (cond
|
||||||
|
(:_suffix item) (:_suffix item)
|
||||||
|
is-multi? (str idx)
|
||||||
|
:else nil)
|
||||||
|
clean-item (dissoc item :_suffix)
|
||||||
|
item-creator (fn [resolved-args]
|
||||||
|
(base-creator resolved-args suffix))]
|
||||||
|
|
||||||
|
(generic-transform item-creator
|
||||||
|
component-opts
|
||||||
|
clean-item
|
||||||
|
(:secrets env)
|
||||||
|
full-config)))
|
||||||
|
defaults-list))]
|
||||||
|
(if is-multi? resources (first resources))))})
|
||||||
|
|
||||||
{:resource resource})
|
|
||||||
(throw (js/Error. (str "No :constructor found for spec: " dispatch-key)))))
|
(throw (js/Error. (str "No :constructor found for spec: " dispatch-key)))))
|
||||||
|
|
||||||
(throw (js/Error. (str "Unknown resource: " dispatch-key)))))
|
(throw (js/Error. (str "Unknown resource: " dispatch-key)))))
|
||||||
@@ -334,17 +405,17 @@
|
|||||||
stack-items)]
|
stack-items)]
|
||||||
(:resources-map result)))
|
(:resources-map result)))
|
||||||
|
|
||||||
(defn deploy! [{:keys [pulumi-cfg service-registry all-providers]}]
|
(defn deploy! [{:keys [pulumi-cfg resource-configs all-providers]}]
|
||||||
(let [
|
(let [
|
||||||
|
|
||||||
deployment-results
|
deployment-results
|
||||||
(into
|
(into
|
||||||
{}
|
{}
|
||||||
(for [config service-registry]
|
(for [config resource-configs]
|
||||||
(let [
|
(let [
|
||||||
{:keys [stack app-name]} config
|
{:keys [stack app-name]} config
|
||||||
_ (when (nil? config)
|
_ (when (nil? config)
|
||||||
(throw (js/Error. "Service registry contains a nil value!")))
|
(throw (js/Error. "Resource configs contain a nil value!")))
|
||||||
|
|
||||||
common-opts (merge
|
common-opts (merge
|
||||||
all-providers
|
all-providers
|
||||||
|
|||||||
Reference in New Issue
Block a user