Standalone script file
This commit is contained in:
parent
532bb967c3
commit
0b10cb7d62
25
deps.edn
25
deps.edn
|
@ -1,21 +1,16 @@
|
||||||
{:deps
|
{:deps
|
||||||
{org.clojure/clojure {:mvn/version "1.10.1"}
|
{org.clojure/clojure {:mvn/version "1.10.1"}
|
||||||
org.clojure/tools.cli {:mvn/version "0.4.2"}
|
org.clojure/tools.cli {:mvn/version "0.4.2"}
|
||||||
cheshire {:mvn/version "5.10.0"}
|
cheshire/cheshire {:mvn/version "5.10.0"}
|
||||||
clj-http {:mvn/version "3.10.0"}
|
clj-http/clj-http {:mvn/version "3.10.0"}
|
||||||
;; org.martinklepsch/clj-http-lite {:mvn/version "0.4.3"}
|
org.seleniumhq.selenium/selenium-java {:mvn/version "4.0.0-alpha-4"}
|
||||||
org.seleniumhq.selenium/selenium-java {:mvn/version "4.0.0-alpha-4"}
|
org.postgresql/postgresql {:mvn/version "42.2.9"}
|
||||||
org.postgresql/postgresql {:mvn/version "42.2.9"}
|
com.layerware/hugsql-core {:mvn/version "0.5.1"}
|
||||||
com.layerware/hugsql-core {:mvn/version "0.5.1"}
|
|
||||||
com.layerware/hugsql-adapter-next-jdbc {:mvn/version "0.5.1"}
|
com.layerware/hugsql-adapter-next-jdbc {:mvn/version "0.5.1"}
|
||||||
digest {:mvn/version "1.4.9"}
|
digest/digest {:mvn/version "1.4.9"}
|
||||||
cljstache {:mvn/version "2.0.4"}}
|
cljstache/cljstache {:mvn/version "2.0.4"}}
|
||||||
:paths ["src" "resources"]
|
:paths ["src" "resources"]
|
||||||
:mvn/repos {"central" {:url "https://repo1.maven.org/maven2/"}
|
:mvn/repos {"central" {:url "https://repo1.maven.org/maven2/"}
|
||||||
"clojars" {:url "https://repo.clojars.org/"}}
|
"clojars" {:url "https://repo.clojars.org/"}}
|
||||||
:aliases {:outdated {:extra-deps {olical/depot {:mvn/version "1.8.4"}}
|
:aliases {:outdated {:extra-deps {olical/depot {:mvn/version "1.8.4"}}
|
||||||
:main-opts ["-m" "depot.outdated.main" "-a" "outdated"]}
|
:main-opts ["-m" "depot.outdated.main" "-a" "outdated"]}}}
|
||||||
:docs {:extra-deps {marginalia {:git/url "https://github.com/zilti/marginalia" :sha "33af53d4848c58aa0e7cfdd76ab23310052816af"}}
|
|
||||||
:main-opts ["-m" "marginalia.core" "-n" "Sompani-Toolbox"]}
|
|
||||||
:test {:extra-paths ["test"]
|
|
||||||
:extra-deps {mockery {:mvn/version "0.1.4"}}}}}
|
|
||||||
|
|
|
@ -1,21 +1,50 @@
|
||||||
#!/usr/bin bb
|
#!/bin/sh
|
||||||
(ns
|
#_(
|
||||||
(:require [babashka.curl :as curl])
|
DEPS='
|
||||||
(:import (java.nio.file Files
|
{:deps
|
||||||
LinkOption)
|
{org.clojure/clojure {:mvn/version "1.10.1"}
|
||||||
(java.nio.file.attribute PosixFileAttributeView
|
org.clojure/tools.cli {:mvn/version "0.4.2"}
|
||||||
FileAttribute)
|
cheshire/cheshire {:mvn/version "5.10.0"}
|
||||||
(java.io BufferedReader File)
|
clj-http/clj-http {:mvn/version "3.10.0"}
|
||||||
(java.util.regex Pattern)))
|
org.seleniumhq.selenium/selenium-java {:mvn/version "4.0.0-alpha-4"}
|
||||||
|
org.postgresql/postgresql {:mvn/version "42.2.9"}
|
||||||
|
com.layerware/hugsql-core {:mvn/version "0.5.1"}
|
||||||
|
com.layerware/hugsql-adapter-next-jdbc {:mvn/version "0.5.1"}
|
||||||
|
digest/digest {:mvn/version "1.4.9"}
|
||||||
|
cljstache/cljstache {:mvn/version "2.0.4"}}
|
||||||
|
:paths ["src" "resources"]
|
||||||
|
:mvn/repos {"central" {:url "https://repo1.maven.org/maven2/"}
|
||||||
|
"clojars" {:url "https://repo.clojars.org/"}}
|
||||||
|
:aliases {:outdated {:extra-deps {olical/depot {:mvn/version "1.8.4"}}
|
||||||
|
:main-opts ["-m" "depot.outdated.main" "-a" "outdated"]}}}
|
||||||
|
'
|
||||||
|
OPTS=''
|
||||||
|
echo "Calling onboarding script with $@"
|
||||||
|
exec clojure $OPTS -Sdeps "$DEPS" "$0" "$@"
|
||||||
|
)
|
||||||
|
|
||||||
|
(require '[clojure.java.io :as io]
|
||||||
|
'[clojure.string :as str]
|
||||||
|
'[clojure.tools.cli :refer [parse-opts]]
|
||||||
|
'[clj-http.client :as http]
|
||||||
|
'[cljstache.core :as cljstache])
|
||||||
|
(import (java.nio.file Files
|
||||||
|
LinkOption)
|
||||||
|
(java.nio.file.attribute PosixFileAttributeView
|
||||||
|
FileAttribute)
|
||||||
|
(java.io BufferedReader #_File)
|
||||||
|
(org.openqa.selenium.firefox FirefoxDriver)
|
||||||
|
(org.openqa.selenium By))
|
||||||
|
|
||||||
|
;; # Helper functions
|
||||||
(defn sh
|
(defn sh
|
||||||
"Launches a process with optional args, returning the exit code.
|
"Launches a process with optional args, returning exit code.
|
||||||
Prints stdout & stderr."
|
Prints stdout & stderr."
|
||||||
[bin & args]
|
[bin & args]
|
||||||
(let [arg-array ^"[Ljava.lang.String;]" (into-array String (cons bin args))
|
(let [arg-array ^"[Ljava.lang.String;" (into-array String (cons bin args))
|
||||||
process (-> (ProcessBuilder. arg-array)
|
process (-> (ProcessBuilder. arg-array)
|
||||||
(.redirectErrorStream true) ;; TODO stream stderr to stderr
|
(.redirectErrorStream true) ;; TODO stream stderr to stderr
|
||||||
(.start))]
|
(.start))]
|
||||||
(with-open [out (io/reader (.getInputStream process))]
|
(with-open [out (io/reader (.getInputStream process))]
|
||||||
(loop []
|
(loop []
|
||||||
(when-let [line (.readLine ^BufferedReader out)]
|
(when-let [line (.readLine ^BufferedReader out)]
|
||||||
|
@ -23,13 +52,71 @@
|
||||||
(recur))))
|
(recur))))
|
||||||
(.waitFor process)))
|
(.waitFor process)))
|
||||||
|
|
||||||
|
(def driver (atom nil))
|
||||||
|
|
||||||
|
;; # AWS Domain
|
||||||
|
(declare make-dns-entries!)
|
||||||
|
|
||||||
|
(defn aws-login [& {:keys [aws-username aws-password]}]
|
||||||
|
(.get driver "https://eu-west-1.console.aws.amazon.com/ses/home?region=eu-west-1")
|
||||||
|
(.sendKeys (.findElement driver (By/id "resolving_input"))
|
||||||
|
(into-array String [(or aws-username (System/getenv "AWS_USERNAME"))]))
|
||||||
|
(.click (.findElement driver (By/id "next_button")))
|
||||||
|
(Thread/sleep 15000)
|
||||||
|
(.sendKeys (.findElement driver (By/id "password"))
|
||||||
|
(into-array String [(or aws-password (System/getenv "AWS_PASSWORD"))]))
|
||||||
|
(.click (.findElement driver (By/id "signin_button"))))
|
||||||
|
|
||||||
|
(defn aws-verify-domain-dns [{:keys [company-name]}]
|
||||||
|
(.click (.findElement driver (By/linkText "Domains")))
|
||||||
|
(.click (.findElement driver (By/id "gwt-debug-verifyNewDomain")))
|
||||||
|
(.sendKeys (.findElement driver (By/cssSelector "td > .gwt-TextBox"))
|
||||||
|
(into-array String [(str company-name ".talent.careers")]))
|
||||||
|
(.click (.findElement driver (By/cssSelector ".gwt-CheckBox input")))
|
||||||
|
(.click (.findElement driver (By/xpath "//span[contains(text(),\"Verify This Domain\")]")))
|
||||||
|
(Thread/sleep 2000)
|
||||||
|
(let [rows (.findElements driver (By/cssSelector ".dialogMiddle table[style^=\"table-layout\"] tr[__gwt_subrow=\"0\"]"))
|
||||||
|
entries (->>
|
||||||
|
(map #(identity {:name (.getText (.findElement % (By/cssSelector "td:nth-child(1)")))
|
||||||
|
:type (.getText (.findElement % (By/cssSelector "td:nth-child(2)")))
|
||||||
|
:content (.getText (.findElement % (By/cssSelector "td:nth-child(3)")))}) rows)
|
||||||
|
(remove #(or (= "" (:name %))
|
||||||
|
(= "MX" (:type %)))))]
|
||||||
|
(.click (.findElement driver (By/xpath "//span[contains(text(), \"Close\")]")))
|
||||||
|
(make-dns-entries! entries)))
|
||||||
|
|
||||||
|
(defn aws-verify-domain-mailfrom [{:keys [company-name]}]
|
||||||
|
(.click (.findElement driver (By/linkText "Domains")))
|
||||||
|
(.click (.findElement driver (By/linkText (str company-name ".talent.careers"))))
|
||||||
|
(.click (.findElement driver (By/xpath "//span[contains(text(),\"MAIL FROM Domain\")]")))
|
||||||
|
(.click (.findElement driver (By/xpath "//button[contains(text(),\"Set MAIL FROM Domain\")]")))
|
||||||
|
(.sendKeys (.findElement driver (By/cssSelector "td > input"))
|
||||||
|
(into-array String ["m"]))
|
||||||
|
(.click (.findElement driver (By/xpath "//span[contains(text(),\"Set MAIL FROM Domain\")]")))
|
||||||
|
(Thread/sleep 2000)
|
||||||
|
(let [rows (.findElements driver (By/cssSelector ".dialogMiddle table[style^=\"table-layout\"] tr[__gwt_subrow=\"0\"]"))
|
||||||
|
entries (->> (map #(identity {:name (.getText (.findElement % (By/cssSelector "td:nth-child(1)")))
|
||||||
|
:type (.getText (.findElement % (By/cssSelector "td:nth-child(2)")))
|
||||||
|
:content (.getText (.findElement % (By/cssSelector "td:nth-child(3)")))}) rows))]
|
||||||
|
(.click (.findElement driver (By/xpath "//span[contains(text(),\"Close\")]")))
|
||||||
|
(make-dns-entries! entries)))
|
||||||
|
|
||||||
|
;; # AWS Mail
|
||||||
|
(defn aws-verify-mail-address [{:keys [company-name]}]
|
||||||
|
(.click (.findElement driver (By/linkText "Email Addresses")))
|
||||||
|
(.click (.findElement driver (By/xpath "//button[contains(text(),\"Verify a New Email Address\")]")))
|
||||||
|
(.sendKeys (.findElement driver (By/id "gwt-debug-verifySenderEmailBox"))
|
||||||
|
(into-array String [(str "info@" company-name ".talent.careers")]))
|
||||||
|
(.click (.findElement driver (By/xpath "//span[contains(text(),\"Verify This Email Address\")]"))))
|
||||||
|
|
||||||
;; ## Deployment directory structure
|
;; ## Deployment directory structure
|
||||||
(defn set-owner [path owner]
|
|
||||||
|
(defn- set-owner [path owner]
|
||||||
(->
|
(->
|
||||||
(Files/getFileAttributeView path PosixFileAttributeView (into-array LinkOption [LinkOption/NOFOLLOW_LINKS]))
|
(Files/getFileAttributeView path PosixFileAttributeView (into-array LinkOption [LinkOption/NOFOLLOW_LINKS]))
|
||||||
(.setOwner owner)))
|
(.setOwner owner)))
|
||||||
|
|
||||||
(defn set-group [path group]
|
#_(defn- set-group [path group]
|
||||||
(->
|
(->
|
||||||
(Files/getFileAttributeView path PosixFileAttributeView (into-array LinkOption [LinkOption/NOFOLLOW_LINKS]))
|
(Files/getFileAttributeView path PosixFileAttributeView (into-array LinkOption [LinkOption/NOFOLLOW_LINKS]))
|
||||||
(.setGroup group)))
|
(.setGroup group)))
|
||||||
|
@ -62,8 +149,9 @@
|
||||||
(Files/createSymbolicLink link
|
(Files/createSymbolicLink link
|
||||||
(.toPath (io/file (format "/srv/http/staging.%s.talent.careers.1234" company-name)))
|
(.toPath (io/file (format "/srv/http/staging.%s.talent.careers.1234" company-name)))
|
||||||
fattr)
|
fattr)
|
||||||
(set-owner link owner)))
|
(set-owner link owner))
|
||||||
|
)
|
||||||
|
|
||||||
(printf ".")
|
(printf ".")
|
||||||
(let [link (.toPath (io/file (format "/srv/http/%s.talent.careers" company-name)))]
|
(let [link (.toPath (io/file (format "/srv/http/%s.talent.careers" company-name)))]
|
||||||
(and
|
(and
|
||||||
|
@ -74,38 +162,33 @@
|
||||||
(printf " ok.\n")))
|
(printf " ok.\n")))
|
||||||
|
|
||||||
;; ## nginx configuration
|
;; ## nginx configuration
|
||||||
(defn render-replace [input datamap]
|
|
||||||
(reduce
|
|
||||||
#(str/replace %1 (Pattern/compile (str "\{\{" (name (key %2)) "\}\}")) (val %2))
|
|
||||||
input
|
|
||||||
datamap))
|
|
||||||
|
|
||||||
(defn create-nginx-server! [{:keys [company-name] :as datamap}]
|
(defn create-nginx-server! [datamap]
|
||||||
(printf "Creating nginx entries for %n." company-name)
|
(printf "Creating nginx entries for %n." (:company-name datamap))
|
||||||
(doseq [file ["skel.talent.careers"
|
(doseq [file ["skel.talent.careers"
|
||||||
"staging.skel.talent.careers"]
|
"staging.skel.talent.careers"]
|
||||||
:let [in-file (str "resources/nginx/" file)
|
:let [in-file (str "resources/nginx/" file)
|
||||||
out-file (format "/etc/nginx/servers-available/%s" (str/replace file #"skel" company-name))]]
|
out-file (format "/etc/nginx/servers-available/%s" (str/replace file #"skel" (:company-name datamap)))]]
|
||||||
(printf ".")
|
(printf ".")
|
||||||
(spit out-file
|
(spit out-file
|
||||||
(render-replace (slurp in-file) datamap)))
|
(cljstache/render (slurp in-file) datamap)))
|
||||||
(printf " ok.\n"))
|
(printf " ok.\n"))
|
||||||
|
|
||||||
;; ## Certificates
|
;; ## Certificates
|
||||||
(defn generate-certs! [{:keys [company-name company-domain] :as datamap}]
|
(defn generate-certs! [{:keys [_company-name _company-domain] :as datamap}]
|
||||||
(println "Generating certificates...")
|
(println "Generating certificates...")
|
||||||
(let [command (map #(render-replace % datamap)
|
(let [command (map #(cljstache/render % datamap)
|
||||||
["certbot" "certonly" "--nginx"
|
["certbot" "certonly" "--nginx"
|
||||||
"-d" "staging.{{company-name}}.talent.careers"
|
"-d" "staging.{{company-name}}.talent.careers"
|
||||||
"-d" "{{company-name}}.talent.careers"
|
"-d" "{{company-name}}.talent.careers"
|
||||||
"-d" "talent.{{company-domain}}"
|
"-d" "talent.{{company-domain}}"
|
||||||
"-d" "www.talent.{{company-domain}}"
|
"-d" "www.talent.{{company-domain}}"
|
||||||
"--cert-name" "{{company-name}}"])]
|
"--cert-name" "{{company-name}}"])]
|
||||||
(println "Executing " (pr-str command))
|
(println "Executing" (pr-str command))
|
||||||
(apply sh command))
|
(apply sh command))
|
||||||
(println "ok."))
|
(println "ok."))
|
||||||
|
|
||||||
;; # DNS Configuration
|
;; # DNS configuration
|
||||||
|
|
||||||
;; ## Basic cloudflare entries
|
;; ## Basic cloudflare entries
|
||||||
|
|
||||||
|
@ -114,8 +197,8 @@
|
||||||
{:type "A" :name (format "staging.%s" company-name) :content "185.163.117.139"}
|
{:type "A" :name (format "staging.%s" company-name) :content "185.163.117.139"}
|
||||||
{:type "AAAA" :name company-name :content "2a03:4000:3b:2bb:18ea:e0ff:fe8c:aa9a"}
|
{:type "AAAA" :name company-name :content "2a03:4000:3b:2bb:18ea:e0ff:fe8c:aa9a"}
|
||||||
{:type "AAAA" :name (format "staging.%s" company-name) :content "2a03:4000:3b:2bb:18ea:e0ff:fe8c:aa9a"}
|
{:type "AAAA" :name (format "staging.%s" company-name) :content "2a03:4000:3b:2bb:18ea:e0ff:fe8c:aa9a"}
|
||||||
{:type "MX" :name company-name :content "mx.yandex.net." :priority 50}
|
{:type "MX" :name company-name :content "mx.yandex.net." :priority 0}
|
||||||
{:type "MX" :name (format "m.%s.talent.careers" company-name) :content "feedback-smtp.eu-west-1.amazonses.com" :priority 50}
|
{:type "MX" :name (format "m.%s.talent.careers" company-name) :content "feedback-smtp.eu-west-1.amazonses.com" :priority 0}
|
||||||
{:type "TXT" :name (format "m.%s.talent.careers" company-name) :content "v=spf1 include:amazonses.com ~all"}
|
{:type "TXT" :name (format "m.%s.talent.careers" company-name) :content "v=spf1 include:amazonses.com ~all"}
|
||||||
{:type "TXT" :name (format "%s.talent.careers" company-name) :content "v=spf1 redirect=_spf.yandex.net"}
|
{:type "TXT" :name (format "%s.talent.careers" company-name) :content "v=spf1 redirect=_spf.yandex.net"}
|
||||||
{:type "TXT" :name (format "_dmarc.%s" company-name) :content "v=DMARC1; p=none; rua=sompani-d@dmarc.report-uri.com"}])
|
{:type "TXT" :name (format "_dmarc.%s" company-name) :content "v=DMARC1; p=none; rua=sompani-d@dmarc.report-uri.com"}])
|
||||||
|
@ -125,46 +208,54 @@
|
||||||
headers {"Authorization" (str "Bearer " (System/getenv "CLOUDFLARE_API"))}]
|
headers {"Authorization" (str "Bearer " (System/getenv "CLOUDFLARE_API"))}]
|
||||||
(doseq [entry entries]
|
(doseq [entry entries]
|
||||||
(printf ".")
|
(printf ".")
|
||||||
(curl/post uri
|
(http/post uri
|
||||||
{:headers headers
|
{:headers headers
|
||||||
:content-type :json
|
:content-type :json
|
||||||
:form-params entry}))))
|
:form-params entry}))))
|
||||||
|
|
||||||
(defn make-basic-dns-entries [{:keys [company-name]}]
|
(defn make-basic-dns-entries! [{:keys [company-name]}]
|
||||||
(printf "Creating basic DNS entries for %s." company-name)
|
(printf "Creating basic DNS entries for %s." company-name)
|
||||||
(make-dns-entries! (basic-dns-entries company-name))
|
(make-dns-entries! (basic-dns-entries company-name))
|
||||||
(println " ok."))
|
(println " ok."))
|
||||||
|
|
||||||
;; # Main initialization
|
;; # Main initialization
|
||||||
(def cli-options
|
(def cli-options
|
||||||
[["-d" "--domain VCDOMAIN" "The domain of the VC to onboard"
|
[["-d" "--domain VCDOMAIN" "The domain of the VC to onboard. Example: connectventures.co"
|
||||||
:default nil
|
:default nil
|
||||||
:id :vc-domain]
|
:id :vc-domain]
|
||||||
["-n" "--name VCNAME" "The name of the VC to onboard"
|
["-n" "--name VCNAME" "The name of the VC to onboard. Example: connectventures"
|
||||||
:default nil
|
:default nil
|
||||||
:id :vc-name]
|
:id :vc-name]
|
||||||
[nil "--deploy-directories" "Create deploy directories"]
|
[nil "--deploy-directories" "Create deploy directories"]
|
||||||
[nil "--base-dns" "Create basic DNS entries. Make sure to have the CLOUDFLARE_API env var set."]
|
[nil "--base-dns" "Create basic DNS entries. Make sure to have the CLOUDFLARE_API env var set."]
|
||||||
|
[nil "--aws-domain" "Create AWS Domain DNS entries and verify new domain. Make sure to have the AWS_USERNAME and AWS_PASSWORD env vars set."]
|
||||||
[nil "--nginx" "Create nginx entries"]
|
[nil "--nginx" "Create nginx entries"]
|
||||||
[nil "--certify" "Generate certificates"]
|
[nil "--certify" "Generate certificates"]
|
||||||
["-h" "--help"]])
|
["-h" "--help"]])
|
||||||
|
|
||||||
(let [{:keys [vc-domain
|
(defn -main [& args]
|
||||||
vc-name
|
(let [{:keys [vc-domain
|
||||||
deploy-directories
|
vc-name
|
||||||
base-dns
|
deploy-directories
|
||||||
aws-domain
|
base-dns
|
||||||
nginx
|
aws-domain
|
||||||
certify
|
nginx
|
||||||
help]
|
certify
|
||||||
:as options}
|
help]
|
||||||
(:options (tools.cli/parse-opts args cli-options))
|
:as _options}
|
||||||
datamap {:company-name vc-name :company-domain vc-domain}]
|
(:options (parse-opts args cli-options))
|
||||||
(if help
|
datamap {:company-name vc-name :company-domain vc-domain}]
|
||||||
(println (:summary (tools.cli/parse-opts args cli-options)))
|
(if help
|
||||||
(do
|
(println (:summary (parse-opts args cli-options)))
|
||||||
(and deploy-directories (make-dirs! datamap))
|
(do
|
||||||
(and base-dns (make-basic-dns-entries! datamap))
|
(and deploy-directories (make-dirs! datamap))
|
||||||
(and nginx (create-nginx-server! datamap))
|
(and base-dns (make-basic-dns-entries! datamap))
|
||||||
(and certify (generate-certs! datamap))
|
(and aws-domain (do (reset! driver (FirefoxDriver.))
|
||||||
(println "Done."))))
|
(aws-login)
|
||||||
|
(Thread/sleep 5000)
|
||||||
|
(aws-verify-domain-dns datamap)
|
||||||
|
(aws-verify-domain-mailfrom datamap)))
|
||||||
|
(and nginx (create-nginx-server! datamap))
|
||||||
|
(and certify (generate-certs! datamap))
|
||||||
|
(println "Done.")))))
|
||||||
|
(apply -main *command-line-args*)
|
||||||
|
|
Loading…
Reference in New Issue