mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-01 14:34:42 +01:00
fix(ubicloud): ubi-runner up/run -S accepts only Ubicloud's storage sizes, before any API call (A11)
Files: scripts/ubicloud/ubi-runner.sh, test/ubicloud-runner.test.ts Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
47d639abff
commit
bfbb1dfb5e
2 files changed
+40
-3
No files matched your search
@@ -51,6 +51,7 @@ API_TIMEOUT="${UBI_API_TIMEOUT:-120}"
|
||||
CREATE_GRACE="${UBI_CREATE_GRACE:-180}"
|
||||
DOWN_TIMEOUT="${UBI_DOWN_TIMEOUT:-900}"
|
||||
POLL="${UBI_POLL_SECONDS:-5}"
|
||||
ALLOWED_STORAGE="${UBI_ALLOWED_STORAGE:-320 640}"
|
||||
PREFIX="ubirun"
|
||||
if [ -n "${UBI_VM_RECORD:-}" ]; then VM_RECORD="$UBI_VM_RECORD"
|
||||
elif [ -d "$HOME/.capy/work" ]; then VM_RECORD="$HOME/.capy/work/ubi-runner/vms.tsv"
|
||||
@@ -229,6 +230,14 @@ new_name() { echo "$PREFIX-$OWNER-$(date +%s)-$(head -c4 /dev/urandom | od -An -
|
||||
|
||||
valid_name() { [[ "$1" =~ ^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$ ]]; }
|
||||
|
||||
# check_storage GIB: Ubicloud accepts only these disk sizes; refuse before any API call.
|
||||
check_storage() {
|
||||
case " $ALLOWED_STORAGE " in
|
||||
*" $1 "*) [ -n "$1" ] && return 0 ;;
|
||||
esac
|
||||
die "invalid storage '$1' GiB (allowed: $ALLOWED_STORAGE; set UBI_ALLOWED_STORAGE when Ubicloud adds sizes)"
|
||||
}
|
||||
|
||||
UP_NAME=""
|
||||
UP_READY=""
|
||||
cmd_up() {
|
||||
@@ -238,7 +247,7 @@ cmd_up() {
|
||||
-s|--size) size=$2; shift 2 ;;
|
||||
-l|--location) location=$2; shift 2 ;;
|
||||
-n|--name) name=$2; shift 2 ;;
|
||||
-S|--storage) storage=$2; shift 2 ;;
|
||||
-S|--storage) check_storage "$2"; storage=$2; shift 2 ;;
|
||||
-b|--image) image=$2; shift 2 ;;
|
||||
*) die "up: unknown option $1" ;;
|
||||
esac
|
||||
@@ -430,7 +439,8 @@ cmd_run() {
|
||||
local up_args=() src=. dest="" setup="" keep=0 pulls=() envs=()
|
||||
while [ $# -gt 0 ]; do
|
||||
case $1 in
|
||||
-s|--size|-l|--location|-n|--name|-S|--storage|-b|--image) up_args+=("$1" "$2"); shift 2 ;;
|
||||
-S|--storage) check_storage "$2"; up_args+=("$1" "$2"); shift 2 ;;
|
||||
-s|--size|-l|--location|-n|--name|-b|--image) up_args+=("$1" "$2"); shift 2 ;;
|
||||
--src) src=$2; shift 2 ;;
|
||||
--dest) dest=$2; shift 2 ;;
|
||||
--setup) setup=$2; shift 2 ;;
|
||||
@@ -498,6 +508,7 @@ usage: ubi-runner.sh <command> [args]
|
||||
up + sync + setup + command + pull + destroy; exits with COMMAND's status
|
||||
up [-s SIZE] [-l LOCATION] [-n NAME] [-S STORAGE_GIB] [-b IMAGE]
|
||||
create a VM and wait for SSH; prints its name
|
||||
(STORAGE_GIB: one of $ALLOWED_STORAGE)
|
||||
ssh NAME [COMMAND] shell or login-shell command on the VM (user ubi, passwordless sudo)
|
||||
sync NAME [SRC] [DEST] stream a checkout (tracked + untracked-unignored + .git)
|
||||
pack [SRC] write that checkout tarball to stdout
|
||||
@@ -516,7 +527,8 @@ VMs are named $PREFIX-<owner>-<epoch>-<suffix>; set UBI_OWNER (e.g. your thread
|
||||
code) to tag them, otherwise a per-machine id is used.
|
||||
defaults: size=$DEFAULT_SIZE location=$DEFAULT_LOCATION (env UBI_SIZE, UBI_LOCATION)
|
||||
env: UBI_GC_HOURS (unset/0: no sweep on up), UBI_CREATE_GRACE (${CREATE_GRACE}s),
|
||||
UBI_DOWN_TIMEOUT (${DOWN_TIMEOUT}s), UBI_API_TIMEOUT (${API_TIMEOUT}s), UBI_VM_RECORD (scratch VM-id file)
|
||||
UBI_DOWN_TIMEOUT (${DOWN_TIMEOUT}s), UBI_API_TIMEOUT (${API_TIMEOUT}s), UBI_VM_RECORD (scratch VM-id file),
|
||||
UBI_ALLOWED_STORAGE (the -S sizes Ubicloud accepts; default "320 640")
|
||||
EOF
|
||||
}
|
||||
|
||||
|
||||
@@ -92,6 +92,31 @@ describe('ubicloud free-suite runner', () => {
|
||||
expect(result.stderr.toString()).toContain('UBICLOUD_API_KEY is not set');
|
||||
expect(result.stdout.toString()).toBe('');
|
||||
});
|
||||
|
||||
test('up and run accept only the storage sizes Ubicloud offers, before any API call; UBI_ALLOWED_STORAGE widens the list', () => {
|
||||
const root = mkdtempSync(join(tmpdir(), 'ubi-storage-'));
|
||||
try {
|
||||
const bin = join(root, 'bin'), log = join(root, 'curl.log');
|
||||
mkdirSync(bin);
|
||||
writeFileSync(join(bin, 'curl'), `#!/usr/bin/env bash\necho "curl $*" >> ${JSON.stringify(log)}\necho 000\n`);
|
||||
chmodSync(join(bin, 'curl'), 0o755);
|
||||
const env = { ...process.env, PATH: `${bin}:${process.env.PATH}`, UBICLOUD_API_KEY: 'offline', UBI_RUNNER_STATE: join(root, 'state'), UBI_VM_RECORD: join(root, 'vms.tsv'), UBI_OWNER: 't' };
|
||||
const ubi = (args: string[], extra: Record<string, string> = {}) => Bun.spawnSync(['bash', join(DIR, 'ubi-runner.sh'), ...args], { env: { ...env, ...extra }, timeout: 10_000 });
|
||||
for (const args of [['up', '-S', '100'], ['run', '--storage', '1000', '--', 'true'], ['up', '-S', '']]) {
|
||||
const r = ubi(args);
|
||||
expect(r.exitCode).toBe(1);
|
||||
expect(r.stderr.toString()).toContain('(allowed: 320 640; set UBI_ALLOWED_STORAGE when Ubicloud adds sizes)');
|
||||
}
|
||||
expect(existsSync(log)).toBe(false);
|
||||
for (const [size, extra] of [['320', {}], ['1280', { UBI_ALLOWED_STORAGE: '320 640 1280' }]] as const) {
|
||||
const accepted = ubi(['run', '-S', size, '--bogus'], extra);
|
||||
expect(accepted.stderr.toString()).toContain('run: unknown option --bogus');
|
||||
}
|
||||
expect(existsSync(log)).toBe(false);
|
||||
} finally {
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('ubi-runner teardown is confirmed and never sweeps other runners by default', () => {
|
||||
|
||||
Reference in new issue
Block a user