Get started
In five minutes you will have a server, a database, a console and about three hundred simulated devices updating themselves, with nothing to configure and nothing to buy.
What Qawk is, in one paragraph
Qawk hands software to devices over the air. Devices call in on a schedule and ask "anything for me?"; Qawk answers with a link to download and install, and the device reports back how it went. That much is Eclipse hawkBit, whose protocols Qawk speaks exactly, so existing devices and tools work unchanged. On top of it Qawk adds the parts a real fleet needs: channels a release moves through under conditions, centres so you move a place rather than a list of machines, and an orchestrator for machines that only make sense updated together.
Try it in five minutes
You need docker, python3 and curl, and ports 8080 and 8090 free. Nothing is installed on your machine outside Docker, and the demo keeps no data.
git clone https://github.com/padovanl/qawk.git
cd qawk
demo/start.sh
That builds two images, starts PostgreSQL, the server and the console, loads
sample data and starts simulated devices. When it settles, open
http://localhost:8090 and sign in as admin /
changeme.
What you just started
- A catalogue:
app1.0.0 to 1.2.0,app-broken1.3.0 (the simulated devices fail anything named broken, on purpose),os,device2-fw,device3-fw. - Channels
dev→beta→prod(prod needs an approval) and a temporaryexpo. - About 270 simulated devices spread across those channels, and 16 simulated
systems — a
device1with twodevice2and adevice3each. - Four centres, each holding both kinds of machine:
c01andc02inbeta,c03andc04inprod. Every device in them reports itscenteridand follows its centre — which is how a real fleet is arranged.devandexpohave no centre and reach their channel by rule instead. devhas already been givenapp1.1.0, so something is moving the moment you open the page.
demo/start.sh seed # load the sample data again
demo/start.sh down # stop and remove everything
Everything is configurable. QAWK_ADMIN_PASSWORD,
QAWK_PORT, CONSOLE_PORT, PROD_DEVICES,
SYSTEMS, USERS_FILE. The same thing with docker compose
is in demo/compose.yml.
Run it yourself, with the smallest configuration there is
The demo above is a toy with sample data in it. This is the real thing: a server, a database and a console, and nothing else. Two commands' worth of configuration — a database URL and an administrator password.
A. From Docker Hub
Nothing to build. Two images, one network, one command each.
docker pull padovanl/qawk:0.1.0 # the server, with qawk-sim and qawk-load
docker pull padovanl/qawk-console:0.1.0 # the console
docker network create qawk
docker run -d --name qawk-db --network qawk --restart unless-stopped \
-v qawk-db:/var/lib/postgresql/data \
-e POSTGRES_USER=qawk -e POSTGRES_PASSWORD='db-secret' -e POSTGRES_DB=qawk \
postgres:16-alpine
docker run -d --name qawk --network qawk --restart unless-stopped -p 8080:8080 \
-v qawk-artifacts:/var/lib/qawk \
-e QAWK_DATABASE_URL='postgres://qawk:db-secret@qawk-db:5432/qawk?sslmode=disable' \
-e QAWK_ADMIN_PASSWORD='a-long-admin-password' \
padovanl/qawk:0.1.0
docker run -d --name qawk-console --network qawk --restart unless-stopped -p 8090:8090 \
-e HB_URL=http://qawk:8080 \
padovanl/qawk-console:0.1.0
Open http://localhost:8090 and sign in as admin with the
password you just set. On its first start Qawk creates its own schema, the
built-in roles and hawkBit's default types — there is no migration step to run and
no schema to load.
Set QAWK_ADMIN_PASSWORD. Without it the administrator's
password is admin. That administrator is never stored in the
database: it always works, which is how a new server is set up and how a lost
password is fixed — and why the password must not be the default on anything
reachable.
B. Built from this repository
You need only Docker. The server's image builds its own Go toolchain stage, and the console has nothing to install at all — no npm, no bundler, no build step.
git clone https://github.com/padovanl/qawk.git
cd qawk
docker build -t qawk:local server/
docker build -t qawk-console:local console/
Then run exactly the three docker run commands above, with
qawk:local and qawk-console:local in place of the Docker
Hub names.
To publish under your own namespace, give the server its version — it reports it
at /qawk/v1/info and on the console's About page — and push both with
the same tag:
V=0.1.0
docker build --build-arg VERSION=$V -t <you>/qawk:$V server/
docker build -t <you>/qawk-console:$V console/
docker push <you>/qawk:$V
docker push <you>/qawk-console:$V
C. With docker compose
A compose.yml with the same three services and nothing else:
name: qawk
services:
db:
image: postgres:16-alpine
restart: unless-stopped
volumes: ["db:/var/lib/postgresql/data"]
environment:
POSTGRES_USER: qawk
POSTGRES_PASSWORD: db-secret
POSTGRES_DB: qawk
server:
image: padovanl/qawk:0.1.0
restart: unless-stopped
ports: ["8080:8080"]
volumes: ["artifacts:/var/lib/qawk"]
environment:
QAWK_DATABASE_URL: postgres://qawk:db-secret@db:5432/qawk?sslmode=disable
QAWK_ADMIN_PASSWORD: a-long-admin-password
depends_on: [db]
console:
image: padovanl/qawk-console:0.1.0
restart: unless-stopped
ports: ["8090:8090"]
environment:
HB_URL: http://server:8080
depends_on: [server]
volumes: { db: {}, artifacts: {} }
docker compose up -d
The demo's own compose file, with the sample data and the simulated devices
wired in, is demo/compose.yml in the repository.
D. Without Docker at all
The server is one static binary and the console is a Python script. If you have Go 1.25 and a PostgreSQL to point at:
cd server && go build -o qawk ./cmd/qawk
QAWK_DATABASE_URL='postgres://qawk:qawk@localhost:5432/qawk?sslmode=disable' \
QAWK_ADMIN_PASSWORD='a-long-admin-password' ./qawk
# in another terminal
python3 console/serve.py --port 8090 --hawkbit http://localhost:8080
The two things to back up
The database and the artifact directory (/var/lib/qawk
in the image). Everything else is rebuilt from them. Full configuration, TLS,
Kubernetes and upgrades are in Installing the server.
Your first update
Four things worth doing, in order. Each takes a minute and each shows you one of the ideas Qawk is built on.
- Watch a release reach a channel.
Open Fleets.devis runningapp:1.1.0and its bar is filling as the simulated devices take it. Clickdevto open its drawer: the members, what each runs, what each was given. - Promote it to beta.
Still in Fleets, press promote onbeta. Qawk shows you the gate first — a ✓ or a ✗ per condition — and refuses if it is closed, telling you exactly which line failed. When it opens, promote, and watch beta fill in waves. - Break something on purpose.
Givedevthe releaseapp-broken:1.3.0. The simulated devices fail anything named broken. Within a minute the release halts by itself: failures passed dev's error threshold, and no further device is sent it. Press resume and the failures already seen stop counting — only new ones can halt it again. - Update sixteen systems as sixteen wholes.
Open Systems and deploy the manifestdevice-system-2.0. Each system's terminals go first, its lane computer second — the manifest's order — and one system that fails takes itself back to what it ran before while the other fifteen carry on. That is the orchestrator, and it is the part hawkBit has no answer for.
There is no hardware anywhere in this
Every device above is qawk-sim: a program that registers, reports
the attributes a real device would, polls, takes what it is given, waits a random
while and says how it went. It is not a mock inside the server — it speaks the real
device API over the real network, so what you are watching is the real thing with
the hardware replaced. All three hundred of them live in one container: there is
no operating system and no application inside a simulated device, and it
simulates only the installation and the rollback — it never downloads the
artifact, it sleeps instead of installing, and a failed one simply says it rolled
back. Everything the server decides is real;
what is real and what is pretended is set out
in full under Connecting devices.
You can point it at any Qawk server, not only the demo's:
# 50 devices reporting ring=lab, polling every 30 s
demo/simulate.sh --url http://localhost:8080 --token <gateway token> --fleet lab:50
# 16 systems -- a device1 with two device2 and a device3 -- in four centres
demo/simulate.sh --name centres --url http://localhost:8080 --token <token> --systems 16
demo/simulate.sh --list # what is running
demo/simulate.sh --stop # stop it all
More, including how to make devices fail on demand so you can watch halts, thresholds and rollbacks, is in Connecting devices.
Next
If you are going to use Qawk, read Using the console. If you are going to run it, read Installing the server. If you want to know how the pieces fit before either, read Concepts.