简体   繁体   中英

How to use gcloud with Babashka

I'm trying to use Babashka to replace a few Bash scripts I use to deploy functions on GCP Cloud Functions.

The script below is working, but I wonder if there is a better way to execute the gcloud shell command:

#!/usr/bin/env bb
(require '[cheshire.core :as json]
         '[clojure.java.shell :refer [sh]])

(let [package-json (json/parse-string (slurp "package.json") true)
      name (:name package-json)
      entry-point "entryPoint"
      region "europe-west3"
      memory "128MB"
      runtime "nodejs14"
      source "dist"
      service-account "sa-function-invoker@prj-kitchen-sink.iam.gserviceaccount.com"
      timeout "10s"]
  (println "deploy function" name "with entry point" entry-point "to GCP Cloud Functions." "Attach service account" service-account)
  (let [output (sh "gcloud" "functions" "deploy" name "--region" region "--entry-point" entry-point "--memory" memory "--runtime" runtime "--service-account" service-account "--source" source "--trigger-http" "--timeout" timeout)]
    (if (= "" (:err output))
      (println (:out output))
      (println (:err output)))))

As a comparison, the Bash script I was using is easier to read:

#!/bin/bash
set -euo pipefail

FUNCTION_NAME=$(cat package.json | jq '{name}' | jq '.name' | sed 's/"//g')
FUNCTION_ENTRY_POINT=entryPoint
ATTACHED_SA=sa-function-invoker@prj-kitchen-sink.iam.gserviceaccount.com
MEMORY=128MB

echo "deploy function `${FUNCTION_NAME}` with entry point `${FUNCTION_ENTRY_POINT}` to GCP Cloud Functions. Attach service account `${ATTACHED_SA}`"

gcloud functions deploy ${FUNCTION_NAME} \
  --project ${GCP_PROJECT_ID} \
  --region ${GCP_REGION} \
  --memory ${MEMORY} \
  --runtime nodejs14 \
  --service-account ${ATTACHED_SA} \
  --source dist \
  --entry-point ${FUNCTION_ENTRY_POINT} \
  --timeout 10s

I guess my question is not very specific to Babashka or gcloud, but it's about how to construct commands with clojure.java.shell in general...

If you want to execute the shell command and see the direct output as it appears, I recommend using babashka.process/process or babashka.tasks/shell :


@(babashka.process/process ["ls" "-la"] {:out :inherit :err :inherit})

@(babashka.process/process ["ls" "-la"] {:inherit true})

(babashka.tasks/shell "ls -la")

The above invocations do pretty much the same, but shell also applied babashka.process/check which throws if the exit code was non-zero. The @ sign before the invocation is the same as calling deref which means: wait for the process to finish. If you don't prepend that, than the process is going to run asynchronously.

More info:

One trick I use to simplify calling out to the shell is shown by this helper function :

(shell-cmd cmd-str)
Runs a command string in the default OS shell (/bin/bash); returns result in a Clojure map. Example:

 (shell-cmd "ls -ldF *")
   ;=>   {:exit    0     ; unix exit status (0 -> normal)
          :err    ''     ; text from any errors
          :out    '...'  ; text output as would printed to console
         }

It allows you to write a single command string, instead of having to manually tokenize all the parts of the string. The implementation is quite simple:

 (def ^:dynamic *os-shell* "/bin/bash") ; could also use /bin/zsh, etc

 (defn shell-cmd
   [cmd-str]
   (let [result (shell/sh *os-shell* "-c" cmd-str)]
     (if (= 0 (grab :exit result))
       result
       (throw (ex-info "shell-cmd: clojure.java.shell/sh failed, cmd-str:" (vals->map cmd-str result))))))

So it allows you to send a command string directly to /bin/bash and allow it to parse the args as normal.

I used this extensively a few years back to control AWS RDS hosts (creating, snapshots, selecting, deleting) via the AWS CLI and it was very easy to use.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM