1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
|
===================================
Snappy Transactional System Updates
===================================
.. contents::
.. sectnum::
Introduction
------------
This document provides an overview of how system-level updates are
applied to a snappy system, and how the system boot operates.
System-level updates
--------------------
Unlike a traditional Ubuntu system where individual packages are updated
as required, a snappy system is split into two logical pieces:
* The read-only minimal base system
This comprises required configuration file, standard directories,
libraries, utilities and core system services.This portion of the
system is read-only and individual elements cannot be updated. It is
known as a "system image". There are up to two system images available
on a snappy system.
* The writable apps ("snaps") and frameworks part of the system.
These make use of services provided by the base system.
Root partitions
---------------
The base system is embodied conventionally by a root filesystem
(containing a system image) on a separate disk partition. However,
unlike a standard Ubuntu system, a snappy system has dual read-only root
filesystem partitions (two system images).
Snappy manages these "A/B" system partitions which are used both to:
* Allow a root partition to be updated as a single unit (by applying a
new system image).
* Support rolling back to the "other" root filesystem in the case of
problems with the most recently-installed root filesystem (by making
the bootloader switch root filesystems).
Partitions
----------
All snappy systems comprises the following disk partitions:
================= ======================= ================= =========== ===========================
Partition Label Default Size (MB) Filesystem type Writable? Description
================= ======================= ================= =========== ===========================
``system-boot`` 64 vfat Yes Boot-related files
``system-a`` 1024 ext4 No Primary root filesystem
``system-b`` 1024 ext4 No Secondary root filesystem
``writable`` `(all remaining space)` ext4 Yes All persistent user data
================= ======================= ================= =========== ===========================
Notes:
* The boot partition must be formatted as a vfat filesystem since:
* This is required for EFI systems.
* vfat is supported by the majority of u-boot variants and grub.
U-Boot-based systems
~~~~~~~~~~~~~~~~~~~~
Systems that use the u-boot bootloader (such as armhf hosts) have the
following partition layout:
================= ======================= =========== ====================================================================================
Partition Label Default Size (MB) Writable? Notes
================= ======================= =========== ====================================================================================
``system-boot`` 64 Yes Used to store snappy bootloader variables.
``system-a`` 1024 No Provisioned automatically by ubuntu-device-flash.
``system-b`` 1024 No Provisioned automatically by ubuntu-device-flash at the same revision as system-a.
``writable`` `(all remaining space)` Yes
================= ======================= =========== ====================================================================================
Grub-based systems
~~~~~~~~~~~~~~~~~~
Systems that use the grub bootloader (such as ``i386`` and ``amd64`` hosts) have
the following partition layout:
================= ======================== =========== ====================================================================================================================
Partition Label Default Size (MB) Writable? Notes
================= ======================== =========== ====================================================================================================================
``grub`` 4 Yes Partition containing grub installation.
``system-boot`` 64 Yes EFI-capable partition (note that EFI is not currently used though. Also used to store snappy bootloader variables.
``system-a`` 1024 No Provisioned automatically by ubuntu-device-flash.
``system-b`` 1024 No Formatted, but not provisioned for cloud hosts.
``writable`` `(all remaining space)` Yes
================= ======================== =========== ====================================================================================================================
Bootloader Configuration
------------------------
Snappy sets a small number of bootloader variables which provide state
both for snappy and the bootloader itself.
Primary variables
~~~~~~~~~~~~~~~~~
===================== ================== ========================== ====================================
Bootloader variable Default value Permissible values Description
===================== ================== ========================== ====================================
``snappy_mode`` ``regular`` "``regular``" or "``try``" Type of boot in operation.
``snappy_ab`` "``a``" or "``b``" "``a``" or "``b``" Denotes rootfs to attempt to boot.
===================== ================== ========================== ====================================
``snappy_mode``
'''''''''''''''
This variable is initially set to "``regular``" which corresponds to a
normal boot (no special behaviour occurs).
Setting the variable to "try" will inform the bootloader that it should
attempt to boot a brand-new (never booted) root filesystem.
``snappy_ab``
'''''''''''''
This variable specifies which of the two possible root filesystems the
bootloader should attempt to use when "``snappy_mode=try``".
Configuration Files
~~~~~~~~~~~~~~~~~~~
The variables in the table above are stored in different locations,
depending on the system bootloader:
============ ================================= ===========================================================
Bootloader Configuration file Description
============ ================================= ===========================================================
grub ``/boot/grub/grubenv`` Default location for grub environment block.
u-boot ``/boot/uboot/snappy-system.txt`` File sourced by ``/boot/uboot/uEnv.txt`` on snappy systems.
============ ================================= ===========================================================
Boot Assets
-----------
The location of the boot assets depends on the bootloader being used:
============ ============================================ =============================================
Bootloader Boot assets Boot assets partition
============ ============================================ =============================================
grub * ``/boot/vmlinuz-$version`` ``system-a`` and ``system-b`` [#boot-grub]_
* ``/boot/initrd.img-$version``
u-boot * ``/boot/uboot/$snappy_ab/vmlinuz`` ``system-boot``
* ``/boot/uboot/$snappy_ab/initrd.img``
* ``/boot/uboot/$snappy_ab/dtbs/$board.dtb``
============ ============================================ =============================================
Key:
* ``$version`` expands to a kernel version.
* ``$snappy_ab`` expands to a value of the `snappy_ab`_ variable.
* ``$board`` expands to a name representing the device.
Updating the System
-------------------
When a new system image is available it can be applied simply by
running::
$ sudo snappy update
This command will:
#. Download the latest system image.
#. Apply the latest system image to the other root partition.
#. Update the bootloader configuration such that the next boot will
automatically be using the latest system image by setting the
following bootloader variables:
#. Set "``snappy_mode=try``".
#. Set "``snappy_ab=$rootfs``" where "``$rootfs``" depends on which rootfs should be attempted on next boot.
Booting in "try-mode"
~~~~~~~~~~~~~~~~~~~~~
When the bootloader runs on next boot, it will detect that
"``snappy_mode=try``" and know that the rootfs specified by
"``snappy_ab``" has not yet been successfully booted. It will then
perform an action that it expects to be "undone" if the next boot is
successful:
============ =================================================== ================================================
Bootloader Action on "``snappy_mode=try``" Undone by
============ =================================================== ================================================
grub Sets "``snappy_trial_boot=1``" bootloader variable ``/lib/systemd/system/ubuntu-core-snappy.service``
u-boot Creates empty file ``/boot/uboot/snappy-stamp.txt`` ``/lib/systemd/system/ubuntu-core-snappy.service``
============ =================================================== ================================================
Notes:
* The action is undone using a boot script (which calls ``snappy``).
* The actions performed by u-boot are different to grub since some
versions of u-boot are unable to reliably write files on ``vfat``
partitions (which would be required if it were to rewrite the snappy
variables file). As such, u-boot is simply expected to "``touch``" a
zero-length file on a ``vfat`` partition, which most versions of u-boot
are able to do.
Successful next boot
''''''''''''''''''''
If the next boot succeeds, snappy will undo the actions performed by the
bootloader:
* Change "``snappy_mode``" from "``try``" to "``regular``".
* On Grub systems, unset the standard "``snappy_trial_boot``" bootloader
variable.
* On U-boot systems, remove the file ``/boot/uboot/snappy-stamp.txt``.
These actions will inform the bootloader on next boot to continue to use
the current root filesystem, since it is now known to be usable.
Failed next boot
''''''''''''''''
If the next boot fails, the actions performed by the bootloader will
have failed to be undone. Thus on subsequent boot, the bootloader will
still see "``snappy_mode=try``" and know the rootfs specified by
"``snappy_ab``" is bad. The bootloader itself will then force a revert to
the other root filesystem, which is known to be usable:
* Change "``snappy_mode``" from "``try``" to "``regular``".
* Change "``snappy_ab``" from its current value to the "other" value.
snappy will simply fail to modify the "``snappy_mode``" bootloader
variable such that on the subsequent boot, the bootloader will detect
that "``snappy_mode``" is still set to "``try``" and thus realise that
the last boot failed to change this setting. The bootloader will then
know that the rootfs specified by "``snappy_ab``" is "bad" and
automatically revert to using the "other" rootfs (which is known to be
usable).
Rolling Back the System
-----------------------
To revert to using the previous system image, simply run::
$ sudo snappy rollback ubuntu-core
This command will update the bootloader configuration to ensure that the
next boot automatically uses the "other" system image rather than the
current one:
* Set "``snappy_ab``" to the "other" value.
For example, if "``snappy_ab=b``", the rollback will set "``snappy_ab=a``".
Note that there is no need to modify "``snappy_mode``" since the previous
rootfs is always usable.
Failure Resilience
------------------
Snappy currently offers a few strategies to ensure recovery from failure
scenarios.
Current Story
~~~~~~~~~~~~~
Kernel or Init system failure
'''''''''''''''''''''''''''''
The kernel command-line is automatically set to include "``panic=-1``"
meaning that if either the kernel panics or if the init system fails,
the system will automatically reboot.
* If the failure occurs early in boot [#early-boot]_, the first time
after a new system image has been applied, the system will
automatically reboot, reverting back to the "last good system image",
using the same logic as outlined in the section `Updating the System`_.
* If the failure occurs after the system has successfully booted, the
system will be restarted automatically and will continue to use the
existing system image.
Hanging Boot
''''''''''''
If the system hangs in early boot [#early-boot]_, the first time after a
new system image has been applied, forcibly power-cycling the system
will cause it to boot using the "last good system image".
Corrupt Bootloader Variables
''''''''''''''''''''''''''''
Since the bootloader variables are on a writable device, it is possible
the files could become corrupt either due to bad media, user error or
power failure whilst writes were occurring. Snappy attempts to protect
against the last scenario by mounting the boot partition using the
"``sync``" option.
Snappy systems attempt to deal with corrupt bootloader variables by
providing default values to the bootloader in the case where the
bootloader cannot read the values written by snappy.
Future
~~~~~~
The following sections are ideas for future improvements; there is no
guarantee that they will be implemented.
Automatic reboot on hung boot
'''''''''''''''''''''''''''''
It would be beneficial to automatically detect a hung boot and reboot
without requiring manual intervention to power cycle. However, this is a
difficult problem since some devices are inherently slow to boot so it
is currently unclear how best to solve this problem.
A compromise may be to introduce a well-known boot sequence point /
"try_watchdog" service which could be configured as required by users
for systems with fixed hardware (and thus a known "worst-case" boot
experience). Snappy could provide this service, disabled by default,
along with a default value (in seconds) for the maximum time a system is
expected to boot to a ``getty`` login prompt within. Users would be able to
modify the default number of seconds to suite their particular systems.
Minimise writes to boot partition
'''''''''''''''''''''''''''''''''
It would be possible to further reduce the amount of data written to the
boot partition on u-boot systems by making ``/boot/uboot/snappy-system.txt``
only include the current snappy variables (``snappy_mode`` and ``snappy_ab``)
and introducing an intermediate file such that:
* ``/boot/uboot/uEnv.txt`` sources ``/boot/uboot/snappy-common.txt``.
* ``/boot/uboot/snappy-common.txt`` sources ``/boot/uboot/snappy-system.txt``.
This would further reduce the possibility of an unbootable system since
``snappy-common.txt`` (which would never be written) could contain default
values for ``snappy_mode`` and ``snappy_ab``.
Disaster-recovery
'''''''''''''''''
Snappy systems should:
* Tolerate systems where the writable partition is full or corrupt.
* Allow the bootloader to be re-installed if the system-boot partition
becomes corrupt.
* Allow the bootloader configuration to be re-installed if it becomes
corrupt.
Multiple Disks
''''''''''''''
* Support systems with dual local disk devices:
* Support systems with minimal writable partition and a remote
writable mount for user data.
This would make most of the snappy image recreatable by
ubuntu-device-flash.
Miscellaneous
'''''''''''''
* Support UEFI secure boot.
* Handle booting with encrypted partitions.
References
----------
* https://developer.ubuntu.com/en/snappy/porting/
* https://developer.ubuntu.com/en/snappy/guides/filesystem-layout/
Footnotes
---------
.. [#boot-grub]
On grub systems, "``/boot/grub``" is where the system-boot partition
is mounted. However, "``/boot``" is part of the read-only root
filesystem image.
.. [#early-boot]
Early boot is defined as being "any time before a login prompt is
available".
|