File: task.yaml

package info (click to toggle)
snapd 2.72-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 80,412 kB
  • sloc: sh: 16,506; ansic: 16,211; python: 11,213; makefile: 1,919; exp: 190; awk: 58; xml: 22
file content (355 lines) | stat: -rw-r--r-- 13,819 bytes parent folder | download
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
summary: End-to-end test for install Ubuntu Core via muinstaller

details: |
  This test installs Ubuntu Core using the muinstaller. The muinstaller is a
  program that interfaces with the snapd API to install an Ubuntu Core system.
  We test both the encrypted and unencrypted cases. We also verify that the
  system has properly installed system seed post-installation.

systems: [ubuntu-22.04-64, ubuntu-24.04-64]

environment:
  # default (encrypted) case. all of the install_optional_* variants exercise
  # the encrypted case
  NESTED_ENABLE_TPM: true
  NESTED_ENABLE_SECURE_BOOT: true

  # encrypted + passphrase auth smoke test
  # TODO: extract a more comprehensive core24 test similar
  # to tests/nested/manual/passphrase-support-on-hybrid.
  NESTED_PASSPHRASE/passphrase_auth: "ubuntu"

  # unencrypted case
  NESTED_ENABLE_TPM/plain: false
  NESTED_ENABLE_SECURE_BOOT/plain: false

  # ensure we use our latest code
  NESTED_BUILD_SNAPD_FROM_CURRENT: true
  NESTED_REPACK_KERNEL_SNAP: true
  # image
  IMAGE_MOUNTPOINT: /mnt/cloudimg

  # by default, we don't specify any optional installs. this means we should
  # install all snaps and components
  INSTALL_OPTIONAL_SNAP: false
  INSTALL_OPTIONAL_COMPONENT: false
  INSTALL_OPTIONAL_ALL: false
  INSTALL_OPTIONAL_EXPECT_ALL: true

  INSTALL_OPTIONAL_SNAP/install_optional_snap: true
  INSTALL_OPTIONAL_EXPECT_ALL/install_optional_snap: false

  INSTALL_OPTIONAL_SNAP/install_optional_snap_and_comp: true
  INSTALL_OPTIONAL_COMPONENT/install_optional_snap_and_comp: true
  INSTALL_OPTIONAL_EXPECT_ALL/install_optional_snap_and_comp: true

  INSTALL_OPTIONAL_ALL/install_optional_all: true
  INSTALL_OPTIONAL_EXPECT_ALL/install_optional_all: true

prepare: |
  if [ "$TRUST_TEST_KEYS" = "false" ]; then
      echo "This test needs test keys to be trusted"
      exit
  fi

restore: |
  rm -rf pc-kernel.* pc.* initrd* linux* kernel* tmp* pc-gadget snap-with-comps.snap snap-with-comps+comp1.comp core-seed fake-disk.img

