How Qawk is put together
Qawk has two halves. The bottom half is hawkBit's model, which you may already know and which cannot change without breaking every device. The top half is what Qawk adds, and it is built on the bottom half rather than beside it — which is why none of it requires anything new on a device.
The bottom half: hawkBit's model
Four nouns. Everything a device ever sees is made of them.
| Thing | What it is |
|---|---|
| Target | A device. Identified by its controller id — the name it calls in with. Carries attributes it reports about itself and metadata you set from the outside. |
| Software module | One installable thing with a version, holding one or more artifacts
(the actual files). A module has a type: os,
application, and whatever else you define. |
| Distribution set | A named, versioned bundle of modules — app:1.2.0. This is
the unit a device is given. You never assign a module; you assign a set. |
| Action | One attempt to get one set onto one device. It is created when the set is
assigned, it is active while the device works on it, and it ends
finished or error when the device says so. |
A device is in_sync when what it has installed is what it was
assigned, pending while an action is open, and error
when the last one failed.
Everything reports through the device. Qawk never reaches into a machine. A device polls, is told what to do, does it, and says how it went. Every gate, every threshold, every rollback is driven by those reports — which is also why a device that stops calling in is simply a device Qawk knows nothing new about, rather than a failure.
The top half: what Qawk adds
hawkBit can put a set on a device. It has no opinion about which devices, in what order, under what conditions, or what to do when it goes wrong. That is the part Qawk is.
Channel (a fleet)
A set of devices that should all run the same release. A channel can have a
rule — a query like attribute.ring==beta — and any device
matching it that is in no channel yet joins by itself. So a device
registering for the first time lands where it belongs, from what it says about
itself, with nobody deciding.
Channels chain: beta names dev as its upstream, prod names beta. A release reaches a channel with an upstream only by promotion from it, and only through that channel's gate.
Centre
Where a device physically is — a shop, a site, a bowling centre. The device says
so (attribute.centerid by default) and the centre is put in a
channel. Every device of that centre follows.
This matters more than it sounds. Without it, moving a site from beta to prod means finding its forty machines and moving them one by one, and getting it wrong silently. With it, you move the place, and the lane computers, the terminals and the standalone machines all go together — because they belong to the place, not to a list someone maintains.
System
Devices that only make sense updated together. A lane computer and the two terminals bolted to it are one machine to the person using them; they are three targets to hawkBit.
A system type (Mender calls it a topology) says what components the system has and how a device declares which system it is in. A manifest says what each component should run, and in what order. The orchestrator applies the manifest to each system in turn: lower orders first, equal orders together, and if one device fails, the whole system goes back to what it was running.
Release
What a channel runs, and the history of what it was asked to run. A release carries a distribution set for the devices that stand alone and, when the channel has systems, a manifest for those — because a lane computer and the terminal under it cannot share one set.
How they fit together
The awkward question is: if a device is in a channel and a centre and a system, who decides what it runs? The answer is a single rule, and it is worth learning:
A device that belongs to a system is updated by the orchestrator, never by its channel's set. Everything else in the channel gets the channel's set.
So the three layers do not fight:
- The centre decides the channel. If a device's centre is in a channel, that is the device's channel. You cannot move it elsewhere by hand — its centre would take it straight back — though you can lend it to a temporary channel.
- The channel decides the release. Which distribution set, and which manifest.
- Being in a system decides who delivers it. Standalone devices take the set from the channel. System members take their components' sets from the orchestrator, in the manifest's order.
And a release is only complete when both halves are done: the standalone devices are on the set and the orchestrator has finished with the systems. The next gate checks both, so a release cannot be promoted out of a channel whose systems it never actually reached.
The engine
None of this happens when you press a button. Pressing a button records an intention; a background loop makes it true, every ten seconds:
- channels adopt the devices their rules match;
- centres pull their devices into their channel, a hundred at a time;
- each channel's release goes to the members that do not have it, all at once or in waves, halting by itself over the error threshold;
- the orchestrator steps every running system deployment, and picks up the systems that joined a channel since — a centre moved in this morning is taken this afternoon, without anyone starting anything;
- a channel set to promote itself checks its gate and promotes when it opens.
With several instances of Qawk on one database, exactly one runs that loop: they elect a leader through PostgreSQL, and another takes over within ten seconds if it stops. See Scaling.
A device with an action under way is waited for, never overtaken. A forced assignment cancels a running action — and a system half armed, or an application half live, would lose the deployment it belongs to. So the channel reaches a busy device on the next pass instead. This is why a wave sometimes appears to skip a machine and pick it up a minute later: it is deliberate.
Glossary
| Term | Means |
|---|---|
| action | One attempt to put one distribution set on one device. |
| artifact | A file inside a software module. What actually downloads. |
| attribute | Something a device says about itself, in configData. attribute.ring, attribute.centerid. |
| centre | Where a device is. Put in a channel; its devices follow. |
| channel / fleet | The same thing. Devices that should run the same release. "Fleet" is the name in the API and the console; "channel" is the name in this documentation when the pipeline is the point. |
| component | One role inside a system type — device1, device2 — with a query saying which devices fill it. |
| controller id | A device's identity. What it calls in with. |
| DDI | hawkBit's Direct Device Integration API: what devices speak. |
| distribution set | A named, versioned bundle of software modules. The unit assigned to a device. |
| freeze | A period in which no release reaches a channel. |
| gate | What a channel's upstream must show before a release may be promoted in. |
| manifest | What each component of a system type should run, and in what order. |
| metadata | Something you set on a device from the outside, as opposed to what it reports. |
| promotion | Moving a release from one channel to the next, through the gate. |
| release | What a channel runs: a set, optionally a manifest, and the history of both. |
| rollout | hawkBit's own staged deployment, with groups and thresholds. A different tool from channels; Qawk has both. |
| run | One system inside a system deployment. |
| soft / forced | Whether the device may choose when to install, or is told to do it now. |
| system | Devices that work together and are updated as one. |
| system deployment | Applying a manifest to some systems, a few at a time. |
| target | hawkBit's word for a device. |
| topology | Mender's word for a system type. |
| wave | A share of a channel's members given the release at a time. |