Skip to content
Open
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
16 changes: 16 additions & 0 deletions demos/counter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,22 @@ This command will:
- Create the `WorkerPool` and `ActorTemplate`.
- Wait until the template is ready.

#### Outbound connectivity probe

By default the counter fetches `https://www.google.com/generate_204` every 10
seconds and logs the result, showing that the actor's egress path keeps working
across suspends and resumes. Override or disable the target at deploy time:

```bash
# Probe a custom URL
OUTBOUND_PROBE_URL=http://example.com/health ./hack/install-ate.sh --deploy-demo-counter

# Disable the probe (e.g. air-gapped clusters)
OUTBOUND_PROBE_URL="" ./hack/install-ate.sh --deploy-demo-counter
```

The same variable works for the micro-VM variant (`./hack/run-microvm-demo.sh`).

### 2. Create a Counter Actor

Actors live in an **atespace**, which must exist before you create actors in it. Create one (e.g., `demo`), then create the counter actor with a chosen ID (e.g., `my-counter-1`):
Expand Down
3 changes: 3 additions & 0 deletions demos/counter/counter-microvm.yaml.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ spec:
containers:
- name: counter
image: ko://github.com/agent-substrate/substrate/demos/counter
command:
- /ko-app/counter
${OUTBOUND_PROBE_URL_ARG}
readyz:
httpGet:
path: /readyz
Expand Down
26 changes: 25 additions & 1 deletion demos/counter/counter.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ func main() {
fileCounterDirectory := pflag.String("file-counter-directory", "/home/counter", "Directory for file counter")
secondFileCounterDirectory := pflag.String("second-file-counter-directory", "", "Directory for a second file counter; empty disables it. Used to exercise an Actor with more than one durable volume")
validateExistingFilePath := pflag.String("validate-existing-file-path", "", "Path to existing file to validate reading")
outboundProbeURL := pflag.String("outbound-probe-url", "", "URL fetched on every count tick to demonstrate outbound connectivity (e.g. https://www.google.com/generate_204); empty disables it")
pflag.Parse()
ctx := context.Background()

Expand Down Expand Up @@ -138,13 +139,36 @@ func main() {
slog.InfoContext(ctx, "Count", slog.Int("count", count), slog.String("fshash", hashRandomFile()))
count++

probeClient := &http.Client{Transport: &http.Transport{DisableKeepAlives: true}}
for range time.Tick(10 * time.Second) {
// TODO: Test outbound connectivity by pinging google.com
logOutboundProbe(ctx, probeClient, *outboundProbeURL)
slog.InfoContext(ctx, "Count", slog.Int("count", count), slog.String("fshash", hashRandomFile()))
count++
}
}

// A reachable server counts as connectivity, whatever its status code.
func logOutboundProbe(ctx context.Context, client *http.Client, url string) {
if url == "" {
return
}
probeCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
start := time.Now()
req, err := http.NewRequestWithContext(probeCtx, http.MethodGet, url, nil)
if err != nil {
slog.ErrorContext(ctx, "Outbound probe failed", slog.String("url", url), slog.Any("err", err))
return
}
resp, err := client.Do(req)
if err != nil {
slog.ErrorContext(ctx, "Outbound probe failed", slog.String("url", url), slog.Any("err", err))
return
}
resp.Body.Close()
slog.InfoContext(ctx, "Outbound probe succeeded", slog.String("url", url), slog.Int("status", resp.StatusCode), slog.Duration("elapsed", time.Since(start)))
}

func writeRandomFile() error {
rf, err := os.Create("/random-content-file")
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions demos/counter/counter.yaml.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ spec:
command:
- /ko-app/counter
${VALIDATE_EXISTING_FILE_PATH_ARG}
${OUTBOUND_PROBE_URL_ARG}
readyz:
httpGet:
path: /readyz
Expand Down
9 changes: 9 additions & 0 deletions hack/install-demo-counter.sh
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,18 @@ demo-counter_deploy() {
ext_vol_spec_cmd=("-e" "s|\${EXTERNAL_VOLUMES}| - name: external-data\n externalVolumeTemplate:\n capacity: 1Gi\n storageClassName: standard|g")
fi

# On by default; OUTBOUND_PROBE_URL="" disables (e.g. air-gapped clusters).
local probe_url="${OUTBOUND_PROBE_URL-https://www.google.com/generate_204}"
local probe_cmd=("-e" "/\${OUTBOUND_PROBE_URL_ARG}/d")
if [[ -n "${probe_url}" ]]; then
probe_cmd=("-e" "s|\${OUTBOUND_PROBE_URL_ARG}| - --outbound-probe-url=${probe_url}|g")
fi

sed -e "s|\${BUCKET_NAME}|${BUCKET_NAME}|g" \
"${validate_cmd[@]}" \
"${ext_vol_mount_cmd[@]}" \
"${ext_vol_spec_cmd[@]}" \
"${probe_cmd[@]}" \
demos/counter/counter.yaml.tmpl \
| run_ko apply -f -

Expand All @@ -71,6 +79,7 @@ demo-counter_delete() {
delete_demo_actors ate-demo-counter counter
sed -e "s|\${BUCKET_NAME}|${BUCKET_NAME}|g" \
-e "/\${VALIDATE_EXISTING_FILE_PATH_ARG}/d" \
-e "/\${OUTBOUND_PROBE_URL_ARG}/d" \
-e "/\${EXTERNAL_VOLUME_MOUNTS}/d" \
-e "/\${EXTERNAL_VOLUMES}/d" \
demos/counter/counter.yaml.tmpl \
Expand Down
10 changes: 10 additions & 0 deletions hack/run-microvm-demo.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
# OUT asset dir (default: $PWD/bin/microvm-assets/$ARCH, gitignored).
# ATE_INSTALL_KIND "true" for the kind path (stage assets to rustfs + install-ate-kind.sh);
# default false uploads assets to GCS + uses install-ate.sh.
# OUTBOUND_PROBE_URL
# URL the counter probes every tick (default: google generate_204);
# set to "" to disable, e.g. on air-gapped clusters.

set -o errexit -o nounset -o pipefail

Expand Down Expand Up @@ -149,8 +152,15 @@ log "Applying the counter-microvm demo manifest..."
# (cloud-hypervisor/kernel/rootfs/config, plus virtiofsd on amd64 where upstream
# publishes a prebuilt) keep their committed, reproducible per-arch shas.
VIRTIOFSD_SHA256="$(sha256sum "${OUT}/virtiofsd" | awk '{print $1}')"
# On by default; OUTBOUND_PROBE_URL="" disables (e.g. air-gapped clusters).
probe_url="${OUTBOUND_PROBE_URL-https://www.google.com/generate_204}"
probe_cmd=("-e" "/\${OUTBOUND_PROBE_URL_ARG}/d")
if [[ -n "${probe_url}" ]]; then
probe_cmd=("-e" "s|\${OUTBOUND_PROBE_URL_ARG}| - --outbound-probe-url=${probe_url}|g")
fi
sed -e "s|\${BUCKET_NAME}|${BUCKET_NAME}|g" \
-e "s|\${VIRTIOFSD_SHA256}|${VIRTIOFSD_SHA256}|g" \
"${probe_cmd[@]}" \
demos/counter/counter-microvm.yaml.tmpl \
| ./hack/run-tool.sh ko apply -f - ${KUBECTL_CONTEXT:+-- --context="${KUBECTL_CONTEXT}"}

Expand Down