Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions scripts/guest/macos-runner-bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ prepare_runner_home() {
}

cleanup_runner() {
if [[ ! -f "${RUNNER_ROOT}/.runner" ]]; then
log "runner registration already removed by ephemeral listener"
cleanup_local_state
return 0
fi

cleanup_runner_registration "cd '${RUNNER_ROOT}' && ./config.sh remove --token \"\${RUNNER_REMOVE_TOKEN}\""
}

Expand All @@ -69,6 +75,8 @@ require_env RUNNER_ROOT
require_env RUNNER_WORK_DIR
require_env RUNNER_VERSION

export PATH="${RUNNER_PATH:-/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:${HOME}/.local/bin}"

prepare_runner_home
cleanup_local_state

Expand Down
20 changes: 20 additions & 0 deletions scripts/lume/create-base-vm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,32 @@ set -Eeuo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/lib.sh"

usage() {
cat <<EOF
Usage: $(basename "$0") [options]

Create the sealed Lume base macOS VM used for ephemeral slot clones.

Options:
--config PATH Runner config file (default: $(default_lume_config_path))
--env PATH Env file with GitHub/Lume settings (default: $(default_lume_env_path))
--ipsw PATH|latest IPSW to use for VM creation (default: latest)
--unattended PATH Unattended setup plist (default: $(default_lume_unattended_path))
-h, --help Show this help text
EOF
}

config_path="$(default_lume_config_path)"
env_path="$(default_lume_env_path)"
ipsw="latest"
unattended="$(default_lume_unattended_path)"

while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help)
usage
exit 0
;;
--config)
config_path="$2"
shift 2
Expand All @@ -28,6 +47,7 @@ while [[ $# -gt 0 ]]; do
shift 2
;;
*)
usage >&2
echo "unknown argument: $1" >&2
exit 1
;;
Expand Down
28 changes: 26 additions & 2 deletions scripts/lume/create-slot.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,30 @@ set -Eeuo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/lib.sh"

usage() {
cat <<EOF
Usage: $(basename "$0") --slot N [options]

Clone and start one Lume slot VM, then wait for SSH readiness.

Options:
--slot N Slot number to create
--config PATH Runner config file (default: $(default_lume_config_path))
--env PATH Env file with GitHub/Lume settings (default: $(default_lume_env_path))
-h, --help Show this help text
EOF
}

slot=""
config_path="$(default_lume_config_path)"
env_path="$(default_lume_env_path)"

while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help)
usage
exit 0
;;
--slot)
slot="$2"
shift 2
Expand All @@ -23,13 +41,15 @@ while [[ $# -gt 0 ]]; do
shift 2
;;
*)
usage >&2
echo "unknown argument: $1" >&2
exit 1
;;
esac
done

if [[ -z "${slot}" ]]; then
usage >&2
echo "--slot is required" >&2
exit 1
fi
Expand All @@ -47,8 +67,12 @@ lume clone "${LUME_VM_BASE_NAME}" "${LUME_VM_NAME}" $(clone_args) >/dev/null
lume set "${LUME_VM_NAME}" --cpu "${LUME_VM_CPU}" --memory "${LUME_VM_MEMORY}" --disk-size "${LUME_VM_DISK_SIZE}" $(storage_args) >/dev/null

log "starting ${LUME_VM_NAME}"
nohup lume run "${LUME_VM_NAME}" --no-display --network "${LUME_VM_NETWORK}" $(storage_args) >"${LUME_SLOT_VM_LOG_FILE}" 2>&1 &
echo $! > "${LUME_SLOT_VM_PID_FILE}"
vm_pid="$(
spawn_detached \
"${LUME_SLOT_VM_LOG_FILE}" \
lume run "${LUME_VM_NAME}" --no-display --network "${LUME_VM_NETWORK}" $(storage_args)
)"
echo "${vm_pid}" > "${LUME_SLOT_VM_PID_FILE}"

wait_for_ssh
log "slot ${LUME_VM_NAME} is reachable over SSH"
20 changes: 20 additions & 0 deletions scripts/lume/destroy-slot.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,30 @@ set -Eeuo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/lib.sh"

usage() {
cat <<EOF
Usage: $(basename "$0") --slot N [options]

Stop and delete one Lume slot VM and clear its tracked VM PID file.

Options:
--slot N Slot number to destroy
--config PATH Runner config file (default: $(default_lume_config_path))
--env PATH Env file with GitHub/Lume settings (default: $(default_lume_env_path))
-h, --help Show this help text
EOF
}

slot=""
config_path="$(default_lume_config_path)"
env_path="$(default_lume_env_path)"

