google-cloud

Google Cloud Platform: Clojure + {GAE, GCE, anything else on Google Platform}
mozinator2 2020-12-08T20:02:20.048900Z

I wrote a hacky babashka script that extracts all the http requests to the google cloud api from terraform. This way I can see how terraform sets up a google cloud project and learn how I can do it myself using babashka and direct google cloud http requests

# first collect all output in the shell to file
TF_LOG=debug terraform apply -auto-approve -no-color &> apply.txt

then in babashka extract all requests

  (def requests  
    (->> (slurp "apply.txt") 
         (re-seq #"(?s)---\[ REQUEST \]-{39}(.*?)-{53}" )
         (map #(second %))
         (map (fn [lines] 
                (->> lines
                     (clojure.string/split-lines)
                     (map (fn [line] (second (clojure.string/split line #"0_x5: " )))) ; you might need to modify 0_x5
                     (remove nil?)
                     (map (fn [line] 
                            (let [[_ method url] (re-find #"^(POST|GET|PUT) (.*?) HTTP" line)
                                  [_ hk hv] (re-find #"^([a-zA-Z-]*?): (.*?)$" line)
                                  ]
                              (cond (some? method) [:method-and-url method url]
                                    (some? hk) [:header [hk hv]] 
                                   :else [:body line] 
                                    ) )
                            ))
                     (reduce (fn [acc [k v1 v2]]
                               (condp = k
                                 :method-and-url (merge acc {:method v1 :url v2})
                                 :header (merge acc {:headers (conj (:headers acc) v1 v2)})
                                 :body (merge acc {:body (str (:body acc) v1 "\n")})
                                 acc)
                               ) {:headers {} :body "" :method "" :url ""})
                     )))))

; write to edn file for reference
(clojure.pprint/pprint requests (<http://clojure.java.io/writer|clojure.java.io/writer> "apply2.edn")

domparry 2020-12-08T20:03:10.049200Z

neat!!!

mozinator2 2020-12-08T20:04:03.050Z

Also working on some functions to easily interact with google cloud from babashka

mozinator2 2020-12-08T20:05:02.050400Z

It's a work in progress. But this is how it looks like

(def headers
  {"Accept" "application/json"
   "Content-Type" "application/json"
    "Authorization"
  (str "Bearer "
       (clojure.string/trim (:out (sh "gcloud" "beta" "auth" "application-default" "print-access-token"))))})

(defn to-kebab [inp]
  (-&gt; inp 
      (s/replace #"([A-Z0-9])([A-Z])" "$1-$2")
      (s/replace #"([a-z0-9])([A-Z])" "$1-$2")
      (s/replace #"[\s_]+", "-")
      (s/lower-case)
      keyword))

(defn to-camel-case-name [inp]
  (-&gt; inp
      name
      (s/replace #"-(\w)" #(s/upper-case (second %1)))))

(def hosts 
  {:crm  "<http://cloudresourcemanager.googleapis.com|cloudresourcemanager.googleapis.com>" 
   :iam  "<http://iam.googleapis.com|iam.googleapis.com>" 
   :sql  "<http://sqladmin.googleapis.com|sqladmin.googleapis.com>"
   :run  "<http://us-east1-run.googleapis.com|us-east1-run.googleapis.com>" 
   :use  "<http://serviceusage.googleapis.com|serviceusage.googleapis.com>"
   :bill "<http://cloudbilling.googleapis.com|cloudbilling.googleapis.com>" 
   :sec  "<http://secretmanager.googleapis.com|secretmanager.googleapis.com>" })

(defn url [api &amp; paths]
  (str "https://" 
       (get hosts api) "/" 
       (clojure.string/join "/" paths)))

(defn purl [api &amp; paths] 
  (apply url (concat [api "v1" "projects"] paths)))

(def knative-apis 
  {:serving "serving.knative.dev"
   :domains "<http://domains.cloudrun.com|domains.cloudrun.com>"})

(defn kurl [api &amp; paths]
  (apply url (concat [:run "apis" (get knative-apis api) "v1" ] paths)))

(defn api [opts method url &amp; [params]]
  (let [body (-&gt; params :body)
        conv (or (:convert-keys opts) false)
        _ (clojure.pprint/pprint [method params] (io/writer (str "req.edn")))
        res (apply 
              (condp method = :get curl/get :post curl/post :put curl/put) 
              [url
               (merge 
                 {:headers headers
                  :throw false}  
                 params
                 (when 
                   (map? body) 
                   {:body 
                    (-&gt; body 
                        (json/generate-string 
                          (if conv {:key-fn to-camel-case-name} {})))}))])
        _ (clojure.pprint/pprint res (io/writer (str "res.edn")))
        body (-&gt; res :body (json/parse-string (if conv to-kebab true)))]
    (clojure.pprint/pprint body (io/writer (str "body.edn"))) 
    body))

(def gc (partial api {:convert-keys true}))
(def kn (partial api {:convert-keys false}))

(def project-id "shed-suite-classic-auth")

; services activated on the project
(gc :get 
        (purl :use project-id "services") 
        {:query-params {"fields" "services/name,nextPageToken"
                        "filter" "state:ENABLED"}})

mozinator2 2020-12-08T20:06:07.050900Z

get all service accounts for instance

(gc :get (purl :crm project-id "serviceAccounts"))

mozinator2 2020-12-08T20:08:05.052500Z

Input and output keys get converted from and to kebab case. so it's more idiomatic clojure. request / response and body get written to edn files for testing purposes

mozinator2 2020-12-08T20:08:42.053100Z

Can't do the kebab conversion for knative / cloud run because that would mess up the manifest files