Restructuring
This commit is contained in:
parent
2e84901280
commit
e2d2564273
15
deps.edn
15
deps.edn
|
@ -1,18 +1,15 @@
|
|||
{:deps
|
||||
{org.clojure/clojure {:mvn/version "1.10.1"}
|
||||
clj-http {:mvn/version "3.10.0"}
|
||||
cheshire {:mvn/version "5.9.0"}
|
||||
org.clojure/tools.cli {:mvn/version "0.4.2"}
|
||||
cheshire {:mvn/version "5.10.0"}
|
||||
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.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 {:mvn/version "1.4.9"}
|
||||
cljstache {:mvn/version "2.0.4"}
|
||||
;; Logging
|
||||
com.taoensso/timbre {:mvn/version "4.10.0"}
|
||||
com.fzakaria/slf4j-timbre {:mvn/version "0.3.14"}
|
||||
org.slf4j/log4j-over-slf4j {:mvn/version "1.7.29"}
|
||||
org.slf4j/jul-to-slf4j {:mvn/version "1.7.29"}
|
||||
org.slf4j/jcl-over-slf4j {:mvn/version "1.7.29"}}
|
||||
cljstache {:mvn/version "2.0.4"}}
|
||||
:paths ["src" "resources"]
|
||||
:mvn/repos {"central" {:url "https://repo1.maven.org/maven2/"}
|
||||
"clojars" {:url "https://repo.clojars.org/"}}
|
||||
|
|
|
@ -1,27 +1,90 @@
|
|||
(ns com.sompani.onboarding
|
||||
"A tool to automate the onboarding of new VCs.
|
||||
|
||||
This works by providing `-main` with an EDN file containing the keys
|
||||
with the necessary info. The EDN file has to contain a map with the
|
||||
following keys:
|
||||
|
||||
* `:company-name`: the company name as in <company-name>.talent.careers.
|
||||
* `:company-domain`: the company domain name as in talent.<company-domain>."
|
||||
(:require [clojure.java.shell :as sh]
|
||||
[clojure.java.io :as io]
|
||||
"A tool to automate the onboarding of new VCs."
|
||||
(: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]
|
||||
[taoensso.timbre :as timbre
|
||||
:refer [log trace debug info warn error fatal report
|
||||
logf tracef debugf infof warnf errorf fatalf reportf
|
||||
spy get-env]])
|
||||
[cljstache.core :as cljstache])
|
||||
(:import (java.nio.file Files
|
||||
LinkOption)
|
||||
(java.nio.file.attribute PosixFileAttributeView
|
||||
FileAttribute)))
|
||||
FileAttribute)
|
||||
(java.io BufferedReader File)
|
||||
(org.openqa.selenium.firefox FirefoxDriver)
|
||||
(org.openqa.selenium By)))
|
||||
|
||||
;; # Webserver configuration
|
||||
;; # Helper functions
|
||||
(defn sh
|
||||
"Launches a process with optional args, returning exit code.
|
||||
Prints stdout & stderr."
|
||||
[bin & args]
|
||||
(let [arg-array ^"[Ljava.lang.String;" (into-array String (cons bin args))
|
||||
process (-> (ProcessBuilder. arg-array)
|
||||
(.redirectErrorStream true) ;; TODO stream stderr to stderr
|
||||
(.start))]
|
||||
(with-open [out (io/reader (.getInputStream process))]
|
||||
(loop []
|
||||
(when-let [line (.readLine ^BufferedReader out)]
|
||||
(println line)
|
||||
(recur))))
|
||||
(.waitFor process)))
|
||||
|
||||
(def driver (FirefoxDriver.))
|
||||
|
||||
;; # 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
|
||||
|
||||
|
@ -36,6 +99,7 @@
|
|||
(.setGroup group)))
|
||||
|
||||
(defn make-dirs! [{:keys [company-name]}]
|
||||
(printf "Creating deploy directories for %s." company-name)
|
||||
(let [attrs (Files/getFileAttributeView (.toPath (io/file "/srv/http/www.sompani.com"))
|
||||
PosixFileAttributeView
|
||||
(into-array LinkOption [LinkOption/NOFOLLOW_LINKS]))
|
||||
|
@ -52,10 +116,11 @@
|
|||
"/srv/http/%s.talent.careers-uploads"
|
||||
"/srv/http/%s.talent.careers.1234"]
|
||||
:let [dir (.toPath (io/file (format dir-str company-name)))]]
|
||||
(printf ".")
|
||||
(and
|
||||
(Files/createDirectory dir fattr)
|
||||
(set-owner dir owner))
|
||||
)
|
||||
(set-owner dir owner)))
|
||||
(printf ".")
|
||||
(let [link (.toPath (io/file (format "/srv/http/staging.%s.talent.careers" company-name)))]
|
||||
(and
|
||||
(Files/createSymbolicLink link
|
||||
|
@ -64,35 +129,39 @@
|
|||
(set-owner link owner))
|
||||
)
|
||||
|
||||
(printf ".")
|
||||
(let [link (.toPath (io/file (format "/srv/http/%s.talent.careers" company-name)))]
|
||||
(and
|
||||
(Files/createSymbolicLink link
|
||||
(.toPath (io/file (format "/srv/http/%s.talent.careers.1234" company-name)))
|
||||
fattr)
|
||||
(set-owner link owner))
|
||||
)))
|
||||
(set-owner link owner)))
|
||||
(printf " ok.\n")))
|
||||
|
||||
;; ## nginx configuration
|
||||
|
||||
(defn create-nginx-server! [datamap]
|
||||
(printf "Creating nginx entries for $s." (:company-name datamap))
|
||||
(doseq [file ["skel.talent.careers"
|
||||
"staging.skel.talent.careers"]
|
||||
:let [in-file (str "resources/nginx/" file)
|
||||
out-file (format "/etc/nginx/servers-available/%s" (str/replace file #"skel" (:company-name datamap)))]]
|
||||
(info "using template" in-file "to create" out-file)
|
||||
(printf ".")
|
||||
(spit out-file
|
||||
(cljstache/render (slurp in-file) datamap))))
|
||||
(cljstache/render (slurp in-file) datamap)))
|
||||
(printf " ok.\n"))
|
||||
|
||||
;; ## Certificates
|
||||
(defn generate-certs! [{:keys [company-name company-domain] :as datamap}]
|
||||
(info
|
||||
(apply sh/sh (map #(cljstache/render % datamap)
|
||||
["certbot" "certonly" "--nginx"
|
||||
"-d" "staging.{{company-name}}.talent.careers"
|
||||
"-d" "{{company-name}}.talent.careers"
|
||||
"-d" "talent.{{company-domain}}"
|
||||
"-d" "www.talent.{{company-domain}}"
|
||||
"--cert-name" "{{company-name}}"]))))
|
||||
(println "Generating certificates...")
|
||||
(apply sh (map #(cljstache/render % datamap)
|
||||
["certbot" "certonly" "--nginx"
|
||||
"-d" "staging.{{company-name}}.talent.careers"
|
||||
"-d" "{{company-name}}.talent.careers"
|
||||
"-d" "talent.{{company-domain}}"
|
||||
"-d" "www.talent.{{company-domain}}"
|
||||
"--cert-name" "{{company-name}}"]))
|
||||
(println "ok."))
|
||||
|
||||
;; # DNS configuration
|
||||
|
||||
|
@ -108,28 +177,53 @@
|
|||
{: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"}])
|
||||
|
||||
(defn make-basic-dns-entries! [{:keys [company-name]}]
|
||||
(defn make-dns-entries! [entries]
|
||||
(let [uri "https://api.cloudflare.com/client/v4/zones/5cd643e7432d7cf69f44e268e32b5452/dns_records"
|
||||
headers {"Authorization" (str "Bearer " (System/getenv "CLOUDFLARE_API"))}
|
||||
entries (basic-dns-entries company-name)]
|
||||
(debug "Creating DNS entries for" company-name "; Headers: " headers)
|
||||
headers {"Authorization" (str "Bearer " (System/getenv "CLOUDFLARE_API"))}]
|
||||
(doseq [entry entries]
|
||||
(info (http/post uri
|
||||
{:headers headers
|
||||
:content-type :json
|
||||
:form-params entry})))))
|
||||
(printf ".")
|
||||
(http/post uri
|
||||
{:headers headers
|
||||
:content-type :json
|
||||
:form-params entry}))))
|
||||
|
||||
(defn make-basic-dns-entries! [{:keys [company-name]}]
|
||||
(printf "Creating basic DNS entries for %s." company-name)
|
||||
(make-dns-entries! (basic-dns-entries company-name))
|
||||
(println " ok."))
|
||||
|
||||
;; # Main initialization
|
||||
(def cli-options
|
||||
[["-d" "--domain VCDOMAIN" "The domain of the VC to onboard"
|
||||
:default nil
|
||||
:id :vc-domain]
|
||||
["-n" "--name VCNAME" "The name of the VC to onboard"
|
||||
:default nil
|
||||
:id :vc-name]
|
||||
[nil "--deploy-directories" "Create deploy directories"]
|
||||
[nil "--base-dns" "Create basic DNS entries"]
|
||||
[nil "--aws-domain" "Create AWS Domain DNS entries and verify new domain"]
|
||||
[nil "--nginx" "Create nginx entries"]
|
||||
[nil "--certify" "Generate certificates"]
|
||||
["-h" "--help"]])
|
||||
|
||||
(defn -main [& args]
|
||||
(let [datamap (read-string (slurp (nth args 0)))]
|
||||
(info "Creating deploy directories.")
|
||||
(make-dirs! datamap)
|
||||
(info "Creating basic DNS entries.")
|
||||
(make-basic-dns-entries! datamap)
|
||||
(info "Creating nginx entries.")
|
||||
(create-nginx-server! datamap)
|
||||
(info "Generating certificates.")
|
||||
(generate-certs! datamap)
|
||||
(info "Done.")))
|
||||
|
||||
(let [{:keys [vc-domain
|
||||
vc-name
|
||||
deploy-directories
|
||||
base-dns
|
||||
aws-domain
|
||||
nginx
|
||||
certify]
|
||||
:as options}
|
||||
(:options (parse-opts args cli-options))
|
||||
datamap {:company-name vc-name "company-domain" vc-domain}]
|
||||
(and deploy-directories (make-dirs! datamap))
|
||||
(and base-dns (make-basic-dns-entries! datamap))
|
||||
(and aws-domain (do (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.")))
|
||||
|
|
Loading…
Reference in New Issue