while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help)
usage
exit 0
;;
--slot)
slot="$2"
shift 2
Expand All @@ -23,13 +41,15 @@ while [[ $# -gt 0 ]]; do
shift 2
;;
*)
usage >&2
echo "unknown argument: $1" >&2
exit 1
;;
esac
done

if [[ -z "${slot}" ]]; then
usage >&2
echo "--slot is required" >&2
exit 1
fi
Expand Down
25 changes: 25 additions & 0 deletions scripts/lume/install-launch-agent.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@ STDOUT_PATH="${LOG_DIR}/lume-pool.stdout.log"
STDERR_PATH="${LOG_DIR}/lume-pool.stderr.log"
DOMAIN_TARGET="gui/$(id -u)"

usage() {
cat <<EOF
Usage: $(basename "$0")

Install and kickstart the per-user launch agent that reconciles the Lume pool.

This script writes:
${PLIST_PATH}
EOF
}

require_command() {
local command_name="$1"

Expand Down Expand Up @@ -70,6 +81,20 @@ EOF
main() {
local rtk_path

if [[ $# -gt 0 ]]; then
case "$1" in
-h|--help)
usage
return 0
;;
*)
usage >&2
echo "unknown argument: $1" >&2
return 1
;;
esac
fi

require_command launchctl
require_command plutil
require_command rtk
Expand Down
28 changes: 23 additions & 5 deletions scripts/lume/install-system-launch-daemons.sh
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
#!/usr/bin/env bash
set -Eeuo pipefail

if [[ "${EUID}" -ne 0 ]]; then
echo "run as root: sudo $0" >&2
exit 1
fi

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"

Expand All @@ -21,19 +16,42 @@ POOL_PLIST_PATH="${DAEMON_DIR}/${POOL_LABEL}.plist"
USER_LUME_AGENT_PATH="${TARGET_HOME}/Library/LaunchAgents/com.trycua.lume_daemon.plist"
DISABLE_USER_LUME_AGENT="false"

usage() {
cat <<EOF
Usage: $(basename "$0") [options]

Install root-owned launchd services for Lume itself and the system-wide pool reconciler.

Options:
--disable-user-lume-agent Disable the per-user Lume launch agent if present
-h, --help Show this help text
EOF
}

while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help)
usage
exit 0
;;
--disable-user-lume-agent)
DISABLE_USER_LUME_AGENT="true"
shift
;;
*)
usage >&2
echo "unknown argument: $1" >&2
exit 1
;;
esac
done

if [[ "${EUID}" -ne 0 ]]; then
usage >&2
echo "run as root: sudo $0" >&2
exit 1
fi

require_command() {
local command_name="$1"

Expand Down
46 changes: 45 additions & 1 deletion scripts/lume/lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ default_lume_unattended_path() {
printf '%s/scripts/lume/unattended-sequoia.yml' "${REPO_ROOT}"
}

default_guest_runner_path() {
printf '%s\n' '/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:${HOME}/.local/bin'
}

load_slot_env() {
local slot="$1"
local config_path="$2"
Expand Down Expand Up @@ -94,11 +98,16 @@ clone_args() {

wait_for_ssh() {
local attempt
local ssh_output
local ssh_exit

for attempt in $(seq 1 60); do
if lume ssh "${LUME_VM_NAME}" --user "${GUEST_USER}" --password "${GUEST_PASSWORD}" --timeout 10 "true" >/dev/null 2>&1; then
# Use 'if' to suppress set -e so a failed SSH attempt does not abort the loop.
if ssh_output="$(lume ssh "${LUME_VM_NAME}" --user "${GUEST_USER}" --password "${GUEST_PASSWORD}" --timeout 10 "true" 2>&1)"; then
return 0
fi
ssh_exit=$?
log "wait_for_ssh attempt ${attempt}/60: exit=${ssh_exit} output=[${ssh_output}]"
sleep 5
done

Expand Down Expand Up @@ -129,8 +138,10 @@ upload_env_file() {
render_guest_runner_env() {
local env_path="$1"
local temp_env
local runner_path

temp_env="$(mktemp)"
runner_path="${RUNNER_PATH:-$(default_guest_runner_path)}"
Comment thread
jmcte marked this conversation as resolved.
(
set -a
# shellcheck disable=SC1090
Expand All @@ -147,6 +158,7 @@ RUNNER_LABELS=${RUNNER_LABELS}
RUNNER_NAME=${RUNNER_NAME}
RUNNER_ROOT=${RUNNER_ROOT}
RUNNER_WORK_DIR=${RUNNER_WORK_DIR}
RUNNER_PATH=${runner_path}
RUNNER_VERSION=${RUNNER_VERSION}
RUNNER_DOWNLOAD_URL=${RUNNER_DOWNLOAD_URL:-}
EOF
Expand All @@ -158,3 +170,35 @@ EOF
vm_exists() {
lume get "${LUME_VM_NAME}" --format json $(storage_args) >/dev/null 2>&1
}

spawn_detached() {
local log_path="$1"
shift

python3 - "${log_path}" "$@" <<'PY'
import os
import sys

log_path = sys.argv[1]
command = sys.argv[2:]

pid = os.fork()
if pid:
print(pid)
sys.exit(0)

os.setsid()

stdin_fd = os.open("/dev/null", os.O_RDONLY)
log_fd = os.open(log_path, os.O_WRONLY | os.O_CREAT | os.O_APPEND, 0o644)

os.dup2(stdin_fd, 0)
os.dup2(log_fd, 1)
os.dup2(log_fd, 2)

os.close(stdin_fd)
os.close(log_fd)

os.execvp(command[0], command)
PY
}
20 changes: 20 additions & 0 deletions scripts/lume/provision-base-vm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@ set -Eeuo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/lib.sh"

usage() {
cat <<EOF
Usage: $(basename "$0") [options]

Boot the base VM, stream a host Xcode.app into it, and finish first-launch provisioning.

Options:
--config PATH Runner config file (default: $(default_lume_config_path))
--env PATH Env file with GitHub/Lume settings (default: $(default_lume_env_path))
--host-xcode-app DIR Host Xcode app bundle to copy into the guest (default: /Applications/Xcode.app)
--leave-running Leave the base VM running after provisioning
-h, --help Show this help text
EOF
}

config_path="$(default_lume_config_path)"
env_path="$(default_lume_env_path)"
host_xcode_app="/Applications/Xcode.app"
Expand Down Expand Up @@ -48,6 +63,10 @@ trap cleanup EXIT INT TERM

while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help)
usage
exit 0
;;
--config)
config_path="$2"
shift 2
Expand All @@ -65,6 +84,7 @@ while [[ $# -gt 0 ]]; do
shift
;;
*)
usage >&2
echo "unknown argument: $1" >&2
exit 1
;;
Expand Down
Loading
Loading