diff --git a/toolsrv/bootstrap.sh b/toolsrv/bootstrap.sh index cac9aa9..43f3bf3 100644 --- a/toolsrv/bootstrap.sh +++ b/toolsrv/bootstrap.sh @@ -1,15 +1,27 @@ #!/bin/sh # Bootstrap script for ollie-remote SSH deployment. -# Checks for cached binary by hash, downloads if needed, then execs. +# Checks for cached binaries by hash, downloads if needed, then execs. main() { set -e # CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/ollie/bin" CACHE_BIN="$CACHE_DIR/ollie-remote" CACHE_HASH="$CACHE_DIR/ollie-remote.hash" +CACHE_LANDRUN="$CACHE_DIR/landrun" +CACHE_LANDRUN_HASH="$CACHE_DIR/landrun.hash" # -if [ -x "$CACHE_BIN" ] && [ -f "$CACHE_HASH" ] && [ "$(cat "$CACHE_HASH")" = "@@HASH@@" ]; then - echo "OLLIE_LOADER_START {\"need_download\":false}" >&2 +NEED_DOWNLOAD=false +NEED_LANDRUN=false +# +if ! [ -x "$CACHE_BIN" ] || ! [ -f "$CACHE_HASH" ] || [ "$(cat "$CACHE_HASH")" != "@@HASH@@" ]; then + NEED_DOWNLOAD=true +fi +if ! [ -x "$CACHE_LANDRUN" ] || ! [ -f "$CACHE_LANDRUN_HASH" ] || [ "$(cat "$CACHE_LANDRUN_HASH")" != "@@LANDRUN_HASH@@" ]; then + NEED_LANDRUN=true +fi +# +if [ "$NEED_DOWNLOAD" = "false" ] && [ "$NEED_LANDRUN" = "false" ]; then + echo "OLLIE_LOADER_START {\"need_download\":false,\"need_landrun\":false}" >&2 else # Find base64 decoder if command -v base64 >/dev/null 2>&1; then @@ -32,24 +44,41 @@ else command -v gunzip >/dev/null 2>&1 || GUNZIP_CMD="gzip -d" # mkdir -p "$CACHE_DIR" - echo "OLLIE_LOADER_START {\"need_download\":true}" >&2 + echo "OLLIE_LOADER_START {\"need_download\":$NEED_DOWNLOAD,\"need_landrun\":$NEED_LANDRUN}" >&2 # - # Read download size, then binary data - while IFS= read -r line; do - case "$line" in - OLLIE_DOWNLOAD\ *) BINARY_LENGTH="${line#OLLIE_DOWNLOAD }"; break ;; - esac - done - # - CACHE_TMP="$CACHE_BIN.tmp.$$" - if ! head -c "$BINARY_LENGTH" | $BASE64_CMD | $GUNZIP_CMD > "$CACHE_TMP"; then - rm -f "$CACHE_TMP" - echo "ERROR: binary transfer failed" >&2 - exit 1 + if [ "$NEED_DOWNLOAD" = "true" ]; then + while IFS= read -r line; do + case "$line" in + OLLIE_DOWNLOAD\ *) BINARY_LENGTH="${line#OLLIE_DOWNLOAD }"; break ;; + esac + done + CACHE_TMP="$CACHE_BIN.tmp.$$" + if ! head -c "$BINARY_LENGTH" | $BASE64_CMD | $GUNZIP_CMD > "$CACHE_TMP"; then + rm -f "$CACHE_TMP" + echo "ERROR: ollie-remote transfer failed" >&2 + exit 1 + fi + chmod +x "$CACHE_TMP" + mv "$CACHE_TMP" "$CACHE_BIN" + echo "@@HASH@@" > "$CACHE_HASH" + fi + # + if [ "$NEED_LANDRUN" = "true" ]; then + while IFS= read -r line; do + case "$line" in + OLLIE_DOWNLOAD\ *) BINARY_LENGTH="${line#OLLIE_DOWNLOAD }"; break ;; + esac + done + CACHE_TMP="$CACHE_LANDRUN.tmp.$$" + if ! head -c "$BINARY_LENGTH" | $BASE64_CMD | $GUNZIP_CMD > "$CACHE_TMP"; then + rm -f "$CACHE_TMP" + echo "ERROR: landrun transfer failed" >&2 + exit 1 + fi + chmod +x "$CACHE_TMP" + mv "$CACHE_TMP" "$CACHE_LANDRUN" + echo "@@LANDRUN_HASH@@" > "$CACHE_LANDRUN_HASH" fi - chmod +x "$CACHE_TMP" - mv "$CACHE_TMP" "$CACHE_BIN" - echo "@@HASH@@" > "$CACHE_HASH" echo "OLLIE_LOADER_READY" >&2 fi # diff --git a/toolsrv/remote.go b/toolsrv/remote.go index cc98dee..6434dd2 100644 --- a/toolsrv/remote.go +++ b/toolsrv/remote.go @@ -77,9 +77,22 @@ func RemoteDial(ctx context.Context, cfg RemoteConfig) (*RemoteServer, error) { hash := sha256.Sum256(binData) hashStr := hex.EncodeToString(hash[:]) - // Generate bootstrap script with hash and CWD baked in. + // Find landrun binary to deploy alongside ollie-remote. + landrunPath, err := exec.LookPath("landrun") + if err != nil { + return nil, fmt.Errorf("find landrun binary: %w", err) + } + landrunData, err := os.ReadFile(landrunPath) + if err != nil { + return nil, fmt.Errorf("read landrun binary: %w", err) + } + landrunHash := sha256.Sum256(landrunData) + landrunHashStr := hex.EncodeToString(landrunHash[:]) + + // Generate bootstrap script with hashes and CWD baked in. bootstrap := bootstrapTemplate bootstrap = strings.ReplaceAll(bootstrap, "@@HASH@@", hashStr) + bootstrap = strings.ReplaceAll(bootstrap, "@@LANDRUN_HASH@@", landrunHashStr) cwdEscaped := shellEscape(cfg.CWD) extraArgs := "" if cfg.ToolsPath != "" { @@ -132,6 +145,7 @@ func RemoteDial(ctx context.Context, cfg RemoteConfig) (*RemoteServer, error) { // Monitor stderr for bootstrap messages. type loaderMsg struct { NeedDownload bool `json:"need_download"` + NeedLandrun bool `json:"need_landrun"` } stderrScanner := bufio.NewScanner(stderrPipe) @@ -144,7 +158,7 @@ func RemoteDial(ctx context.Context, cfg RemoteConfig) (*RemoteServer, error) { var msg loaderMsg json.Unmarshal([]byte(after), &msg) loaderCh <- msg - if !msg.NeedDownload { + if !msg.NeedDownload && !msg.NeedLandrun { close(readyCh) } } else if line == "OLLIE_LOADER_READY" { @@ -159,8 +173,16 @@ func RemoteDial(ctx context.Context, cfg RemoteConfig) (*RemoteServer, error) { if msg.NeedDownload { if err := transferBinary(stdin, binData); err != nil { cmd.Process.Kill() - return nil, fmt.Errorf("transfer binary: %w", err) + return nil, fmt.Errorf("transfer ollie-remote: %w", err) } + } + if msg.NeedLandrun { + if err := transferBinary(stdin, landrunData); err != nil { + cmd.Process.Kill() + return nil, fmt.Errorf("transfer landrun: %w", err) + } + } + if msg.NeedDownload || msg.NeedLandrun { // Wait for ready signal. select { case <-readyCh: