Skip to content
Closed
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
14 changes: 14 additions & 0 deletions scripts/factory-edge-demo-live.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -168,4 +168,18 @@ grep -q '^FINDING: install-time preparation ran during the demo' <<<"${out}" ||
out="$(fresh; stage ok HYPERVISOR=hvf >/dev/null; demo needs-bootstrap HYPERVISOR=hvf)" && fail "an install that needs bootstrap passed"
grep -q "^FINDING: the install asked for 'mvmctl bootstrap'" <<<"${out}" || fail "no bootstrap finding"

# ---- the one-command runner ----
fresh
out="$(envrun ok factory-edge-run.sh HYPERVISOR=hvf)" || fail "the one-command run failed on a correct product: ${out}"
grep -q '^DEMO_RESULT=pass$' <<<"${out}" || fail "the one-command run printed no pass line: ${out}"
grep -q '^The demo passed in ' <<<"${out}" || fail "the one-command run did not say it passed: ${out}"
[ "$(ls "${work}"/state/m.* 2>/dev/null | wc -l | tr -d ' ')" = 0 ] || fail "the one-command run left staged machines behind"
fresh
out="$(envrun inspection-silent factory-edge-run.sh HYPERVISOR=hvf)" && fail "the one-command run passed although an inspection workload stopped: ${out}"
grep -q '^The demo did not pass' <<<"${out}" || fail "a failing one-command run did not say so: ${out}"
[ "$(ls "${work}"/state/m.* 2>/dev/null | wc -l | tr -d ' ')" = 0 ] || fail "a failing one-command run left staged machines behind"
fresh
out="$(envrun image-missing factory-edge-run.sh HYPERVISOR=hvf)" && fail "the one-command run passed with the image missing: ${out}"
grep -q 'could not be staged' <<<"${out}" || fail "a staging failure was not reported by the one-command run: ${out}"

echo "ok ($n checks per run)"
85 changes: 85 additions & 0 deletions scripts/factory-edge-demo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# The factory-edge demo

Three small programs run side by side on one Mac, and each is allowed to reach
only its own destination. One of them asks for something it was not allowed, the
host refuses and records it, and the other two carry on. Then that program is
stopped and a fresh one takes its place.

## Run it

```sh
scripts/factory-edge-run.sh
```

It takes about 20 seconds. It starts the three programs, runs the demo against
them, and removes them again, even if the demo fails. Nothing is left running.

You need an Apple Silicon Mac on macOS 26 or later with the demo set up (see
"Set up a new Mac" below). Ari's Mac is already set up.

## What you will see

The demo prints one line for each thing it checks. A run that works ends with
`DEMO_RESULT=pass`.

1. The two inspection programs are working, each reaching only its own
destination.
2. The maintenance program asks for a destination it was not allowed. The host
refuses it, and the refusal can be read back afterwards.
3. The two inspection programs are not affected and keep working.
4. The audit record is checked and is intact.
5. The maintenance program is stopped and its session sealed.
6. A replacement starts as a fresh program and carries none of the old refusals.

## If it does not pass

The script stops at the first problem and prints a line starting `FAIL` or
`FINDING` that says what is missing. The usual causes:

- **Not set up.** `mvmctl` is not installed, or the demo home does not exist, or
the test image is not in it. Follow "Set up a new Mac".
- **No network.** Every allowed destination is looked up when its program
starts, so the demo needs working internet and DNS.
- **Something left over.** Run `scripts/factory-edge-stage.sh --down`, then run it
again.

## Set up a new Mac

Do this once, from a checkout of this repository. It installs the release the
demo is verified against and prepares a home for it. The demo never installs or
prepares anything itself.

```sh
MVM_VERSION=v0.28.0-rc.2 MVM_SKIP_BOOTSTRAP=1 sh install.sh
export MVM_HOME="$HOME/.mvm-demo"
mvmctl image pull curlimages/curl:8.21.0
mvmctl run --image curlimages/curl:8.21.0 -- true
```

The last command builds the runtime the first time, which takes a few minutes.
The demo scripts use `~/.mvm-demo` by default, so nothing else needs setting.

## Presenting it

For a live presentation, start the programs ahead of time so the audience sees
only the demo itself:

1. `scripts/factory-edge-stage.sh` about ten minutes before. Staging earlier makes
the audit record, and with it the readback, slower.
2. `scripts/factory-edge-demo-live.sh` for the live part, about 30 seconds.
3. `scripts/factory-edge-stage.sh --down` afterwards.

After a reboot the staged programs are gone, so stage again.

## What this does not show

- The Studio application's own view. The demo drives the command line, and Studio
will do the same things through the `mvm-client` library.
- The real maintenance and inspection tasks. These are small scripted programs
over synthetic traffic.
- Launches under one second. A launch takes a few seconds on this release, and
the replacement in step 6 is a live launch.

