Tutorial: Run Your First Scenario¶
This tutorial walks you through deploying and running the built-in helloworld example scenario that is included in the examples/ directory. By the end, you will understand Pullpiri's core resource model and how to submit and monitor a workload.
Back to: Getting Started
Prerequisite: Pullpiri must be installed and all containers must be inRunningstate. Follow the Quick Start or Build from Source guide first. Ensure the required ports (8080, 47001–47007, 47098–47099) are open in your firewall — see Open Required Ports.
Background: The Resource Model¶
Every workload in Pullpiri is described by a stack of three Kubernetes-style resources defined in a single YAML file:
Scenario ──▶ defines trigger condition + action
└── Package ──▶ groups Models and defines deployment pattern
└── Model ──▶ defines the actual container workload (pod spec)
| Resource | Role |
|---|---|
Scenario |
Declares when to act (condition) and what to do (action: launch / update / delete) |
Package |
Groups one or more Model resources and specifies the node(s) to deploy to |
Model |
Kubernetes Pod-like spec describing the container image, network, restart policy, etc. |
Step 1: Verify Pullpiri is Running¶
Before running a scenario, confirm that all Pullpiri services are healthy:
Verify the nodeagent systemd service:
systemctl status nodeagent.service
# ● nodeagent.service - Pullpiri NodeAgent Service
# Active: active (running) ...
Check the API server log:
Check the player gateway log:
podman logs pullpiri-filtergateway
# FilterGatewayManager init
# Pullpirid gateway listening on 0.0.0.0:47002
Step 2: Examine the Example Scenario¶
Navigate to the examples/resources/ directory:
ls examples/resources/
# helloworld.yaml (with DDS condition)
# helloworld_no_condition.yaml (no condition, launches immediately)
# helloworld_policy.yaml (with policy)
# parameter-test.yaml
# schedule-test.yaml
For this tutorial we use helloworld_no_condition.yaml, which launches the workload immediately without requiring a DDS signal condition.
View the file:
apiVersion: v1
kind: Scenario
metadata:
name: helloworld
spec:
condition: null # No trigger condition → deploy immediately
action: launch # Action: launch the Package
target: helloworld # Name of the Package to launch
---
apiVersion: v1
kind: Package
metadata:
name: helloworld
spec:
pattern:
- type: plain
models:
- name: helloworld
node: HPC # ← Replace with your node hostname
resources:
volume:
network:
---
apiVersion: v1
kind: Model
metadata:
name: helloworld
annotations:
io.pullpiri.annotations.package-type: helloworld
io.pullpiri.annotations.package-name: helloworld
io.pullpiri.annotations.package-network: default
labels:
app: helloworld
spec:
hostNetwork: true
containers:
- name: helloworld
image: quay.io/podman/hello:latest # Simple hello-world container
terminationGracePeriodSeconds: 0
restartPolicy: Always
Note: The
nodefield inPackage.spec.models[].nodemust match your host's hostname (or the name in/etc/pullpiri/settings.yaml).
Step 3: Set Your Node Name¶
Check your current hostname:
If your hostname differs from HPC, update the node field in the YAML file:
# Replace HPC with your actual hostname
sed -i "s/node: HPC/node: $(hostname)/" examples/resources/helloworld_no_condition.yaml
Verify the change:
Step 4: Submit the Scenario¶
Option A – Use the Provided Shell Script¶
The examples/ directory includes a ready-to-use script:
This script automatically detects the host IP and submits the scenario via the REST API:
# helloworld.sh contents:
# BODY=$(< ./resources/helloworld_no_condition.yaml)
# HOST_IP=$(hostname -I | awk '{print $1}')
# curl -X POST "http://${HOST_IP}:47099/api/artifact" \
# --header 'Content-Type: text/plain' \
# --data "${BODY}"
Option B – Submit Manually with curl¶
HOST_IP=$(hostname -I | awk '{print $1}')
curl -X POST "http://${HOST_IP}:47099/api/artifact" \
--header 'Content-Type: text/plain' \
--data-binary @examples/resources/helloworld_no_condition.yaml
A successful submission returns 200 OK.
Step 5: Verify the Workload is Running¶
After a few seconds, check that the container has been started by nodeagent:
podman ps
# CONTAINER ID IMAGE COMMAND ... NAMES
# 39ab0e9e945f quay.io/podman/hello:latest ... ... helloworld-helloworld
Check the container logs:
Expected output:
!... Hello Podman World ...!
.--"--.
/ - - \
/ (O) (O) \
~~~| -=(,Y,)=- |
.---. /` \ |~~
~/ o o \~~~~.----. ~~
| =(X)= |~ / (O (O) \
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Note: Since
restartPolicy: Alwaysis set, this container restarts continuously. This is expected behavior for the helloworld example.
Step 6: Monitor via API Server¶
You can also query the current state of all submitted artifacts through the API server.
Note: The API server does not expose individual
/api/scenarioor/api/packageGET endpoints. Use theGET /api/notifyendpoint to check connectivity, and query stored data via the RocksDB inspector tool (src/tools/rocksdb-inspector) or by checking service logs.
HOST_IP=$(hostname -I | awk '{print $1}')
# Verify API server is reachable
curl -X GET "http://${HOST_IP}:47099/api/notify"
# Submit a new artifact
curl -X POST "http://${HOST_IP}:47099/api/artifact" \
--header 'Content-Type: text/plain' \
--data-binary @examples/resources/helloworld_no_condition.yaml
# Check apiserver logs for artifact processing
podman logs pullpiri-apiserver
# Check policymanager logs
podman logs pullpiri-policymanager
Step 7: Try a Scenario with a Condition¶
The helloworld.yaml file demonstrates a conditional scenario: the workload is launched only when a DDS signal matches the specified condition.
apiVersion: v1
kind: Scenario
metadata:
name: helloworld
spec:
condition:
express: eq
value: "true"
operands:
type: DDS
name: value
value: ADASObstacleDetectionIsWarning
action: update
target: helloworld
This scenario:
- Listens for the DDS topic ADASObstacleDetectionIsWarning
- Triggers the update action on the helloworld Package when the signal value equals "true"
To submit this scenario (requires a running DDS environment):
HOST_IP=$(hostname -I | awk '{print $1}')
curl -X POST "http://${HOST_IP}:47099/api/artifact" \
--header 'Content-Type: text/plain' \
--data-binary @examples/resources/helloworld.yaml
Step 8: Remove the Scenario¶
To stop and remove the workload, send the same YAML via DELETE /api/artifact.
The API server searches for a Scenario kind in the body and removes it:
HOST_IP=$(hostname -I | awk '{print $1}')
curl -X DELETE "http://${HOST_IP}:47099/api/artifact" \
--header 'Content-Type: text/plain' \
--data-binary @examples/resources/helloworld_no_condition.yaml
Note: The DELETE endpoint accepts the whole YAML body (same format as POST). It extracts the
Scenarioresource from it and removes it from storage. There is no URL-path-basedDELETE /api/scenario/{name}endpoint.
Verify the container has been removed:
Summary¶
In this tutorial you:
- Verified that Pullpiri services are running.
- Examined the three-tier resource model: Scenario → Package → Model.
- Submitted the
helloworldscenario using the REST API. - Verified the container workload was started by the nodeagent.
- Learned about conditional scenarios using DDS signal triggers.
- Removed the scenario and confirmed the workload was stopped.
Next Steps¶
- Explore more example scenarios in
examples/resources/ - Read the API Reference to learn all available REST endpoints
- Read the Project Structure to understand how each component works
- Check Development Guide to start contributing
Troubleshooting¶
| Issue | Cause | Solution |
|---|---|---|
curl returns connection refused |
API server not running | Check podman logs pullpiri-apiserver |
| Container not starting after scenario submit | Node name mismatch | Ensure node in YAML matches hostname output |
| Container keeps restarting | restartPolicy: Always is set |
Expected for helloworld demo; change to Never if needed |
podman ps shows no new container |
nodeagent not running | Check systemctl status nodeagent.service or journalctl -u nodeagent.service |