execute: |
  # shellcheck source=tests/lib/prepare.sh
  . "$TESTSLIB/prepare.sh"
  #shellcheck source=tests/lib/nested.sh
  . "$TESTSLIB"/nested.sh

  if ! os.query is-noble && [ -n "${NESTED_PASSPHRASE-}" ]; then
    echo "SKIPPING: only run passphrase support variant for core24"
    exit 0
  fi

  version="$(nested_get_version)"

  # Retrieve the gadget
  snap download --basename=pc --channel="$version/${KERNEL_CHANNEL}" pc

  # Modify gadget, making sure we can access the device (we are not building
  # the image in the usual way in snapd spread tests).
  unsquashfs -d pc-gadget pc.snap
  echo 'console=ttyS0' > pc-gadget/cmdline.extra
  cat <<EOF > pc-gadget/cloud.conf
  #cloud-config
  datasource_list: [None]
  ssh_pwauth: True
  users:
   - name: user1
     sudo: ALL=(ALL) NOPASSWD:ALL
     shell: /bin/bash
  chpasswd:
    list: |
      user1:ubuntu
    expire: False
  EOF

  echo "Sign the shim binary"
  KEY_NAME=$(tests.nested download snakeoil-key)
  SNAKEOIL_KEY="$PWD/$KEY_NAME.key"
  SNAKEOIL_CERT="$PWD/$KEY_NAME.pem"
  tests.nested secboot-sign gadget pc-gadget "$SNAKEOIL_KEY" "$SNAKEOIL_CERT"
  snap pack --filename=pc.snap pc-gadget/
  rm -rf pc-gadget

  # Retrieve kernel
  snap download --basename=pc-kernel --channel="$version/${KERNEL_CHANNEL}" pc-kernel

  # THIS IS A HACK
  # TODO: Remove when pc-kernel snapd-info includes snap-bootstrap from snapd 2.68+
  # Inject snapd-info file to account for kernels that don't yet include snapd 2.68+
  unsquashfs -d tmp-pc-kernel pc-kernel.snap
  cat <<EOF > tmp-pc-kernel/snapd-info
  VERSION=2.68
  SNAPD_APPARMOR_REEXEC=1
  SNAPD_ASSERTS_FORMATS='{"account-key":1,"snap-declaration":6,"system-user":2}'
  EOF
  rm pc-kernel.snap
  snap pack tmp-pc-kernel
  rm -rf tmp-pc-kernel
  mv pc-kernel_*.snap pc-kernel.snap
  # HACK ENDS

  # Build kernel with initramfs with the compiled snap-bootstrap
  if os.query is-ubuntu-ge 24.04; then
    uc24_build_initramfs_kernel_snap "$PWD/pc-kernel.snap" "$NESTED_ASSETS_DIR"
  else
    uc20_build_initramfs_kernel_snap "$PWD/pc-kernel.snap" "$NESTED_ASSETS_DIR"
  fi
  mv "${NESTED_ASSETS_DIR}"/pc-kernel_*.snap pc-kernel.snap

  # shellcheck source=tests/lib/prepare.sh
  . "$TESTSLIB"/prepare.sh
  build_snapd_snap "$PWD"
  mv snapd_*.snap snapd.snap

  sed -i "s/\$BASE/core${version}/" ./snap-with-comps/meta/snap.yaml
  snap pack ./snap-with-comps --filename=snap-with-comps.snap
  snap pack ./comp1 --filename=snap-with-comps+comp1.comp

  # TODO: refactor preparation/hacks in a reusable script
  # similar to setup_nested_hybrid_system.sh

  # prepare a core seed
  SEED_DIR="core-seed"
  wget -q https://raw.githubusercontent.com/snapcore/models/master/ubuntu-core-"$version"-amd64-dangerous.model -O my.model
  snap prepare-image \
      --channel=edge \
      --snap ./pc-kernel.snap \
      --snap ./pc.snap \
      --snap ./snapd.snap \
      --snap ./snap-with-comps.snap \
      --comp ./snap-with-comps+comp1.comp \
      my.model \
      ./"$SEED_DIR"

  # get the label, which is generated by snap prepare-image and is based on the
  # date
  LABEL=$(basename ./"$SEED_DIR"/system-seed/systems/*)
  cp -a ./"$SEED_DIR"/system-seed/ /var/lib/snapd/seed

  # build the muinstaller snap
  snap install snapcraft --candidate --classic
  "$TESTSTOOLS"/lxd-state prepare-snap
  (cd "$TESTSLIB"/muinstaller && snapcraft)
  MUINSTALLER_SNAP="$(find "$TESTSLIB"/muinstaller/ -maxdepth 1 -name '*.snap')"
  echo "found $MUINSTALLER_SNAP"

  # create new disk for the installer to work on and attach to VM
  truncate --size=4G fake-disk.img

  # create a VM and mount a cloud image
  tests.nested build-image classic

  # TODO: nested classic images do not support secure boot today so
  #       this will not work to test the secure boot installer. So for
  #       now the workaround is to boot classic to create user/ssh
  #       keys, shutdown down, convert disk from qcow2->raw and rename
  #       from classic->core and use nested_start_core_vm (like below)
  #
  # start it so that cloud-init creates ssh keys and user
  # We set a serial for our disk to easily locate it when invoking muinstaller (virtio-target)
  NESTED_PARAM_EXTRA="-drive file=$(pwd)/fake-disk.img,if=none,snapshot=off,format=raw,id=disk2 \
      -device virtio-blk-pci,drive=disk2,serial=target"
  tests.nested create-vm classic --extra-param "$NESTED_PARAM_EXTRA"

  # make sure classic image is bootable with snakeoil keys
  # TODO: move to nested_create_classic_image
  # XXX: use assets from gadget instead?
  for s in BOOT/BOOTX64.EFI ubuntu/shimx64.efi; do
      remote.exec "sudo cp -a /boot/efi/EFI/$s /tmp"
      remote.exec "sudo chmod 755 /tmp/$(basename $s)"
      remote.pull /tmp/"$(basename $s)" .
      nested_secboot_sign_file "$(basename $s)" "$SNAKEOIL_KEY" "$SNAKEOIL_CERT"
      remote.push "$(basename $s)"
      remote.exec "sudo mv $(basename $s) /boot/efi/EFI/$s"
  done

  remote.exec "sudo sh -c 'echo SNAPD_DEBUG=1 >> /etc/environment'"
  # push our snap down
  remote.push "$GOHOME"/snapd_*.deb
  remote.exec "sudo apt install -y ./snapd_*.deb"

  # push our seed down
  # TODO: merge with classic /var/lib/snapd/seed eventually
  # XXX: port scp -r to remote.push
  #remote.push ./"$SEED_DIR"/system-seed/ '~/'
  sshpass -p ubuntu scp -r -P 8022 -o ConnectTimeout=10 \
      -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no \
      ./"$SEED_DIR"/system-seed/ user1@localhost:~/install-seed
  remote.exec "sudo mv /home/user1/install-seed /var/lib/snapd/"

  # shutdown the classic vm to install with a core VM that supports
  # secboot/tpm
  tests.nested vm stop
  sync

  # HACK: convert "classic" qcow2 to raw "core" image because we need
  # to boot with OVMF we really should fix this so that classic and
  # core VMs are more similar
  qemu-img convert -f qcow2 -O raw \
      "$NESTED_IMAGES_DIR/$(nested_get_image_name classic)" \
      "$NESTED_IMAGES_DIR/$(nested_get_image_name core)"
  # and we don't need the classic image anymore
  rm -f  "$NESTED_IMAGES_DIR/$(nested_get_image_name classic)"
  # TODO: this prevents "nested_prepare_ssh" inside nested_start_core_vm
  #       from running, we already have a user so this is not needed
  IMAGE_NAME="$(nested_get_image_name core)"
  touch "$NESTED_IMAGES_DIR/$IMAGE_NAME.configured"
  tests.nested create-vm core --extra-param "$NESTED_PARAM_EXTRA"

  # bind mount new seed
  remote.exec sudo mkdir -p /var/lib/snapd/seed
  remote.exec "sudo mount -o bind /var/lib/snapd/install-seed /var/lib/snapd/seed"
  # push and install muinstaller
  remote.push "$MUINSTALLER_SNAP"
  remote.exec "sudo snap install --classic --dangerous $(basename "$MUINSTALLER_SNAP")"
  # Run installation
  install_disk=$(remote.exec "readlink -f /dev/disk/by-id/virtio-target")

  if [ "$INSTALL_OPTIONAL_ALL" = "true" ]; then
    echo '{"all": true}' > optional-install.json
  elif [ "$INSTALL_OPTIONAL_COMPONENT" = "true" ]; then
    echo '{"snaps": ["snap-with-comps"], "components": {"snap-with-comps": ["comp1"]}}' > optional-install.json
  elif [ "$INSTALL_OPTIONAL_SNAP" = "true" ]; then
    echo '{"snaps": ["snap-with-comps"]}' > optional-install.json
  fi

  # make sure that the system reports the expected available optional snaps
  remote.exec "sudo snap debug api /v2/systems/$LABEL" > system-info.json
  cat <<EOF > expected-available.json
  {
    "snaps": ["snap-with-comps"],
    "components": {
      "snap-with-comps": ["comp1"]
    }
  }
  EOF
  # gojq sorts keys by default
  diff -u <(gojq  '.result.["available-optional"]' system-info.json) <(gojq . expected-available.json)

  muinstaller_args="-label $LABEL -device $install_disk"
  if [ -f optional-install.json ]; then
    remote.push optional-install.json
    muinstaller_args="$muinstaller_args -optional ./optional-install.json"
  fi
  if [ -n "${NESTED_PASSPHRASE-}" ]; then
    muinstaller_args="$muinstaller_args -passphrase ${NESTED_PASSPHRASE}"
  fi

  remote.exec "sudo muinstaller $muinstaller_args"

  remote.exec "sudo sync"

  # Stop and remove the classic vm now that the attached disk (fake-disk.img)
  # contains a just installed UC image.
  tests.nested vm remove
  sync

  # HACK: rename to "core" image because we need to boot with OVMF
  # we really should fix this so that classic and core VMs are more similar
  mv fake-disk.img "$NESTED_IMAGES_DIR/$IMAGE_NAME"

  # Start installed image
  if [ -n "${NESTED_PASSPHRASE-}" ]; then
    tests.nested create-vm core --keep-firmware-state --passphrase "${NESTED_PASSPHRASE}"
  else
    tests.nested create-vm core --keep-firmware-state
  fi

  # things look fine
  remote.exec "cat /etc/os-release" | MATCH 'NAME="Ubuntu Core"'
  remote.exec "snap changes" | MATCH "Done.* Initialize system state"
  remote.exec "snap list" | MATCH pc-kernel

  # check encryption
  remote.exec "sudo snap install test-snapd-tools"
  remote.exec "snap list" | MATCH "test-snapd-tools"
  if [ "$NESTED_ENABLE_TPM" = false ]; then
      remote.exec "test-snapd-tools.cmd snapctl system-mode" | NOMATCH "storage-encrypted"
  else
      remote.exec "test-snapd-tools.cmd snapctl system-mode" | MATCH "storage-encrypted: managed"

      remote.exec "sudo test -d /var/lib/snapd/device/fde"
      remote.exec "sudo test -e /var/lib/snapd/device/fde/marker"
      remote.exec "sudo test -e /var/lib/snapd/device/fde/marker"
      remote.exec "sudo blkid /dev/disk/by-label/ubuntu-data-enc" | MATCH crypto_LUKS

      echo "Ensure recovery keys are available"
      remote.exec "sudo snap recovery --show-keys" > show-keys.out
      MATCH 'recovery:\s+[0-9]{5}-[0-9]{5}-[0-9]{5}-[0-9]{5}-[0-9]{5}-[0-9]{5}-[0-9]{5}-[0-9]{5}' < show-keys.out

      # check disk mappings
      DISK_MAPPINGS=(/run/mnt/ubuntu-save/device/disk-mapping.json
                     /run/mnt/data/system-data/var/lib/snapd/device/disk-mapping.json)
      for DM in "${DISK_MAPPINGS[@]}"; do
          remote.exec "sudo cat $DM" | \
              gojq '.pc."structure-encryption"."ubuntu-save".method' | MATCH '"LUKS"'
          remote.exec "sudo cat $DM" | \
              gojq '.pc."structure-encryption"."ubuntu-data".method' | MATCH '"LUKS"'
      done
  fi

  # check that seed is properly installed
  remote.exec test -d "/run/mnt/ubuntu-seed/systems/${LABEL}"
  remote.exec "sudo snap recovery" | MATCH "${LABEL}\s+canonical\*\*\s+ubuntu-core-$version-amd64-dangerous\s+current"

  # check for unasserted snaps
  for sn in snapd pc pc-kernel; do
      sn_version=$(remote.exec "snap list ${sn}" | awk 'NR != 1 { print $2 }')
      remote.exec "test -f /run/mnt/ubuntu-seed/systems/${LABEL}/snaps/${sn}_${sn_version}.snap"
  done

  if [ "$INSTALL_OPTIONAL_SNAP" = "true" ] || [ "$INSTALL_OPTIONAL_EXPECT_ALL" = "true" ]; then
      sn_version=$(remote.exec "snap list snap-with-comps" | awk 'NR != 1 { print $2 }')

      # snap isn't asserted, but it is not in the model so it should end up here
      remote.exec "test -f /run/mnt/ubuntu-seed/systems/${LABEL}/snaps/snap-with-comps_${sn_version}.snap"

      if [ "$INSTALL_OPTIONAL_EXPECT_ALL" = "true" ]; then
          # make sure our component is there too
          remote.exec "snap run snap-with-comps.test comp1"
      else
          not remote.exec "snap run snap-with-comps.test comp1"
      fi
  else
      not remote.exec "snap list snap-with-comps"
  fi

  # check for asserted snaps
  #shellcheck disable=SC2043
  for sn in core"$version"; do
      rev=$(remote.exec "snap list ${sn}" | awk 'NR != 1 { print $3 }')
      remote.exec "test -f /run/mnt/ubuntu-seed/snaps/${sn}_${rev}.snap"
  done

  # model in the seed should match the one that was installed on the system
  remote.exec "diff <(snap model --assertion) /run/mnt/ubuntu-seed/systems/${LABEL}/model"

  # test that we can actually boot into the installed recovery system
  tests.nested transition "${LABEL}" recover