More detail, including what was measured and why launches are slow, is in the
factory-edge section of
`specs/contracts/host-interface-distributed-execution.md`.
54 changes: 54 additions & 0 deletions scripts/factory-edge-run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env bash
# Run the whole factory-edge demo with one command: stage the three workloads,
# run the demo against them, and remove them again, even if the demo fails.
#
# scripts/factory-edge-run.sh
#
# This is the version for someone who just wants to see it work. A presenter
# who wants no waiting on stage runs the two scripts separately instead: stage
# about ten minutes ahead with scripts/factory-edge-stage.sh, present with
# scripts/factory-edge-demo-live.sh, then remove with
# scripts/factory-edge-stage.sh --down.
#
# It assumes what the two scripts assume: an installed mvmctl and a prepared
# demo home. Nothing here installs or prepares anything. See
# scripts/factory-edge-demo.md for the one-time setup.
#
# Every setting of the two scripts is passed through (MVMCTL, MVM_HOME,
# HYPERVISOR, IMAGE and the rest). ATTEMPT_AFTER and INSPECT_EVERY default to 3
# and 2 seconds here, so the maintenance workload makes its request soon after
# staging and the inspection workloads report often, and the run does not wait.
# A presenter staging ahead wants longer ones, because every lookup is a signed
# audit entry and the record grows for as long as the workloads run; a run of
# about a minute does not grow it meaningfully.
#
# The exit status is the demo's: 0 only if every check passed.
set -uo pipefail

here="$(cd "$(dirname "$0")" && pwd)"
export ATTEMPT_AFTER="${ATTEMPT_AFTER:-3}" INSPECT_EVERY="${INSPECT_EVERY:-2}"

# Remove the staged workloads on any exit, including an interrupt.
cleanup() {
"$here/factory-edge-stage.sh" --down >/dev/null 2>&1 || true
}
trap cleanup EXIT
trap 'exit 130' INT TERM

t0=$SECONDS
echo "Step 1 of 2: staging the three workloads"
"$here/factory-edge-stage.sh" || { echo "The workloads could not be staged, so the demo was not run." >&2; exit 1; }

staged_in=$((SECONDS - t0))
echo
echo "Step 2 of 2: running the demo"
"$here/factory-edge-demo-live.sh"
status=$?

echo
if [ "$status" -eq 0 ]; then
echo "The demo passed in $((SECONDS - t0)) seconds ($staged_in to stage, the rest to run). The staged workloads have been removed."
else
echo "The demo did not pass (see the line starting FAIL or FINDING above). The staged workloads have been removed." >&2
fi
exit "$status"
14 changes: 9 additions & 5 deletions scripts/factory-edge-stage.sh
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,16 @@ staged_at="$(python3 -I -c "from datetime import datetime, timezone; print(datet
# An inspection workload's work: send a result to its granted destination, repeatedly.
inspect() { echo "while true; do curl -sS -m 10 -o /dev/null https://$1/ >/dev/null 2>&1; sleep $INSPECT_EVERY; done"; }
start() { # <name> <grant> <script>
mvm run -d --image "$IMAGE" --hypervisor "$HYPERVISOR" --name "$1" --allow-host "$2" -- sh -c "$3" >/dev/null </dev/null \
|| fail "could not start $1"
mvm run -d --image "$IMAGE" --hypervisor "$HYPERVISOR" --name "$1" --allow-host "$2" -- sh -c "$3" >/dev/null </dev/null
}
start "$LINE_A" "$GRANT_A" "$(inspect "${GRANT_A%%:*}")"
start "$LINE_B" "$GRANT_B" "$(inspect "${GRANT_B%%:*}")"
start "$MAINT" "$APPROVED" "sleep $ATTEMPT_AFTER; while true; do curl -sS -m 10 https://$UNAPPROVED/ >/dev/null 2>&1; sleep $ATTEMPT_EVERY; done"
# The three starts do not depend on each other, so run them together: one after
# another, each would wait out its own launch.
start "$LINE_A" "$GRANT_A" "$(inspect "${GRANT_A%%:*}")" & pid_a=$!
start "$LINE_B" "$GRANT_B" "$(inspect "${GRANT_B%%:*}")" & pid_b=$!
start "$MAINT" "$APPROVED" "sleep $ATTEMPT_AFTER; while true; do curl -sS -m 10 https://$UNAPPROVED/ >/dev/null 2>&1; sleep $ATTEMPT_EVERY; done" & pid_m=$!
wait "$pid_a" || fail "could not start $LINE_A"
wait "$pid_b" || fail "could not start $LINE_B"
wait "$pid_m" || fail "could not start $MAINT"
for m in "$LINE_A" "$LINE_B" "$MAINT"; do until_ok "$m to be running" is_running "$m"; done
say "all three workloads are running"
for m in "$LINE_A" "$LINE_B"; do until_ok "the host to record $m's lookup of its granted destination" allowed_for "$m"; done
Expand Down
Loading