github.com/anonymouse64/snapd@v0.0.0-20210824153203-04c4c42d842d/gadget/install/partition_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2019-2020 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package install_test 21 22 import ( 23 "bytes" 24 "fmt" 25 "io/ioutil" 26 "path/filepath" 27 "testing" 28 "time" 29 30 . "gopkg.in/check.v1" 31 32 "github.com/snapcore/snapd/asserts" 33 "github.com/snapcore/snapd/gadget" 34 "github.com/snapcore/snapd/gadget/install" 35 "github.com/snapcore/snapd/gadget/quantity" 36 "github.com/snapcore/snapd/testutil" 37 ) 38 39 func TestInstall(t *testing.T) { TestingT(t) } 40 41 type partitionTestSuite struct { 42 testutil.BaseTest 43 44 dir string 45 gadgetRoot string 46 cmdPartx *testutil.MockCmd 47 } 48 49 var _ = Suite(&partitionTestSuite{}) 50 51 func (s *partitionTestSuite) SetUpTest(c *C) { 52 s.BaseTest.SetUpTest(c) 53 54 s.dir = c.MkDir() 55 s.gadgetRoot = filepath.Join(c.MkDir(), "gadget") 56 57 s.cmdPartx = testutil.MockCommand(c, "partx", "") 58 s.AddCleanup(s.cmdPartx.Restore) 59 60 cmdSfdisk := testutil.MockCommand(c, "sfdisk", `echo "sfdisk was not mocked"; exit 1`) 61 s.AddCleanup(cmdSfdisk.Restore) 62 cmdLsblk := testutil.MockCommand(c, "lsblk", `echo "lsblk was not mocked"; exit 1`) 63 s.AddCleanup(cmdLsblk.Restore) 64 65 // we test different sector sizes elsewhere, here we always use it to get the sector size 66 cmdBlockdev := testutil.MockCommand(c, "blockdev", blockdevSectorSize512Script) 67 s.AddCleanup(cmdBlockdev.Restore) 68 } 69 70 const ( 71 scriptPartitionsBios = iota 72 scriptPartitionsBiosSeed 73 scriptPartitionsBiosSeedData 74 ) 75 76 func makeSfdiskScript(num int) string { 77 var b bytes.Buffer 78 79 b.WriteString(` 80 >&2 echo "Some warning from sfdisk" 81 echo '{ 82 "partitiontable": { 83 "label": "gpt", 84 "id": "9151F25B-CDF0-48F1-9EDE-68CBD616E2CA", 85 "device": "/dev/node", 86 "unit": "sectors", 87 "firstlba": 34, 88 "lastlba": 8388574, 89 "partitions": [`) 90 91 // BIOS boot partition 92 if num >= scriptPartitionsBios { 93 b.WriteString(` 94 { 95 "node": "/dev/node1", 96 "start": 2048, 97 "size": 2048, 98 "type": "21686148-6449-6E6F-744E-656564454649", 99 "uuid": "2E59D969-52AB-430B-88AC-F83873519F6F", 100 "name": "BIOS Boot" 101 }`) 102 } 103 104 // Seed partition 105 if num >= scriptPartitionsBiosSeed { 106 b.WriteString(`, 107 { 108 "node": "/dev/node2", 109 "start": 4096, 110 "size": 2457600, 111 "type": "C12A7328-F81F-11D2-BA4B-00A0C93EC93B", 112 "uuid": "44C3D5C3-CAE1-4306-83E8-DF437ACDB32F", 113 "name": "Recovery" 114 }`) 115 } 116 117 // Data partition 118 if num >= scriptPartitionsBiosSeedData { 119 b.WriteString(`, 120 { 121 "node": "/dev/node3", 122 "start": 2461696, 123 "size": 2457600, 124 "type": "0FC63DAF-8483-4772-8E79-3D69D8477DE4", 125 "uuid": "f940029d-bfbb-4887-9d44-321e85c63866", 126 "name": "Writable" 127 }`) 128 } 129 130 b.WriteString(` 131 ] 132 } 133 }'`) 134 return b.String() 135 } 136 137 func makeLsblkScript(num int) string { 138 var b bytes.Buffer 139 140 // BIOS boot partition 141 if num >= scriptPartitionsBios { 142 b.WriteString(` 143 [ "$3" == "/dev/node1" ] && echo '{ 144 "blockdevices": [ {"name": "node1", "fstype": null, "label": null, "uuid": null, "mountpoint": null} ] 145 }'`) 146 } 147 148 // Seed partition 149 if num >= scriptPartitionsBiosSeed { 150 b.WriteString(` 151 [ "$3" == "/dev/node2" ] && echo '{ 152 "blockdevices": [ {"name": "node2", "fstype": "vfat", "label": "ubuntu-seed", "uuid": "A644-B807", "mountpoint": null} ] 153 }'`) 154 } 155 156 // Data partition 157 if num >= scriptPartitionsBiosSeedData { 158 b.WriteString(` 159 [ "$3" == "/dev/node3" ] && echo '{ 160 "blockdevices": [ {"name": "node3", "fstype": "ext4", "label": "ubuntu-data", "uuid": "8781-433a", "mountpoint": null} ] 161 }'`) 162 } 163 164 b.WriteString(` 165 exit 0`) 166 167 return b.String() 168 } 169 170 const blockdevSectorSize512Script = ` 171 if [ "$1" == "--getss" ]; then 172 echo 512 173 exit 0 174 fi 175 echo "unexpected cmdline opts $*" 176 exit 1 177 ` 178 179 var mockOnDiskStructureWritable = gadget.OnDiskStructure{ 180 Node: "/dev/node3", 181 LaidOutStructure: gadget.LaidOutStructure{ 182 VolumeStructure: &gadget.VolumeStructure{ 183 Name: "Writable", 184 Size: 1258291200, 185 Type: "83,0FC63DAF-8483-4772-8E79-3D69D8477DE4", 186 Role: "system-data", 187 Label: "ubuntu-data", 188 Filesystem: "ext4", 189 }, 190 StartOffset: 1260388352, 191 Index: 3, 192 }, 193 // expanded to fill the disk 194 Size: 2*quantity.SizeGiB + 845*quantity.SizeMiB + 1031680, 195 } 196 197 var mockOnDiskStructureSave = gadget.OnDiskStructure{ 198 Node: "/dev/node3", 199 LaidOutStructure: gadget.LaidOutStructure{ 200 VolumeStructure: &gadget.VolumeStructure{ 201 Name: "Save", 202 Size: 128 * quantity.SizeMiB, 203 Type: "83,0FC63DAF-8483-4772-8E79-3D69D8477DE4", 204 Role: "system-save", 205 Label: "ubuntu-save", 206 Filesystem: "ext4", 207 }, 208 StartOffset: 1260388352, 209 Index: 3, 210 }, 211 Size: 128 * quantity.SizeMiB, 212 } 213 214 var mockOnDiskStructureWritableAfterSave = gadget.OnDiskStructure{ 215 Node: "/dev/node4", 216 LaidOutStructure: gadget.LaidOutStructure{ 217 VolumeStructure: &gadget.VolumeStructure{ 218 Name: "Writable", 219 Size: 1200 * quantity.SizeMiB, 220 Type: "83,0FC63DAF-8483-4772-8E79-3D69D8477DE4", 221 Role: "system-data", 222 Label: "ubuntu-data", 223 Filesystem: "ext4", 224 }, 225 StartOffset: 1394606080, 226 Index: 4, 227 }, 228 // expanded to fill the disk 229 Size: 2*quantity.SizeGiB + 717*quantity.SizeMiB + 1031680, 230 } 231 232 // mustLayOutVolumeFromGadget takes a gadget rootdir and lays out the 233 // partitions as specified. This function does not handle multiple volumes and 234 // is meant for test helpers only. For runtime users, with multiple volumes 235 // handled by choosing the ubuntu-* role volume, see LaidOutSystemVolumeFromGadget 236 func mustLayOutVolumeFromGadget(c *C, gadgetRoot, kernelRoot string, model gadget.Model) (*gadget.LaidOutVolume, error) { 237 info, err := gadget.ReadInfo(gadgetRoot, model) 238 c.Assert(err, IsNil) 239 240 c.Assert(info.Volumes, HasLen, 1, Commentf("only single volumes supported in test helper")) 241 242 constraints := gadget.LayoutConstraints{ 243 NonMBRStartOffset: 1 * quantity.OffsetMiB, 244 } 245 246 for _, vol := range info.Volumes { 247 pvol, err := gadget.LayoutVolume(gadgetRoot, kernelRoot, vol, constraints) 248 c.Assert(err, IsNil) 249 // we know info.Volumes map has size 1 so we can return here 250 return pvol, nil 251 } 252 // this is impossible to reach, we already asserted that info.Volumes has a 253 // length of 1 254 panic("impossible test error") 255 } 256 257 type uc20Model struct{} 258 259 func (c uc20Model) Classic() bool { return false } 260 func (c uc20Model) Grade() asserts.ModelGrade { return asserts.ModelSigned } 261 262 var uc20Mod = uc20Model{} 263 264 func (s *partitionTestSuite) TestBuildPartitionList(c *C) { 265 cmdSfdisk := testutil.MockCommand(c, "sfdisk", makeSfdiskScript(scriptPartitionsBiosSeed)) 266 defer cmdSfdisk.Restore() 267 268 cmdLsblk := testutil.MockCommand(c, "lsblk", makeLsblkScript(scriptPartitionsBiosSeed)) 269 defer cmdLsblk.Restore() 270 271 err := makeMockGadget(s.gadgetRoot, gptGadgetContentWithSave) 272 c.Assert(err, IsNil) 273 pv, err := mustLayOutVolumeFromGadget(c, s.gadgetRoot, "", uc20Mod) 274 c.Assert(err, IsNil) 275 276 dl, err := gadget.OnDiskVolumeFromDevice("/dev/node") 277 c.Assert(err, IsNil) 278 279 // the expected expanded writable partition size is: 280 // start offset = (2M + 1200M), expanded size in sectors = (8388575*512 - start offset)/512 281 sfdiskInput, create := install.BuildPartitionList(dl, pv) 282 c.Assert(sfdiskInput.String(), Equals, 283 `/dev/node3 : start= 2461696, size= 262144, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, name="Save" 284 /dev/node4 : start= 2723840, size= 5664735, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, name="Writable" 285 `) 286 c.Check(create, NotNil) 287 c.Assert(create, DeepEquals, []gadget.OnDiskStructure{mockOnDiskStructureSave, mockOnDiskStructureWritableAfterSave}) 288 } 289 290 func (s *partitionTestSuite) TestCreatePartitions(c *C) { 291 cmdSfdisk := testutil.MockCommand(c, "sfdisk", makeSfdiskScript(scriptPartitionsBiosSeed)) 292 defer cmdSfdisk.Restore() 293 294 cmdLsblk := testutil.MockCommand(c, "lsblk", makeLsblkScript(scriptPartitionsBiosSeed)) 295 defer cmdLsblk.Restore() 296 297 calls := 0 298 restore := install.MockEnsureNodesExist(func(ds []gadget.OnDiskStructure, timeout time.Duration) error { 299 calls++ 300 c.Assert(ds, HasLen, 1) 301 c.Assert(ds[0].Node, Equals, "/dev/node3") 302 return nil 303 }) 304 defer restore() 305 306 err := makeMockGadget(s.gadgetRoot, gadgetContent) 307 c.Assert(err, IsNil) 308 pv, err := mustLayOutVolumeFromGadget(c, s.gadgetRoot, "", uc20Mod) 309 c.Assert(err, IsNil) 310 311 dl, err := gadget.OnDiskVolumeFromDevice("/dev/node") 312 c.Assert(err, IsNil) 313 created, err := install.CreateMissingPartitions(dl, pv) 314 c.Assert(err, IsNil) 315 c.Assert(created, DeepEquals, []gadget.OnDiskStructure{mockOnDiskStructureWritable}) 316 c.Assert(calls, Equals, 1) 317 318 // Check partition table read and write 319 c.Assert(cmdSfdisk.Calls(), DeepEquals, [][]string{ 320 {"sfdisk", "--json", "/dev/node"}, 321 {"sfdisk", "--append", "--no-reread", "/dev/node"}, 322 }) 323 324 // Check partition table update 325 c.Assert(s.cmdPartx.Calls(), DeepEquals, [][]string{ 326 {"partx", "-u", "/dev/node"}, 327 }) 328 } 329 330 func (s *partitionTestSuite) TestRemovePartitionsTrivial(c *C) { 331 // no locally created partitions 332 cmdSfdisk := testutil.MockCommand(c, "sfdisk", makeSfdiskScript(scriptPartitionsBios)) 333 defer cmdSfdisk.Restore() 334 335 cmdLsblk := testutil.MockCommand(c, "lsblk", makeLsblkScript(scriptPartitionsBios)) 336 defer cmdLsblk.Restore() 337 338 err := makeMockGadget(s.gadgetRoot, gadgetContent) 339 c.Assert(err, IsNil) 340 pv, err := mustLayOutVolumeFromGadget(c, s.gadgetRoot, "", uc20Mod) 341 c.Assert(err, IsNil) 342 343 dl, err := gadget.OnDiskVolumeFromDevice("/dev/node") 344 c.Assert(err, IsNil) 345 346 err = install.RemoveCreatedPartitions(pv, dl) 347 c.Assert(err, IsNil) 348 349 c.Assert(cmdSfdisk.Calls(), DeepEquals, [][]string{ 350 {"sfdisk", "--json", "/dev/node"}, 351 }) 352 353 c.Assert(cmdLsblk.Calls(), DeepEquals, [][]string{ 354 {"lsblk", "--fs", "--json", "/dev/node1"}, 355 }) 356 } 357 358 func (s *partitionTestSuite) TestRemovePartitions(c *C) { 359 const mockSfdiskScriptRemovablePartition = ` 360 if [ -f %[1]s/2 ]; then 361 rm %[1]s/[0-9] 362 elif [ -f %[1]s/1 ]; then 363 touch %[1]s/2 364 exit 0 365 else 366 PART=', 367 {"node": "/dev/node2", "start": 4096, "size": 2457600, "type": "0FC63DAF-8483-4772-8E79-3D69D8477DE4", "uuid": "44C3D5C3-CAE1-4306-83E8-DF437ACDB32F", "name": "Recovery"}, 368 {"node": "/dev/node3", "start": 2461696, "size": 2457600, "type": "0FC63DAF-8483-4772-8E79-3D69D8477DE4", "uuid": "44C3D5C3-CAE1-4306-83E8-DF437ACDB32F", "name": "Recovery"} 369 ' 370 touch %[1]s/1 371 fi 372 echo '{ 373 "partitiontable": { 374 "label": "gpt", 375 "id": "9151F25B-CDF0-48F1-9EDE-68CBD616E2CA", 376 "device": "/dev/node", 377 "unit": "sectors", 378 "firstlba": 34, 379 "lastlba": 8388574, 380 "partitions": [ 381 {"node": "/dev/node1", "start": 2048, "size": 2048, "type": "21686148-6449-6E6F-744E-656564454649", "uuid": "2E59D969-52AB-430B-88AC-F83873519F6F", "name": "BIOS Boot"} 382 '"$PART 383 ] 384 } 385 }"` 386 387 cmdSfdisk := testutil.MockCommand(c, "sfdisk", fmt.Sprintf(mockSfdiskScriptRemovablePartition, s.dir)) 388 defer cmdSfdisk.Restore() 389 390 cmdLsblk := testutil.MockCommand(c, "lsblk", makeLsblkScript(scriptPartitionsBiosSeedData)) 391 defer cmdLsblk.Restore() 392 393 dl, err := gadget.OnDiskVolumeFromDevice("/dev/node") 394 c.Assert(err, IsNil) 395 396 c.Assert(cmdLsblk.Calls(), DeepEquals, [][]string{ 397 {"lsblk", "--fs", "--json", "/dev/node1"}, 398 {"lsblk", "--fs", "--json", "/dev/node2"}, 399 {"lsblk", "--fs", "--json", "/dev/node3"}, 400 }) 401 402 err = makeMockGadget(s.gadgetRoot, gadgetContent) 403 c.Assert(err, IsNil) 404 pv, err := mustLayOutVolumeFromGadget(c, s.gadgetRoot, "", uc20Mod) 405 c.Assert(err, IsNil) 406 407 err = install.RemoveCreatedPartitions(pv, dl) 408 c.Assert(err, IsNil) 409 410 c.Assert(cmdSfdisk.Calls(), DeepEquals, [][]string{ 411 {"sfdisk", "--json", "/dev/node"}, 412 {"sfdisk", "--no-reread", "--delete", "/dev/node", "3"}, 413 {"sfdisk", "--json", "/dev/node"}, 414 }) 415 } 416 417 func (s *partitionTestSuite) TestRemovePartitionsError(c *C) { 418 cmdSfdisk := testutil.MockCommand(c, "sfdisk", makeSfdiskScript(scriptPartitionsBiosSeedData)) 419 defer cmdSfdisk.Restore() 420 421 cmdLsblk := testutil.MockCommand(c, "lsblk", makeLsblkScript(scriptPartitionsBiosSeedData)) 422 defer cmdLsblk.Restore() 423 424 dl, err := gadget.OnDiskVolumeFromDevice("node") 425 c.Assert(err, IsNil) 426 427 err = makeMockGadget(s.gadgetRoot, gadgetContent) 428 c.Assert(err, IsNil) 429 pv, err := mustLayOutVolumeFromGadget(c, s.gadgetRoot, "", uc20Mod) 430 c.Assert(err, IsNil) 431 432 err = install.RemoveCreatedPartitions(pv, dl) 433 c.Assert(err, ErrorMatches, "cannot remove partitions: /dev/node3") 434 } 435 436 func (s *partitionTestSuite) TestEnsureNodesExist(c *C) { 437 const mockUdevadmScript = `err=%q; echo "$err"; [ -n "$err" ] && exit 1 || exit 0` 438 for _, tc := range []struct { 439 utErr string 440 err string 441 }{ 442 {utErr: "", err: ""}, 443 {utErr: "some error", err: "some error"}, 444 } { 445 c.Logf("utErr:%q err:%q", tc.utErr, tc.err) 446 447 node := filepath.Join(c.MkDir(), "node") 448 err := ioutil.WriteFile(node, nil, 0644) 449 c.Assert(err, IsNil) 450 451 cmdUdevadm := testutil.MockCommand(c, "udevadm", fmt.Sprintf(mockUdevadmScript, tc.utErr)) 452 defer cmdUdevadm.Restore() 453 454 ds := []gadget.OnDiskStructure{{Node: node}} 455 err = install.EnsureNodesExist(ds, 10*time.Millisecond) 456 if tc.err == "" { 457 c.Assert(err, IsNil) 458 } else { 459 c.Assert(err, ErrorMatches, tc.err) 460 } 461 462 c.Assert(cmdUdevadm.Calls(), DeepEquals, [][]string{ 463 {"udevadm", "trigger", "--settle", node}, 464 }) 465 } 466 } 467 468 func (s *partitionTestSuite) TestEnsureNodesExistTimeout(c *C) { 469 cmdUdevadm := testutil.MockCommand(c, "udevadm", "") 470 defer cmdUdevadm.Restore() 471 472 node := filepath.Join(c.MkDir(), "node") 473 ds := []gadget.OnDiskStructure{{Node: node}} 474 t := time.Now() 475 timeout := 1 * time.Second 476 err := install.EnsureNodesExist(ds, timeout) 477 c.Assert(err, ErrorMatches, fmt.Sprintf("device %s not available", node)) 478 c.Assert(time.Since(t) >= timeout, Equals, true) 479 c.Assert(cmdUdevadm.Calls(), HasLen, 0) 480 } 481 482 const gptGadgetContentWithSave = `volumes: 483 pc: 484 bootloader: grub 485 structure: 486 - name: mbr 487 type: mbr 488 size: 440 489 content: 490 - image: pc-boot.img 491 - name: BIOS Boot 492 type: DA,21686148-6449-6E6F-744E-656564454649 493 size: 1M 494 offset: 1M 495 offset-write: mbr+92 496 content: 497 - image: pc-core.img 498 - name: Recovery 499 role: system-seed 500 filesystem: vfat 501 # UEFI will boot the ESP partition by default first 502 type: EF,C12A7328-F81F-11D2-BA4B-00A0C93EC93B 503 size: 1200M 504 content: 505 - source: grubx64.efi 506 target: EFI/boot/grubx64.efi 507 - name: Save 508 role: system-save 509 filesystem: ext4 510 type: 83,0FC63DAF-8483-4772-8E79-3D69D8477DE4 511 size: 128M 512 - name: Writable 513 role: system-data 514 filesystem: ext4 515 type: 83,0FC63DAF-8483-4772-8E79-3D69D8477DE4 516 size: 1200M 517 ` 518 519 func (s *partitionTestSuite) TestCreatedDuringInstallGPT(c *C) { 520 cmdLsblk := testutil.MockCommand(c, "lsblk", ` 521 case $3 in 522 /dev/node1) 523 echo '{ "blockdevices": [ {"fstype":"ext4", "label":null} ] }' 524 ;; 525 /dev/node2) 526 echo '{ "blockdevices": [ {"fstype":"ext4", "label":"ubuntu-seed"} ] }' 527 ;; 528 /dev/node3) 529 echo '{ "blockdevices": [ {"fstype":"ext4", "label":"ubuntu-save"} ] }' 530 ;; 531 /dev/node4) 532 echo '{ "blockdevices": [ {"fstype":"ext4", "label":"ubuntu-data"} ] }' 533 ;; 534 *) 535 echo "unexpected args: $*" 536 exit 1 537 ;; 538 esac 539 `) 540 defer cmdLsblk.Restore() 541 cmdSfdisk := testutil.MockCommand(c, "sfdisk", ` 542 echo '{ 543 "partitiontable": { 544 "label": "gpt", 545 "id": "9151F25B-CDF0-48F1-9EDE-68CBD616E2CA", 546 "device": "/dev/node", 547 "unit": "sectors", 548 "firstlba": 34, 549 "lastlba": 8388574, 550 "partitions": [ 551 { 552 "node": "/dev/node1", 553 "start": 2048, 554 "size": 2048, 555 "type": "21686148-6449-6E6F-744E-656564454649", 556 "uuid": "30a26851-4b08-4b8d-8aea-f686e723ed8c", 557 "name": "BIOS boot partition" 558 }, 559 { 560 "node": "/dev/node2", 561 "start": 4096, 562 "size": 2457600, 563 "type": "C12A7328-F81F-11D2-BA4B-00A0C93EC93B", 564 "uuid": "7ea3a75a-3f6d-4647-8134-89ae61fe88d5", 565 "name": "Linux filesystem" 566 }, 567 { 568 "node": "/dev/node3", 569 "start": 2461696, 570 "size": 262144, 571 "type": "0fc63daf-8483-4772-8e79-3d69d8477de4", 572 "uuid": "641764aa-a680-4d36-a7ad-f7bd01fd8d12", 573 "name": "Linux filesystem" 574 }, 575 { 576 "node": "/dev/node4", 577 "start": 2723840, 578 "size": 2457600, 579 "type": "0fc63daf-8483-4772-8e79-3d69d8477de4", 580 "uuid": "8ab3e8fd-d53d-4d72-9c5e-56146915fd07", 581 "name": "Another Linux filesystem" 582 } 583 ] 584 } 585 }' 586 `) 587 defer cmdSfdisk.Restore() 588 589 err := makeMockGadget(s.gadgetRoot, gptGadgetContentWithSave) 590 c.Assert(err, IsNil) 591 pv, err := mustLayOutVolumeFromGadget(c, s.gadgetRoot, "", uc20Mod) 592 c.Assert(err, IsNil) 593 594 dl, err := gadget.OnDiskVolumeFromDevice("node") 595 c.Assert(err, IsNil) 596 597 list := install.CreatedDuringInstall(pv, dl) 598 // only save and writable should show up 599 c.Check(list, DeepEquals, []string{"/dev/node3", "/dev/node4"}) 600 } 601 602 // this is an mbr gadget like the pi, but doesn't have the amd64 mbr structure 603 // so it's probably not representative, but still useful for unit tests here 604 const mbrGadgetContentWithSave = `volumes: 605 pc: 606 schema: mbr 607 bootloader: grub 608 structure: 609 - name: Recovery 610 role: system-seed 611 filesystem: vfat 612 type: EF,C12A7328-F81F-11D2-BA4B-00A0C93EC93B 613 offset: 2M 614 size: 1200M 615 content: 616 - source: grubx64.efi 617 target: EFI/boot/grubx64.efi 618 - name: Boot 619 role: system-boot 620 filesystem: ext4 621 type: 83,0FC63DAF-8483-4772-8E79-3D69D8477DE4 622 size: 1200M 623 - name: Save 624 role: system-save 625 filesystem: ext4 626 type: 83,0FC63DAF-8483-4772-8E79-3D69D8477DE4 627 size: 128M 628 - name: Writable 629 role: system-data 630 filesystem: ext4 631 type: 83,0FC63DAF-8483-4772-8E79-3D69D8477DE4 632 size: 1200M 633 ` 634 635 func (s *partitionTestSuite) TestCreatedDuringInstallMBR(c *C) { 636 cmdLsblk := testutil.MockCommand(c, "lsblk", ` 637 what= 638 shift 2 639 case "$1" in 640 /dev/node1) 641 what='{"name": "node1", "fstype":"ext4", "label":"ubuntu-seed"}' 642 ;; 643 /dev/node2) 644 what='{"name": "node2", "fstype":"vfat", "label":"ubuntu-boot"}' 645 ;; 646 /dev/node3) 647 what='{"name": "node3", "fstype":"ext4", "label":"ubuntu-save"}' 648 ;; 649 /dev/node4) 650 what='{"name": "node4", "fstype":"ext4", "label":"ubuntu-data"}' 651 ;; 652 *) 653 echo "unexpected call" 654 exit 1 655 esac 656 657 cat <<EOF 658 { 659 "blockdevices": [ 660 $what 661 ] 662 } 663 EOF`) 664 defer cmdLsblk.Restore() 665 cmdSfdisk := testutil.MockCommand(c, "sfdisk", ` 666 echo '{ 667 "partitiontable": { 668 "label": "dos", 669 "id": "9151F25B-CDF0-48F1-9EDE-68CBD616E2CA", 670 "device": "/dev/node", 671 "unit": "sectors", 672 "firstlba": 0, 673 "lastlba": 8388574, 674 "partitions": [ 675 { 676 "node": "/dev/node1", 677 "start": 0, 678 "size": 2460672, 679 "type": "0a" 680 }, 681 { 682 "node": "/dev/node2", 683 "start": 2461696, 684 "size": 2460672, 685 "type": "b" 686 }, 687 { 688 "node": "/dev/node3", 689 "start": 4919296, 690 "size": 262144, 691 "type": "c" 692 }, 693 { 694 "node": "/dev/node4", 695 "start": 5181440, 696 "size": 2460672, 697 "type": "0d" 698 } 699 ] 700 } 701 }' 702 `) 703 defer cmdSfdisk.Restore() 704 cmdBlockdev := testutil.MockCommand(c, "blockdev", ` 705 if [ "$1" == "--getss" ]; then 706 echo 512 707 exit 0 708 elif [ "$1" == "--getsz" ]; then 709 echo 1234567 710 exit 0 711 fi 712 echo "unexpected cmdline opts $*" 713 exit 1 714 `) 715 defer cmdBlockdev.Restore() 716 717 dl, err := gadget.OnDiskVolumeFromDevice("node") 718 c.Assert(err, IsNil) 719 720 err = makeMockGadget(s.gadgetRoot, mbrGadgetContentWithSave) 721 c.Assert(err, IsNil) 722 pv, err := mustLayOutVolumeFromGadget(c, s.gadgetRoot, "", uc20Mod) 723 c.Assert(err, IsNil) 724 725 list := install.CreatedDuringInstall(pv, dl) 726 c.Assert(list, DeepEquals, []string{"/dev/node2", "/dev/node3", "/dev/node4"}) 727 } 728 729 func (s *partitionTestSuite) TestCreationSupported(c *C) { 730 winBasic := "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7" 731 732 c.Check(install.CreationSupported(winBasic), Equals, true) 733 c.Check(install.CreationSupported("invalid-partion-uuid"), Equals, false) 734 }