Created
August 15, 2020 20:25
Star
You must be signed in to star a gist
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns x.user.deploy | |
(:require [digitalocean.v2.core :as dg] | |
[org.httpkit.client :as http] | |
[clojure.repl :refer :all] | |
[clojure.pprint :refer :all] | |
[hf.depstar.uberjar :as uj] | |
[clojure.java.shell :refer [sh]] | |
[hf.depstar.uberjar :as uj] | |
[shadow.cljs.devtools.api :as shadow] | |
[clojure.string :as str] | |
[clojure.java.io :as io] | |
[cheshire.core :as json] | |
[clojure.tools.logging :as log]) | |
(:import | |
net.schmizz.sshj.SSHClient | |
net.schmizz.sshj.common.IOUtils | |
net.schmizz.sshj.connection.channel.direct.Session | |
net.schmizz.sshj.connection.channel.direct.Session$Command | |
net.schmizz.sshj.transport.verification.PromiscuousVerifier | |
net.schmizz.sshj.common.LoggerFactory | |
net.schmizz.sshj.common.StreamCopier | |
java.util.concurrent.TimeUnit | |
net.schmizz.sshj.common.IOUtils | |
net.schmizz.sshj.xfer.LocalSourceFile | |
(java.io InputStreamReader BufferedReader))) | |
(def TKN (System/getenv "DIGITAL_OCEAN_DEV_DEPLOY_KEY")) | |
(def PASSPHRASE (System/getenv "PPK_PASS")) | |
(defn get-server [name] | |
(->> (dg/droplets TKN) | |
:droplets | |
(filter (comp #{name} :name)) | |
first)) | |
(defn get-ip [name] | |
(-> (get-server name) | |
:networks | |
:v4 | |
first | |
:ip_address)) | |
(defn create-server [name img tags ssh-keys] | |
(let [ip (assert (not (get-ip name)) (str "Server: " name " already exists.")) | |
imgs {:ubuntu19 53871280 | |
:debian 60461760 ;;["10.3 x64" "Debian" 60461760] | |
:caddy-ubuntu18 63123613} | |
img-id (get imgs img)] | |
(assert img-id (str "invalid image: " img)) | |
(log/info "Creating server with image-id" img-id) | |
(dg/create-droplet TKN nil | |
{:name name | |
:region "nyc1" | |
:size "s-1vcpu-1gb" | |
:image img-id | |
:tags (or tags []) | |
:ssh_keys (or ssh-keys [])}))) | |
#_ | |
(binding [*print-length* 500] | |
(->> (dg/images TKN nil {:per_page "999"}) | |
:images | |
(filter (comp #(str/includes? % "Caddy") :name)) | |
pprint)) | |
(def keypath "C:/Users/me/.ssh/key.ppk") | |
(defn mkssh [ip] | |
(let [ssh (SSHClient.) | |
kp (.loadKeys ssh keypath PASSPHRASE)] | |
(doto ssh | |
(.addHostKeyVerifier (PromiscuousVerifier.)) | |
(.connect ip 22) | |
.loadKnownHosts | |
(.authPublickey "root" (into-array [kp]))))) | |
(defn exec [ssh cmd-str & [{:keys [timeout] :as opt}]] | |
(assert (.isAuthenticated ssh) "ssh isn't authenticated") | |
(let [sesh (.startSession ssh) | |
cmd (.exec sesh cmd-str) | |
rdr (BufferedReader. (InputStreamReader. (.getInputStream cmd))) | |
err (BufferedReader. (InputStreamReader. (.getErrorStream cmd))) | |
] | |
;;https://gist.github.com/h4ck4life/96fb6fa214e9be135087d45c91d56300 | |
;;wip | |
#_(-> (StreamCopier. (.getInputStream cmd) | |
System/out LoggerFactory/DEFAULT ) | |
(.bufSize (spy (.getLocalMaxPacketSize cmd))) | |
(.spawn "stdout" )) | |
#_(str (IOUtils/readFully (.getInputStream cmd))) | |
(.join cmd (or timeout 20) TimeUnit/SECONDS) ;;i belive this just adds a timeout | |
;;(.join cmd) | |
(loop [] | |
(when-let [line (.readLine rdr)] | |
(println line) | |
(recur))) | |
(loop [] | |
(when-let [line (.readLine err)] | |
(println line) | |
(recur))) | |
(log/info "exec loop done") | |
(or (.getExitErrorMessage cmd) (.getExitStatus cmd)))) | |
(defn upload [ssh from to] | |
(.upload (.newSCPFileTransfer ssh) | |
from to)) | |
(defn apt-install [package-string] | |
(str "apt-get -y install " package-string )) | |
(defn apt-update [] | |
"apt-get -y update") | |
(def DEV-SERVER "my-dev-server-name") | |
(def DEV-DOMAIN "mydomain.com") | |
(def DEV-IP (get-ip DEV-SERVER)) | |
(def endpoint "https://api.digitalocean.com/v2/") | |
;;must only have one a record | |
(defn delete-domain-a-record [domain] | |
(let [[a-record :as a-records] (->> (dg/records TKN domain) | |
:domain_records | |
(filter (comp #{"A"} :type))) | |
_ (assert (= (count a-records) 1)) | |
result (http/delete (str endpoint "domains/" | |
domain "/records/" (:id a-record)) | |
{:headers {"Content-Type" "application/json" | |
"Authorization" (str "Bearer " TKN)}})] | |
(pprint @result))) | |
(defn delete-domain-a-records [domain] | |
(doseq [a-record (->> (dg/records TKN domain) | |
:domain_records | |
(filter (comp #{"A"} :type)))] | |
(let [result (http/delete (str endpoint "domains/" | |
domain "/records/" (:id a-record)) | |
{:headers {"Content-Type" "application/json" | |
"Authorization" (str "Bearer " TKN)}})] | |
(pprint @result)))) | |
(defn create-domain-a-records [domain server-name] | |
(let [ip (get-ip server-name)] | |
(assert ip (str "IP DOESN'T EXIST FOR SERVER " domain)) | |
(-> @(http/post (str endpoint "domains/" domain "/records") | |
{:headers {"Content-Type" "application/json" | |
"Authorization" (str "Bearer " TKN)} | |
:body (json/generate-string | |
{ | |
:type "A" | |
:name "@" | |
:data ip | |
:priority nil | |
:port nil | |
:ttl 1800 | |
:weight nil | |
:flags nil | |
:tag nil | |
})}) | |
pprint) | |
(-> @(http/post (str endpoint "domains/" domain "/records") | |
{:headers {"Content-Type" "application/json" | |
"Authorization" (str "Bearer " TKN)} | |
:body (json/generate-string | |
{ | |
:type "A" | |
:name "www" | |
:data ip | |
:priority nil | |
:port nil | |
:ttl 1800 | |
:weight nil | |
:flags nil | |
:tag nil | |
})}) | |
pprint))) | |
#_(->> (dg/records TKN "jt.dev") | |
:domain_records | |
(filter (comp #{"A"} :type)) | |
pprint) | |
#_ | |
(do (assert false "careful") | |
(delete-domain-a-records "mydomain.com") | |
(create-domain-a-records "mydomain.com" PROD-SERVER)) | |
(defn init-server [ssh] | |
(exec ssh (str (apt-update) ";" (apt-install "openjdk-11-jdk") | |
";java -version") | |
{:timeout 260})) | |
(def builds [:app]) | |
(defn release-cljs [] | |
(doseq [build builds] (shadow/release build))) | |
(defn send-jar [ssh] | |
(release-cljs) | |
(uj/uber-main {:dest "srv.jar" :jar :uber} {}) | |
(upload ssh "srv.jar" "/root")) | |
;;todo: use caddy json | |
(defn mkcaddyfile [domain] | |
(spit "Caddyfile" (str | |
;; "www." domain " {\n" | |
;; "redir " "https://" domain "{uri}\n" | |
;; "}\n\n" | |
;;domain " { \n" "reverse_proxy localhost:8080 \n}" | |
domain" \n" "reverse_proxy localhost:8080 \n" | |
))) | |
(defn upload-caddyfile [ssh domain] | |
(mkcaddyfile domain) | |
(upload ssh "Caddyfile" "/root")) | |
;;(mkcaddyfile "mydomain.com") | |
;;(upload ssh "Caddyfile" "") ;;where to upload? | |
(defn start-server [ssh] | |
(exec ssh "ENV=prod java -cp srv.jar clojure.main -m com.mydomain.site.main &" {:timeout 160})) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;;start to finish | |
(def new "mydomain.com-PROD1") | |
;;(create-server new :caddy-ubuntu18) | |
(def new-ip (get-ip new)) | |
(def new-ssh (mkssh new-ip)) | |
;; (send-jar new-ssh) | |
;; (exec new-ssh "killall java") | |
;; (exec new-ssh "ufw allow 8080") | |
;; (start-server new-ssh) | |
;;(exec new-ssh "ls -al log") | |
;;(exec new-ssh "tail log/all.log") | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment