# Full System Updates
Enable adding, deleting, and resizing eMMC and SSD GPT partitions.
## Motivation
The current partition layout does not adequately support fast-paced development for Orb-specific
software such as _orb-core_ or any of the AI packages. As this software is currently bundled
together into the root filesystem or _var_ partition, updating any individual component forces a
larger update that comes with a significant bandwidth cost (even compressed).
Enabling the Orb to fully update its partition layout and all the data therein also enables
Over-the-Air update channels to work more effictively. At present, it is possible for an Orb to
enter into an unstable state, as version numbers across channels are not effectively equivalent. By
enabling a full system update upon any channel swap, we can guarantee that all software versions
running on an Orb belong to one channel and their inter-play known.
Resizing and re-allocating space between partitions allows for issues such as the undersized
_PERSISTENT_ partition to be resolved. Though hopefully rare, the partition table is likely to
change as the needs of the software change, and it is crucial that such changes be well supported
and battle tested as early on as possible.
## Guide-level explanation
The update system supports two fundamental types of updates: partial and full. A partial update
relies the state of previous updates to achieve a desired full system end state. A full update
expects no prior state and rewrites the entire system save for the recovery partition to entirely
match the desired outcome.
Including a full system update into a partial update involves adding a few key components and files
to the update package:
- GPT header and partition entry array (one for eMMC, one for SSD)
- Component files for components which have not changed in this release
- Full versions file (this should match the `standard.json`'s 'target' values)
- Full components file (with GPT components, should match GPT headers)
### Full update packaging vs. partial update
We start with an update from `v1.0.6` _(amorous-albatross)_ to `v1.0.8` _(chiseled-chinchilla)_,
which looks something like the following (labels in parenthesis denote component versions)
```
v1.0.8.tar.gz
├── mainboard.cmp (v1.0.8)
├── manifest.json
├── manifest.json.sig
├── rootfs.cmp (v1.0.8)
├── security.cmp (v0.4.8)
├── standard.json
└── var.cmp (v0.4.8)
```
This update relies on state defined in the `standard.json`, which specifies the acceptable versions
of which are not being update. For the above release, it looks like:
```json
{
"expected": {
"jetson": {
"init": "1.0.6",
"rootfs": "1.0.6",
"var": "1.0.6", (technically this would actually be 1.0.6+patch)
"cuda": "32.6.1",
"cboot": "32.6.1",
"cboot_dtb": "32.6.1",
"secure_os": "32.6.1",
"cboot_cfg": "32.6.1"
},
"mcu": {
"mainboard": "0.3.2",
"security": "0.3.2"
}
},
"target": {
"jetson": {
"init": "1.0.6",
"rootfs": "1.0.8",
"var": "1.0.8",
"cuda": "32.6.1",
"cboot": "32.6.1",
"cboot_dtb": "32.6.1",
"secure_os": "32.6.1",
"cboot_cfg": "32.6.1"
},
"mcu": {
"mainboard": "0.4.8",
"security": "0.4.8"
}
}
}
```
When building the v1.0.8 _partial_ update, components that were not updated in the v1.0.8 release
wouldn't be included. With the introduction of full updates, _every update will include the entirety
of the_ `target` _versions_. This will now look like:
```
v1.0.8.tar.gz
├── cboot_cfg.cmp (l4t 32.6.1)
├── cboot.cmp (l4t 32.6.1)
├── cboot_dtb.cmp (l4t 32.6.1)
├── components.json
├── cuda.cmp (l4t 32.6.1)
├── gpt_emmc.cmp (v1.0.8)
├── gpt_nvme.cmp (v1.0.8)
├── init.cmp (v1.0.6)
├── mainboard.cmp (v0.4.8)
├── manifest.json
├── manifest.json.sig
├── manifest.full.json
├── manifest.full.json.sig
├── rootfs.cmp (v1.0.8)
├── secure_os.cmp (l4t 32.6.1)
├── security.cmp (v0.4.8)
├── standard.json
├── var.cmp (v1.0.8)
└── versions.json
```
Referring back to the beginning of this section, the full system update packages include a few significant files:
- `manifest.json` and `manifest.full.json`
- `gpt_emmc.cmp` and `gpt_nvme.cmp`
- `versions.json` and `components.json`
With the rollout of these full system update packages, the backend will send the full updates in a
few different circumstances. The most common example is channel switching; when an Orb switches from
one channel to another, there is no guarantee that the version numbers on one channel convey the
same meaning that they do on another (i.e. _testing/1.0.1_ might not be the same as
_production/1.0.1_). On those cases, the response from the backend when an Orb requests an update
will change _very_ slightly to instruct the Orb on what the update behavior should be:
```json
{
"update": true,
"manifest": { (this is built using the manifest.full.json)
"magic": "W0r1dC01n",
"type": "system", (changed from "standard")
"components": [
{
"name": "rootfs",
"version-assert": "1.0.6",
"version": "1.0.8",
"size": 183788,
"hash": "..."
},
{
"name": "init",
"version-assert": "0.0.0",
...
},
...
]
},
"manifest-sig": "..."
"urls": {
"rootfs": "https://..."
...
},
}
```
With the `type` in the _manifest.json.full_ set to `system` instead of `standard`, the Orb will run
through the full system update flow after downloading the components.